Módulo cargable en Linux

27 10 2009

Como parte de uno de los cursos que estoy llevando este semestre tuvimos que realizar un módulo cargable “en tiempo de ejecución” en Linux. Este aparte de mostrar mensajes de carga y descarga mediante dmesg, tenía que crear un archivo en el directorio /proc. A continuación la solución.

Primeramente hay que crear el archivo con el código fuente del módulo y agregar el código para el mismo. Abrimos una terminal de comandos y creamos una carpeta para tener un mejor orden y ahí dentro creamos el archivo.

mkdir modulo

cd modulo

nano primerModulo.c

A continuación el código fuente para el módulo.

/* El nombre del archivo es primerModulo */
#include <linux/module.h>          //para los detalles del modulo (Author, License…)
#include <linux/kernel.h>          //para usar la macro printk, KERN_INFO y KERN_ALERT
#include <linux/sched.h>           //para usar la estructura “task_struct”
#include <linux/proc_fs.h>    //para poder hacer la escritura en el archivo que estara en /proc

struct proc_dir_entry *structDirEntrada= NULL;
#define procfs_name “miprimermodulo”    //Nombre del archivo que se creara en /proc
char buff[500];        //buffer para escribir al archivo /proc/miprimermodulo

/*A continuacion viene la funcion de escritura en el archivo en /proc*/
int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data){
int len;
static int count=1;
static char bufo[500];
if(offset>0)
return 0;
len=sprintf(bufo, “%s”, buff);
count++;
*buffer_location=bufo;
return len;
}

static int cargar(void){
//create_proc_entry lleva parametros nombre, modo, y padre de la estructura a la que se hace la asignacion.
structDirEntrada = create_proc_entry(procfs_name, 0644, NULL);

if (structDirEntrada == NULL) {
remove_proc_entry(buff, structDirEntrada);
printk(KERN_ALERT “Error: Could not initialize /proc/%s\n”, procfs_name);
return -ENOMEM;
}

//Ingresa el texto que se guardara en el archivo al buffer “buff”
sprintf(buff, “\n*** Hola soy el primer modulo de G10 – 200413044 ***\n\n”);

//A continuacion se setean varios de los parametros a los elementos de la estructura proc_dir_entry
structDirEntrada->read_proc = procfile_read;
structDirEntrada->owner = THIS_MODULE;
structDirEntrada->mode = S_IFREG | S_IRUGO;
structDirEntrada->uid = 0;
structDirEntrada->gid = 0;
structDirEntrada->size = 100000; //Se establece el tamaño del archivo en /proc (bytes)

//Lo siguiente tiene que ir hasta aca porque el estandar ISO C90 prohíbe las declaraciones mezcladas y código
printk(KERN_INFO “********************************************************\n”);
printk(KERN_INFO “* Hola, ahora se inicia la carga del modulo…\n”);
printk(KERN_INFO “* El user space del proceso es ‘%s’\n”, current->comm);
printk(KERN_INFO “* El PID del programa que lo inserto… %i\n”, current->pid);
printk(KERN_INFO “********************************************************\n”);
printk(KERN_INFO “——————————————————–\n”);
printk(KERN_INFO “——————————————————–\n”);
return 0;    //Se retorna 0 para indicar que todo salio bien, de lo contrario retorna != 0
}

static void descargar(void){
printk(KERN_INFO “#######################################\n”);
printk(KERN_INFO “# Se inicia la descarga del modulo… #\n”);
printk(KERN_INFO “#######################################\n”);
remove_proc_entry(buff, structDirEntrada);
}

module_init(cargar);    // Lo que se debe llamar al cargar un modulo
module_exit(descargar);    // Lo que se debe llamar al remover un modulo

MODULE_AUTHOR(“G10 – 200413044”);
MODULE_LICENSE(“Dual MIT/GPL”);
MODULE_DESCRIPTION(“Este es un modulo para la practica 3 de Sistemas Operativos 2.”);
MODULE_VERSION(“1:1.0-Beta1”);
//Existen mas licencias en module.h, y es quiza uno de los paramatros mas importantes.

Cuando terminanos de agregar el código, guardamos y cerramos el archivo. A continuación debemos crear el archivo make para la construcción del modulo. Esto se hace con los comandos siguientes.

nano Makefile


#Codigo del Makefile para la compilacion del modulo…
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
.PHONY: build clean
build:
#— Importante la linea siguiente debe ir tabulada —
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
#— Importante la linea siguiente debe ir tabulada —
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c
else
$(info Building with KERNELRELEASE = ${KERNELRELEASE})
obj-m :=    primerModulo.o
endif

Guardamos y cerramos el archivo, a continuación para construirlo, en la terminal de comandos tecleamos el comando. Esto nos crea varios archivos, entre ellos uno con extensión .ko, el cual es módulo a cargar en sí.

make

Podemos ver las propiedades del modulo con el comando

modinfo primerModulo.ko

A continuación montamos/insertamos el módulo en el sistema, esto se hace con el comando

sudo insmod primerModulo.ko

Podemos ver los mensajes de bitacora del módulo con el comando

dmesg

Con el modulo ya cargado podemos ver que en /proc se creó el archivo que tiene como objetivo el módulo, este lo podemos abrir con programas como nano, cat o less. Cabe mencionar que este archivo es accesible unicamente mientras el módulo este cargado, cuando se descarga aparece, pero no es accesible.

cat /proc/miprimermodulo

Ahora tenemos que descargar el módulo, esto se hace con el comando.

sudo rmmod primerModulo

Para ver todos los mensajes de bitácora del módulo, podemos teclear el comando siguiente.

tail /var/log/messages

Este es un módulo bastante básico, sin embargo, bastante interesante para iniciarse en la programación de los mismo o simplemente para saber como funcionan los mismos.

Referencias:

Anuncios