gentoo linux, java, software libre y otras hierbas
Sep, 23 2009 - 12:12 pm

Trabajando con el Kernel Linux (I)

Hola a todos! Otra vez yo, Cortex, que hace un buen rato no me pasaba por aquí.

Hoy me gustaría hablar sobre un tema en el que seguro todos tenemos muchas lagunas, configurar el kernel. Si alguna vez has instalado ó intentando instalar Gentoo te habrás dado cuenta que en el ritual de instalación debes de compilar tu propio núcleo, incluyendo también la configuración del mismo. Desde mi experiencia, este suele ser un punto en el que la mayoría de usuarios se quedan; es cierto que también existe genkernel, una herramienta que facilita por completo este proceso pero que también, entre otras cosas, ralentiza mucho el arranque.

Casi la totalidad de distribuciones Linux, incluyen en su sistema un kernel con soporte para la mayor cantidad de hardware posible y en el booteo hay un script que se encarga de identificar el perfil del equipo en cuestión y cargar los módulos respectivos (sonido, disco, sistemas de archivos, etc.). Este sistema me parece excelente, puesto que sobretodo al usuario nuevo le ahorra mucho trabajo a la hora de poner a funcionar su distribución, pero como dije anteriormente no es lo más óptimo, sobretodo si queremos el mejor rendimiento posible. Leer el resto de la entrada…

12 Comentarios | deja el tuyo

Jul, 03 2009 - 4:37 pm

A fondo: Tu primer módulo cargable para el Linux kernel

codigo cEsta entrada pretende profundizar los temas aprendidos en el anterior artículo (Tu primer módulo cargable para el Linux kernel), con el fin de clarificar dudas, atar algunos cabos que dejamos sueltos y prepararnos para los siguientes artículos.

¿Puedo usar directamente el árbol del código fuente del kernel?

Sí, por supuesto. Como ya sabes, no es posible compilar un módulo cargable sin al menos parte del código fuente del kernel – esto es, la parte que contiene la infraestructura de construcción general y los archivos de cabecera esenciales. Solo por recordar, un archivo header (con extensión .h), contiene, normalmente, una declaración directa de clases, subrutinas, variables, u otros identificadores; sin la definición de estas, no es posible compilar código que las use.

En cualquier caso, es siempre útil tener una copia completa del código del kernel, y la manera más fácil de obtenerla es usando git:

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git git-kernel

Además que puedes actualizarlo fácilmente:

$ git pull

Nótese que, al contrario de instalar el paquete oficial de desarrollo del kernel como hicimos en el anterior artículo, usando git no es necesario tener privilegios administrativos para poner todo el código en algún lugar de tu directorio home. Además, si por alguna razón no puedes usarlo, puedes descargarte un archivo tar y funcionará igual; claro, usar git es mucho más cool 8-) Leer el resto de la entrada…

3 Comentarios | deja el tuyo

Jun, 26 2009 - 4:31 pm

[how-to] Tu primer módulo cargable para el Linux kernel

codigo cEste how-to está basado en el artículo The Kernel Newbie Corner: Your First Loadable Kernel Module escrito por Rob Day en Linux.com. En él se enseñan las bases de la programación de módulos para el kernel de Linux. Este primer artículo pretende ilustrar de manera clara los conceptos básicos y espero que, a medida que Rob vaya escribiendo más artículos, pueda ir traduciéndolos para ofrecer este excelente contenido en español. Además, funciona para cualquier distro, aunque en este caso lo hice todo sobre Gentoo. Sin más, ¡vamos al grano!

¿Es necesario tener privilegios de root?

Mientras desarrollamos el módulo, no. Pero al momento de cargar el módulo necesitaremos privilegios administrativos. Por supuesto, es recomendable que el desarrollo lo hagamos con un usuario normal, y solo al final usemos un usuario root para cargar o remover los módulos.

Prerrequisitos

Antes de comenzar es necesario saber/tener algunas cosas:

  • La versión del kernel con la que vamos a trabajar (usualmente la que estamos corriendo). Esto lo hacemos con el comando uname -r:
    $ uname -r
    2.6.29-gentoo-r5
  • El uso de herramientas de desarrollo, como gcc, binutils, etc.
  • Tener instalados las utilidades para trabajar con módulos (insmod, rmmod, etc.), el cual se encuentra en el paquete module-init-tools.
  • El código del kernel de Linux, de tal manera que puedas compilar tu módulo contra este.

¿Para qué el código del kernel?

Esto es realmente importante, así que echaremos un vistazo un poco más profundo. Cuando compilamos un módulo para Linux es necesario tener el código fuente de algunas partes del kernel, puesto que muchas instrucciones de preprocesador usadas no se encuentran en los headers estándar de desarrollo. En vez de ello, se encuentran en los headers de kernel.

Podrías simplemente descargar el código del kernel directamente de la página oficial, aunque lo más sencillo es instalar el paquete que corresponda a la versión del kernel que estemos ejecutando. Por lo general, este tipo de paquetes instala el código en /usr/src o /usr/src/kernels. Por ejemplo, en Fedora el paquete que debes instalar se llama kernel-dev, mientras que en Gentoo es gentoo-sources.

Una vez tengas el código instalado, es necesario saber exactamente en donde se encuentra, de tal manera que podamos referenciarlo al momento de compilar el módulo. Podrías revisar eso manualmente o, mejor aún, buscar el enlace simbólico hacia el kernel, que por lo general se encuentra en /lib/modules:

$ ls -l /lib/modules/`uname -r`
total 104
lrwxrwxrwx 1 root root    31 jun 11 10:24 build -> /usr/src/linux-2.6.29-gentoo-r5

El enlace simbólico que buscamos es build, y como puedes ver en el ejemplo, apunta a la raíz del código del kernel. Esto significa que, cada vez que quieras hacer referencia al kernel en el momento de compilar el módulo, basta con usar dicho enlace.

“Hola, kernel!”

Bien, es hora de crear nuestro primer módulo. Sin más rodeos, el código sería el siguiente:

/* El nombre del archivo es 'hola.c'. */
#include <linux/module.h>      // para todos los modulos
#include <linux/init.h>        // para las macros entry/exit
#include <linux/kernel.h>      // para usar la macro printk
#include <asm/current.h>       // informacion del proceso (solo por diversion)
#include <linux/sched.h>       // para usar la estructura "task_struct"
static int hola(void)
{
     printk(KERN_INFO "Hola, el modulo esta siendo cargado.\n");
     printk(KERN_INFO "El user space del proceso es '%s'\n", current->comm);
     printk(KERN_INFO "El PID es  %i\n", current->pid);
     return 0;       // para indicar que todo ha salido bien
}
static void adios(void)
{
     printk(KERN_INFO "Chao, el modulo esta siendo removido.\n");
}
module_init(hola);     // lo que se debe llamar al cargar un modulo
module_exit(adios);    // lo que se debe llamar al remover un modulo

MODULE_AUTHOR("Robert P. J. Day");
MODULE_AUTHOR("Cristian Castiblanco [solo lo puse en castellano]");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Aqui puedes poner una descripcion de tu modulo");

Algunas observaciones acerca del código de arriba:

  • Técnicamente, no es necesario imprimir cosas cada vez que se carga o remueve un módulo (con printk). Pero puesto que es nuestro primer módulo, y aún no hace nada especial, es más divertido si lo dejamos así.
  • Es necesario hacer que la función de inicio retorne 0, si queremos indicar que la carga fue satisfactoria.
  • No, no es necesario poner una coma después de indicar el nivel de logs (KERN_INFO). Es un error común hacerlo.

Eso es todo… ¡vamos a compilarlo!

El archivo Makefile

Este es el archivo Makefile que necesitaremos:

ifeq ($(KERNELRELEASE),)  

KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)  

.PHONY: build clean

build:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules  

clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c
else  

$(info Building with KERNELRELEASE = ${KERNELRELEASE})
obj-m :=    hola.o

endif

Como has de saber, los archivos Makefile indican las reglas necesarias para compilar código. En este caso, explicándolo a groso modo, lo que hace el Makefile es detectar que aún nos encontramos en el directorio de desarrollo de nuestro módulo, y por lo tanto se dirige al directorio del kernel, compila el módulo desde ahí y se devuelve. Para probarlo basta con ejecutar el comando make:

$ make
make -C /lib/modules/2.6.29-gentoo-r5/build  M=/tmp/hola   modules
make[1]: se ingresa al directorio `/usr/src/linux-2.6.29-gentoo-r5′
Building with KERNELRELEASE = 2.6.29-gentoo-r5
CC [M]  /tmp/hola/hola.o
Building modules, stage 2.
Building with KERNELRELEASE = 2.6.29-gentoo-r5
MODPOST 1 modules
CC      /tmp/hola/hola.mod.o
LD [M]  /tmp/hola/hola.ko
make[1]: se sale del directorio `/usr/src/linux-2.6.29-gentoo-r5′

Examinar el módulo

Una vez compiles el módulo obtendrás un archivo con extensión .ko. Si quieres echarle un ojo a dicho archivo, puedes usar el comando modinfo así:

$ sudo modinfo hola.ko
filename:       hola.ko
description:    Aqui puedes poner una descripcion de tu modulo
license:        Dual BSD/GPL
author:         Cristian Castiblanco [solo lo puse en castellano :P ]
author:         Robert P. J. Day
depends:
vermagic:       2.6.29-gentoo-r5 SMP mod_unload CORE2

En Gentoo es necesario ejecutarlo con privilegios; en otras distros puedes ejecutarlo normalmente.

Cargar o remover el módulo

Llego la hora de cargar nuestro módulo. Para ello, como comenté anteriormente, es necesario poseer privilegios administrativos. Al grano:

# insmod hola.ko
# lsmod
Module                  Size  Used by
hola                    1148  0   <– GENIAL! Es nuestro módulo!
vboxnetflt             69976  0
vboxdrv                94368  1 vboxnetflt
nvidia               9531788  40

$ sudo rmmod hola

¿Y donde está lo que imprimimos con printk? Bien, no es común imprimir en consola cosas mientras un módulo es cargado o removido; en este caso, la salida va a dar al archivo de logs principal de Linux (/var/log/messages); puedes ver la salida con el comando dmesg o directamente en dicho archivo:

# dmesg | tail
[20651.176989] Hola, el modulo esta siendo cargado.
[20651.176993] El user space del proceso es ‘insmod’
[20651.176997] El PID es  13786
[20678.497134] Chao, el modulo esta siendo removido.
# tail /var/log/messages

Conclusión

Estas son apenas las bases que deberíamos tener para comenzar con la construcción de un módulo para el kernel de Linux. Es de valiosa ayuda jugar un poco con este ejemplo, de tal manera que podamos estar seguros que todo irá bien cuando hagamos algo un poco más complejo.

Descargar código fuente del ejemplo

12 Comentarios | deja el tuyo

« Entradas anteriores
Entradas recientes »