Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las...

28
Unidad II – El Núcleo o Kernel Obtención del código fuente Configuración del kernel Compilación del código fuente Arranque del nuevo kernel Análisis del código fuente Llamadas al sistema Módulo del kernel Aplicando parches

Transcript of Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las...

Page 1: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

Unidad II – El Núcleo o Kernel

Obtención del código fuente

Configuración del kernel

Compilación del código fuente

Arranque del nuevo kernel

Análisis del código fuente

Llamadas al sistema

Módulo del kernel

Aplicando parches

Page 2: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

Obtención del código fuente

Introducción

Hay muchas formas diferentes de obtener el código fuente, a continuación se numeran algunas de ellas. Aunque lo más sencillo sea instalar el código fuente que viene con su distribución de Linux, se requiere mantenerse al día con las últimas versiones del código si se desea participar en el desarrollo del kernel.

Formas de obtener el código fuente

• Descargar el código del kernel mediante ftp a ftp.kernel.org. Se trata de una operación que consume un gran ancho de banda, así que no debe usarse si se tiene una conexión lenta.

Conectarse mediante ftp al mirror local, que se llamará:

ftp.<C&OACUTE;DIGO país del>.kernel.org

Por ejemplo, en el caso de España, sería: $ ftp ftp.es.kernel.org

Conectarse, si es necesario, con el nombre de usuario "ftp" o "anonymous". Cambiar de directorio a pub/linux/kernel/v2.4 y descargar el último kernel. Por ejemplo, si la última versión es la 2.4.26, descargar el archivo llamado linux-2.4.26.tar.gz

Formas de obtener el código fuente

Normalmente hay un archivo llamado LATEST-IS-<version> que indica cual es la última versión. Se recomienda el archivo comprimido con gzip (el archivo que tiene la extensión ".gz"), en lugar del comprimido con bzip2 (el que tiene la extensión ".bz"), ya que bzip2 tarda bastante tiempo en descomprimir.Descomprimir y extraer el archivo en el directorio en el que se tenga pensado trabajar. AVISO: El código fuente del kernel se desempaquetará en un directorio denominado "linux". Si ya tiene un directorio creado con ese nombre, o un enlace simbólico denominado linux, se sobreescribirá lo que haya en ese directorio, así que siempre se debe hacer lo siguiente:

Page 3: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

$ rm linux

(Asumiendo que linux era un enlace simbólico)

$ tar xzf linux-<version>.tar.gz$ mv linux linux-<version>$ ln -s linux-<version> linux

Ahora ya se dispone del código fuente del kernel de Linux.

• Instalar el código fuente del kernel que viene con los CDs de tu distribución. Si ya se tiene creado un directorio denominado /usr/src/linux y contiene más de un subdirectorio, entonces ya se tiene el código fuente instalado. En caso de que no sea así, continúa leyendo.

Montar el CDROM de instalación. En un sistema basado en RedHat, el RPM fuente está normalmente en /RPMS/ y se llama kernel-source-..rpm

Una forma de encontrar el paquete del código fuente del kernel es ejecutar este comando, suponiendo que el CD est&eacuta; montado en /mnt/cdrom:

$ find /mnt/cdrom -name *kernel-*$ rpm -iv <pathname>/kernel-source-<version>.<arch>.rpm

La opción "v" indicará si falla la operación o no.

Hay otras formas diferentes de obtener el código fuente del kernel, usando CVS o rsync.

Una razón para preferir usar el código original en vez del modificado por algún distribuidor, es en el caso de que se vaya a crear y enviar parches con modificaciones a otros desarrolladores del kernel. Si se crea un parche y se envía a la lista de distribución del kernel para su inclusión en el código del mismo, debe haber sido creado respecto a la última versión limpia del kernel. Si se crea un parche para el código fuente de una distribución, es probable que no se pueda aplicar a el kernel original. El punto clave para usar el código fuente de un distribuidor es cuando estamos trabajando con arquitecturas distintas a x86. El código limpio del kernel que se puede descargar casi nunca compila y arranca en

Page 4: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

otras arquitecturas que no sean la mencionada x86. A menudo, la mejor forma de conseguir un kernel que pueda funcionar para una arquitectura de este tipo es el código fuente de la distribución en particular. Cada plataforma suele tener alguna forma de añadir el último código fuente al código que ha recibido con tu distribución.

Arrancando el nuevo kernel con LILO en un X86

El archivo de configuración de LILO está en /etc/lilo.conf. La idea básica es que copie allí el trozo del archivo de configuración referido al arranque del nuevo kernel, y que a continuación cambie allí el nombre del archivo en que está el kernel que desea arrancar. Recuerde que está copiando la información sobre el kernel actual y modificando la copia, NO el original. Por ejemplo, suponga que se tiene en /etc/lilo.conf algo parecido a esto:

image=/boot/vmlinuz-2.2.14-5.0label=linuxinitrd=/boot/initrd-2.2.14-5.0.imgread-onlyroot=/dev/sda1

El campo "image" le dice a LILO dónde encontrar el archivo que contiene el nuevo kernel. El campo "label" es lo que escribe en el prompt de LILO para arrancar con ese kernel. Es una buena idea usar como label un nombre corto y sencillo de teclear. El campo "initrd" es opcional y especifica el ramdisc a cargar en memoria antes de montar el sistema de archivos raíz. El campo "read-only" dice que inicialmente hay que montar el sistema de archivos raíz como solo lectura, en contraposición a permitir lectura y escritura. El campo "root" le indica a LILO qué dispositivo contiene el sistema de ficheros raíz.Deberá copiar esta información y cambiar los campos siguientes:

image=<fichero con el kernel nuevo>label=<elegir aquí el nombre que quiera>

Eliminar el campo "initrd" en el caso de que exista:initrd=/boot/initrd-2.2.14-5.0.img

Page 5: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

Escriba la etiqueta (label) que haya elegido lo que hayas escrito en el campo "label") para el nuevo kernel. LILO intentará entonces arrancar con ese kernel. Para evitar tener que escribir una línea de comandos en LILO, ejecute esto justo antes de reiniciar:

# lilo -v -R "<LILO command line>"

Esto le indica a LILO que use esa línea de comandos la siguiente vez que reinicie. A continuación, eliminará esa línea de comandos y volverá a su comportamiento habitual las siguientes veces que se reinicie. Esto es algo realmente útil con los nuevos kernel, ya que puede rearrancar, ver que no funciona, reiniciar la máquina y cargar automáticamente tu kernel original sin necesidad de escribir nada. Si tienes problemas con LILO, Intenta consultar el LILO mini-HOWTO.

La razón para eliminar el campo "initrd" es que el archivo initrd no contiene nada que sea útil para el nuevo kernel. En una distribución normal de Linux, el fichero initrd contiene un montón de módulos del kernel que solamente pueden ser cargados por el kernel que viene con la distribución. Las nuevas líneas que se han añadido al archivo de configuración deberían ser algo parecido al finalizar:

Image=/boot/mynewkernellabel = newread-onlyroot=/dev/sda1

LILO no se dará cuenta de los cambios que se hayan efectuado en el archivo /etc/lilo.conf hasta que ejecutes el comando "lilo". Probablemente harás esto más de una vez: compilar un nuevo kernel, copiarlo a un nuevo destino, olvidarte de ejecutar LILO y rearrancar el sistema, solo para darte cuenta de que LILO no sabe absolutamente nada del nuevo kernel. Por eso, cuando modifiques el archivo /etc/lilo.conf, acuerdate siempre de ejecutar LILO:

#lilo -v

El modificador "-v" significa verbose, y quiere decir que lilo vaya indicando todo lo que va haciendo. A continuación, reinicie el PC, y verá el prompt de LILO.

Page 6: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

Arrancando el nuevo kernel con GRUB en un X86

Necesitará ser root para poder editar /etc/grub.conf. La configuración de GRUB está almacenada en /etc/grub.conf. La idea básica aquí es copiar el trozo de configuración de arranque de tu kernel actual y cambiar el nombre del kernel a arrancar. Recuerda, estás copiando la información sobre tu kernel actual y modificando la copia, NO el original. Por ejemplo, si tienes en tu /etc/grub.conf algo parecido a esto:

title Linux (2.4.9-31)root (hd0,0)kernel /vmlinuz-2.4.9-31 ro root=/dev/hda3initrd /initrd-2.4.9-31.img

El campo "title" es el título en el menú de GRUB que corresponde al nuevo kernel. El campo "root" le indica a GRUB dónde está el directorio raiz (el directorio raiz es lo que está montado en "/"). El campo "kernel" le dice a GRUB dónde encontrar el archivo que contiene el kernel y, a continuación del nombre del archivo, indica varias opciones para pasarle al kernel al arrancarlo. NOTA: El nombre del archivo del kernel está dado de forma relativa a la partición de arranque, lo que normalmente quiere decir que has de eliminar la parte de "/boot"del nombre del archivo. El campo "initrd" es opcional y especifica el ramdisk inicial que se ha de cargar antes de montar el sistema de ficheros raíz. Deberá de copiar esta información y modificar los siguientes campos: title <poner aquí el nombre que quiera>kernel <fichero con tu nuevo kernel> ro root=/dev/hda3

Recuerde eliminar casi con toda probabilidad la parte "/boot" del nombre del archivo, a menos que sepa bien lo que estás haciendo. Elimine el campo "initrd" si es que existe:

initrd /initrd-2.4.9-31.img

La razón para eliminar el campo "initrd" es que el archivo initrd no contiene nada que sea útil para nuestro nuevo kernel. En una distribución normal de Linux, el archivo initrd contiene un montón de módulos del kernel que solamente pueden ser cargados por el kernel que viene con la distribución. Las nuevas líneas que se han añadido al archivo de configuración deberían ser algo parecido a esto al finalizar:

Page 7: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

title newroot (hd0,0)kernel /mynewkernel ro root=/dev/hda3

De nuevo, tener en cuenta que en este caso el nuevo kernel está en "/boot/mynewkernel", pero, puesto que se tiene una partición diferente montada en /boot, y puesto que GRUB solamente mirará dentro de esa partición al arrancar, se requiere eliminar la parte del nombre que corresponde al punto de montaje del directorio, es decir "/boot". Ahora reinicie el ordenador, y verá aparecer el menú de GRUB. Seleccione con las teclas de cursor el título que eligió antes y pulse enter. GRUB intentará a continuación arrancar el nuevo kernel.

Trucos para recompilar el Kernel

A continuación se mencionan un par de trucos para recompilar el código cuando se está trabajando solamente con uno o dos archivos. Supóngase que está cambiando el archivo driver /char/foo.c y que está teniendo problemas para que te compile. Puede escribir simplemente (desde el directorio principal de arbol del código del kernel) "make drivers/char/foo.o", y "make" intentará de inmediato compilar ese archivo, en lugar de ir descendiendo por todos los subdirectorios en el orden correspondiente y buscando qué archivos necesitan recompilación. Si drivers/char/foo.c es un módulo, puedes entonces usar insmod con el archivo resultante drivers/char/foo.o cuando haya compilado, en lugar de ejecutar el comando completo "make modules". Si drivers/char/foo.c no es un módulo, tendrás que ejecutar de nuevo "make -j2 bzImage" para enlazarlo con el resto de las partes del kernel.El operador "&&" en bash es muy útil para la compilación del kernel.La línea de comandos de bash:# cosa1 && cosa2

Dice: "Haz cosa1, y si no devuelve un error, haz cosa2". Esto es útil para ejecutar algo con la condición previa de que la compilación haya funcionado.

Cuando se esta trabajando en un módulo, se usa a menudo el siguiente comando:

# rmmod foo.o && make drivers/char/foo.o && insmod drivers/char/foo.o

Page 8: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

Dice: "Elimina el módulo foo.o, y si eso lo ha hecho bien, compila el archivo drivers/char/foo.c, y si eso también se ha realizado correctamente, entonces carga en memoria el módulo resultante". De esa forma, si existe un error de compilación, no se carga el módulo antiguo y es obvio que se requiere arreglar el código. Si no se determina el error , intentar el comando "make mrproper".

Recompilar el Kernel

Para recompilar el kernel en la mayor parte de los casos, basta con ejecutar simplemente "make -j2 bzImage" (o el comando apropiado para que compile tu kernel) para conseguirlo. Si cambia los archivos de configuración, deberá ejecutar de nuevo "make dep", y posteriormente "make -j2 bzImage". Si ha modificado el código de un módulo, simplemente ejecuta "make modules" y "make modules_install" (si es necesario).

A veces, se cambian tantas cosas que "make" no es capaz de averiguar cómo recompilar los archivos correctamente. "make clean" eliminará todos los archivos objeto (los que terminan en .o) y algunas otras cosas más. "make mrproper" hace todo lo que hace "make clean", y además elimina los archivos de configuración, los de dependencias, y todo el resto de cosas que crea "make config". Asegúrese de grabar su archivo de configuración en otro archivo antes de ejecutar "make mrproper". Más tarde, copiar de nuevo el archivo de configuración a ".config" y comienzar desde el principio, empezando por "make menuconfig". El comando "make mrproper" a menudo soluciona problemas extraños del kernel que no tienen sentido, así como errores raros de compilación que tampoco tengan sentido.

Page 9: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

Configuración del Kernel

Introducción

El kernel de Linux viene con diversas herramientas de configuración. Cada una se ejecuta escribiendo "make <algo>config" en el directorio principal del código fuente del kernel, normalmente /usr/src/linux. (Todos los comandos "make" se han de ejecutar desde el directorio principal del código).

Comandos make

• make config:

Esta es la herramienta de configuración más básica. Preguntará todas y cada una de las preguntas necesarias para configurar el kernel en su orden correspondiente. El kernel de Linux tiene MUCHAS opciones de configuración.

• make oldconfig:

Esto hará que el sistema tome los datos del archivo ".config" y solamente pregunte por las opciones cuya selección no esté indicada en ese archivo. Se usa normalmente cuando se actualiza a una versión más moderna del kernel.

make menuconfig:

Este es el mecanismo más usado para configurar el kernel. Este comando hace que salga un sistema de configuración en modo texto basado en menúes, utilizando la librería ncurses. Se Puede ir entrando en los submenús que te interesen y cambiar únicamente las opciones de configuración que se desee.

• make xconfig:

Si se está usando XWindows, esta es una versión más bonita de menuconfig, que se puede usar a toque de ratón. Tiende a funcionar en menos ocasiones que menuconfig, ya que xconfig es más sensible a los defectos en los archivos de configuración que menuconfig (y tambien debido a que hay más gente que usa menuconfig).

Page 10: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

Consideraciones para configurar el kernel

Puntos a tener en cuenta al configurar un kernel:

• Activar siempre la opción "Prompt for development... drivers" (pregunte por los drivers en versiones de desarrollo).

• Desactivar siempre "module versioning" (versionado de los módulos), pero activar siempre el "kernel module loader" (cargador de módulos del kernel) y los "kernel modules" (módulos del kernel).

• Desactivar todas las características que no sean necesarias

• Utilizar módulos solamente si se tiene una buena razón para hacerlo. Por ejemplo, si está trabajando en un driver, querrás poder cargar una nueva versión del mismo sin necesidad de reiniciar la máquina.

• Asegurarse muy bien de que ha elegido el tipo correcto de procesador. Puede averiguar qué procesador tiene con "cat /proc/cpuinfo".

• Determinar qué dispositivos PCI tiene instalado con "lspci -v".

• Determinar qué tiene compilado el kernel que está usando ahora mismo con el comando "dmesg | less". La mayor parte de los drivers de los dispositivos muestran un mensaje cuando detectan un dispositivo.

Si todo lo demás falla, copie el archivo .config de alguna otra maquina.

Productos finales

Cada uno de los programas de configuración crea estos productos finales:

• Un enlace simbólico desde include/asm<arch> a /include/asm

• Un archivo llamado ".config" en el directorio principal del código fuente, que contiene todas tus opciones de configuración.

• Un conjuto de archivos de cabecera de C definiendo (o no) los símbolos CONFIG_* de forma que el preprocesador de C sepa si están activos o no.

Si se cuenta con un archivo ".config" configurado para su máquina, simplemente se copia al directorio en el que se tenga el código fuente del kernel y ejecuta "make oldconfig". Debería comprobar a continuación la configuración resultante con "make menuconfig". Si no dispone de un archivo ".config" con las opciones de configuración, puede crear uno visitando cada submenú y activando o

Page 11: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

desactivando las opciones que necesite. menuconfig y xconfig tienen una opción de ayuda ("Help") que muestra la entrada de Configure.help correspondiente a esa opción, lo cual puede ayudar a decidir si debería estar o no activada.

Compilación del kernel

Consideraciones previas

Antes de comenzar a compilar, asegúrate de que /usr/src/linux es un enlace simbólico al árbol de directorios del código fuente. Si es un enlace simbólico a un árbol _diferente_, algunas partes de la compilación podrían usar las cabeceras equivocadas. Si el enlace no existe, algunos pasos de la compilación no funcionarán.

Pasos para compilar el kernel

Paso1:Primero, crear la información sobre las dependencias# make dep

Esto ejecuta un script que calcula (la mayor parte de las veces) las dependencias entre los diferentes archivos. El archivo foo.c depende de baz.h si un cambio en baz.h afecta al resultado de la compilación de boo.c. Por ejemplo, baz.h define la estructura "driver_stuff", y foo.c usa una estructura driver_stuff. Si añade un nuevo elemento a la estructura driver_stuff definida en baz.h, eso hará que cambie el tamaño de la estructura driver_stuff, y entonces será necesario recompilar foo.c con el tamaño adecuado de la estructura driver_stuff.

Paso2: Después de calcular las dependencias, se construye el propio kernel:

En un x86: # make -j<número de procesos> bzImage

En un ppc:# make -j<número de procesos> zImage

Donde <número de procesos> es dos veces el número de CPUs en tu sistema. Así, si tienes un ordenador con una única CPU Pentium II, por ejemplo, pondría:

# make -j2 bzImage

Lo que hace el modificador "-j" es decirle al programa make cuántos procesos

Page 12: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

(comandos en el Makefile) ha de ejecutar simultaneamente. "make" sabe qué procesos se pueden realizar de manera simultanea, y cuáles necesitan esperar a

que terminen otros procesos previos antes de poder ejecutarse.Los procesos de compilación del kernel se pasan tanto tiempo esperando por

operaciones de entrada y salida (I/O), como leer el archivo con el código fuente desde el disco, que ejecutar dos de los procesos por cada procesador hace que

se obtenga el menor tiempo de compilación.NOTA: Si tiene un error de compilación, ejecute "make" con un único proceso para

ver con más facilidad dónde ha ocurrido el error.

Paso3: Si ha habilitado los módulos, necesitará compilarlos con el comando:

# make modules

Si tiene pensado cargar esos módulos en la misma máquina que los ha compilado, ejecute el comando que realiza la instalación automática de los módulos, pero ANTES - grabe una copia de los viejos módulos.

# mv /lib/modules/`uname -r` /lib/modules/`uname r`.bak# make modules_install

Esto pondrá todos los módulos nuevos en el directorio /lib/modules/<version>. Puede averiguar qué <version> es mirando en include/linux/version.h.

Arranque del nuevo kernel

Introducción

La regla número uno a seguir es no borrar nunca el kernel con el que se está trabajando ahora mismo ni los archivos de configuración del bootloader o programa iniciador. Nunca sobrescriba su nuevo kernel sobre el original. No es necesario mantener una copia de todos y cada uno de los kernel que se compile, pero se deben seleccionar uno o varios kernel "seguros" y mantenerlos a ellos y a sus archivos de configuración intactos.

Copiar el nuevo kernel a un lugar seguroLo primero que se debe hacer es copiar el kernel que acaba de compilar a un lugar seguro. Se sugiere que use /boot/mynewkernel como destino. Si está usando un x86, ha de copiar bzImage:

Page 13: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

# cp arch/i386/boot/bzImage /boot/mynewkernel

Si está en un PowerPC o Alpha, copia el archivo vmlinux:

# cp vmlinux /boot/mynewkernel

Análisis del código fuente

Introducción

En esta sección se estudia una idea general de dónde se encuentran localizadas las diferentes partes del kernel en el árbol de directorios, en qué órden se ejecutan y cómo hay que hacer para buscar un trozo concreto de código.

¿Dónde está todo el código?

Vamos a comenzar por el directorio principal del árbol de directorios del código fuente de Linux, que normalmente, aunque no siempre, se encuentra en /usr/src/linux-<version>. No vamos a entrar en demasiados detalles, ya que el código fuente de Linux cambia constantemente, pero intentaremos dar la suficiente información para ser capaces de encontrar dónde se encuentra un driver o una función concreta.

¿Dónde se produce la unión de todo?

El punto central que conecta todo el kernel de Linux es el fichero "init/main.c". Cada arquitectura ejecuta algunas funciones de inicialización de bajo nivel y posteriormente ejecuta la función "start_kernel", que se encuentra en "init/main.c". El orden de ejecución del código se ve como algo así:

Código de inicialización específico de la arquitectura (en arch/<arch>/*)

l

v

La función start_kernel() (en init/main.c)

Page 14: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

l

v

La función init() (en init/main.c)

l

v

El programa a nivel de usuario “init”

¿Dónde se produce la unión de todo? - En detalle

En mayor detalle, esto es lo que ocurre:

• Codigo de inicialización específico de la arquitectura que hace:

1. Descomprime y mueve el propio código del kernel, si es necesario.

2. Inicializa el hardware.

1. Esto puede incluir inicializar la gestión de memoria de bajo nivel.

3. Transferir el control a la función start_kernel()

• start_kernel() hace, entre otras cosas:

1. Imprime la versión del kernel y la línea de comandos.

2. Da comienzo a la salida de datos por la consola.

3. Habilita las interrupciones.

4. Calibra el delay loop, o bucle de retraso.

5. Arranca los demás procesadores (en máquinas SMP o multiprocesador).

6. Inicia un hilo de ejecución del kernel para ejecutar la función init()

Page 15: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

7. Entra en el idle loop, o bucle de espera.

• init() hace:

1. Inicia los subsistemas de los dispositivos.

2. Monta el directorio raíz.

3. Libera la memoria no utilizada del kernel

4. Ejecuta /sbin/init (o /etc/init, o...)

Llegando a este punto, el programa init está ejecutándose a nivel usuario, lo que hace cosas como inicializar los servicios de red y ejecutar getty (el programa de login) en tu(s) consola(s).

Archivos y directorios

Makefile: Este fichero es el Makefile de orden superior de todo el arbol del código. Define numerosas variables y reglas importantes, como por ejemplo los flags de compilación por defecto del gcc. Lo que probablemente importe más es que las primeras líneas definen el número de versión del kernel (por ejemplo 2.4.18-pre7). Puedes añadir tu propia cadena de caracteres (como tus iniciales) a la línea EXTRAVERSION para personalizar la cadena que define la versión del kernel.Documentation/ : Este directorio contiene información util (aunque a menudo obsoleta) sobre cómo configurar el kernel, utilizar un ramdisk, y cosas similares. El fichero más importante en este directorio es "Configure.help" - Es el fichero en el que se encuentran todas las entradas individuales de la ayuda sobre las diferentes opciones de configuración. (Nota: Esto ha cambiado en la serie 2.5.x del kernel a ficheros Config.help individuales en cada directorio).Arch/ : Todo el código específico de cada arquitectura se encuentra en los directorios include/asm-<arch>. Cada arquitectura tiene su propio directorio. Por ejemplo, el código para un ordenador basado en PowerPC se encontrarí en arch/ppc. Encontrarás aquí la gestión de la memoria a bajo nivel, manejo de las interrupciones, primera inicialización, rutinas en ensamblador y bastantes más cosas.

kernel/ :El código genérico a nivel del kernel que no encaja en ninguna otra parte viene a este directorio. El código relativo a las llamadas al sistema de alto nivel está aquí, así como el código de printk(), el scheduler, el código para manejar las señales, y muchas más cosas. Los archivos tienen nombres

Page 16: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

informativos, así que puedes escribir "ls kernel/" y averiguar con bastante exactitud lo que hace cada fichero.

Lib/: Aquí vienen las rutinas útiles en general para todo el código del kernel. En ella se encuentran las operaciones comunes con cadenas de caracteres, rutinas de depuración de errores y el código de análisis de las líneas de comando.Mm/ : Aquí viene el código de gestión de la memoria de alto nivel. La memoria virtual (VM, Virtual Memory) es implementada mediante estas rutinas, conjuntamente con las rutinas de bajo nivel específicas de cada arquitectura que se encuentran normalmente en "arch/<arch>/mm/". La gestión temprana de la memoria en el arranque (que es necesaria antes de que el subsistema de memoria esté totalmente operativo) se realiza aquí, así como el mapeado en memoria de ficheros, gestión de la caché de las páginas, organización de la memoria y descarga de las páginas en RAM (entre otras muchas cosas).

net/ : El código de alto nivel de manejo de redes se encuentra en este directorio. Los drivers de red de bajo nivel pasan los paquetes de información hacia estos niveles superiores y obtienen de aquí los paquetes a enviar. Desde aquí se puede pasar los datos a una aplicación de usuario, descartar los datos o usarlos dentro del propio kernel, según el paquete. El directorio "net/core" contiene código útil para la mayor parte de los distintos protocolos de red, lo que también ocurre con varios de los ficheros en el propio directorio "net/". Los protocolos de red específicos están implementados en subdirectorios de "net/". Por ejemplo, el código del protocolo TCP/IP (versión 4) se encuentra en el directorio "net/ipv4".

Scripts/ : Este directorio contiene scripts que son útiles para la construcción del kernel, pero que no incluyen nada de código que se use en el propio kernel. Las diferentes herramientas de configuración mantienen aquí sus ficheros, por ejemplo.

include/: La mayor parte de los archivos de cabecera que se incluyen al inicio de los archivos .c se encuentran en este directorio. Los ficheros específicos de una arquitectura se encuentran en "asm-<arch>". Una parte del proceso de construcción del kernel crea un enlace simbólico desde "asm" a "asm-<arch>", con lo que "#include <asm/file.h>" incluirá el fichero adecuado para esa arquitectura sin que haya necesidad de especificar la arquitectura directamente en el código del archivo .c. Los demás directorios incluyen ficheros de cabecera que no son específicos de cada arquitectura. Si se usa una misma estructura, constante o variable en más de un fichero .c, probablemente esté definida en uno de estos ficheros de cabecera.

Page 17: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

Init/ : Este directorio contiene dos ficheros: "main.c" y "version.c". "version.c" define la cadena de texto con la versión de Linux. "main.c" se puede entender como la especie de "pegamento" que une el kernel. Hablaremos más sobre "main.c" en la siguiente sección.Ipc/ : "IPC" quiere decir "Inter-Process Communication", o comunicación entre procesos. Contiene el código para la memoria compartida, semáforos y otras formas de IPC.

drivers/ : Como norma general, el código para usar dispositivos periféricos se encuentra en subdirectorios dentro de este directorio. Esto incluye drivers de video, de tarjetas de red, drivers SCSI de bajo nivel y cosas similares. Por ejemplo, la mayor parte de los drivers de tarjetas de red se encuentran en drivers/net. El código que actúa de pegamento para unir todos los drivers de un mismo tipo puede o no estar incluido en el mismo directorio que los mismos drivers de bajo nivel.

Fs/ : Se encuentra en este directorio tanto el código genérico del sistema de archivos (conocido como VFS, o Virtual File System - Sistema de archivos virtual) como el código para cada uno de los diferentes sistemas de archivos. El sistema de archivos raiz tal vez sea ext2; el código para leer el formato ext2 se encuentra en fs/ext2. No todos los sistemas de archivos que hay son capaces de compilar y funcionar, y los sistemas de archivos más oscuros son a menudo un buen candidato para alguien que busque un proyecto en el kernel.

Encontrando las cosas dentro del arbol de directorios del código fuente

El problema es, si quiere trabajar, por ejemplo, en el driver USB, ¿Dónde empiezas a mirar para buscar el código del USB?En primer lugar, puedes intentar usar el comando "find" desde el directorio principal del arbol del código fuente:

$ find . -name *usb*

Este comando imprimirá el nombre de todos los ficheros que contengan la cadena "usb" en el medio del nombre. Otra cosa que puedes intentar probar es buscar una cadena de caracteres que sea única. Esta puede ser la salida de una función

Page 18: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

printk(), el nombre de un fichero en /proc, o cualquier otra cadena de caracteres que se encuentre únicamente el en código fuente de ese driver. Por ejemplo, USB imprime el mensaje:

usb-ohci.c: USB OHCI at membase 0xcd030000, IRQ 27

Así que puede intentar un grep recursivo para encontrar el trozo de ese printk que no es un caracter de conversión de formatos como %d.

$grep -r “USB OHCI at”

Otra forma que tiene para intentar localizar dónde está el código fuente de USB es mirando en /proc. Si escribe "find /proc -name usb", probablemente encuentre que existe un directorio llamado "/proc/bus/usb". Es probable que encuentre entre las entradas de ese directorio una cadena única, que no se repita en ningún otro lugar del código, con la que pueda hacer un grep. Si todo lo demás falla, intenta descender a los directorios individuales y hacer un listado deOtra forma que tiene para intentar localizar dónde está el código fuente de USB es mirando en /proc. Si escribe "find /proc -name usb", probablemente encuentre que existe un directorio llamado "/proc/bus/usb". Es probable que encuentre entre las entradas de ese directorio una cadena única, que no se repita en ningún otro lugar del código, con la que pueda hacer un grep. Si todo lo demás falla, intenta descender a los directorios individuales y hacer un listado de los archivos, o mirando en la salida de "ls -lR".

Llamadas al sistemas

Introducción

En el sentido más literal, una llamada al sistema (también llamada "syscall") es una instrucción, similar a las instrucciones "add" o "jump". En un nivel más alto, las llamadas al sistema son la forma en que un programa de usuario le pide al sistema que haga algo.

Page 19: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

Las llamadas al sistema en detalle

Así es cómo funciona una llamada al sistema: En primer lugar, el programa de usuario prepara los parámetros para la llamada al sistema. Uno de los parámetros es el número de llamada al sistema (system call number), del que hablaremos más adelante. Se debe tener en cuenta que ésto es algo que se realiza de forma automática por las librerías de funciones, a menos que esté programando en ensamblador. Una vez que los parámetros están preparados, el programa ejecuta la instrucción de llamada al sistema (system call). Esta instrucción causa una excepción: un suceso que hace que el procesador salte a una nueva dirección y comience a ejecutar el código que haya allí.

Las instrucciones en la nueva dirección graban el estado del programa de usuario en el momento en que se ha invocado la llamada al sistema, averigua qué llamada al sistema es la que quieres realizar, llama a la función del kernel que implementa esa llamada al sistema, restaura el estado del programa de usuario y devuelve el control de nuevo a éste. Una llamada al sistema es uno de los mecanismos por el que se llama a las funciones definidas en un driver de dispositivo.

Un ejemplo de llamada al sistema

Este es un buen lugar para empezar a mostrar código que acompañe a la teoría. Seguiremos desarrollo de la invocación de la llamada a read(), comenzando desde el momento en que se ejecuta la instrucción de llamada al sistema. Se usará la arquitectura PowerPC como ejemplo para la parte del código específica de la arquitectura. En el PowerPC, cuando se ejecuta una llamada al sistema, el procesador salta a la dirección 0xc00. El código en esa posición está definido en el fichero arch/ppc/kernel/head.S

El código es algo parecido a lo siguiente:

/* System call */. = 0xc00SystemCall:EXCEPTION_PROLOGstw r3,ORIG_GPR3(r21)li r20,MSR_KERNELrlwimi r20,r23,0,16,16 /* copiar bit EE del MSR almacenado*/bl transfer_to_handler

Page 20: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

.long DoSyscall

.long ret_from_except

Lo que hace este código es grabar el estado y pasar el control a otra función llamada "DoSyscall".

Módulos del kernel

Introducción

Escribir tu propio módulo te permite escribir código independiente del kernel, aprender a usar los módulos y descubrir algunas reglas sobre cómo los enlaza el kernel. Nota: Estas instrucciones han sido escritas para los kernel 2.4.x y tal vez no funcionen con diferentes versiones del kernel.

¿Soporta módulos tu kernel?

Para esta lección, tu kernel ha de estar compilado con las siguientes opciones:

Loadable module support --->[*] Enable loadable module support[ ] Set version information on all module symbols[*] Kernel module loader

Si has compilado tu kernel de acuerdo con estas instrucciones en las primeras lecciones sobre el kernel, deberís tener ya estas opciones activadas. En caso contrario, cambia estas opciones, recompila el kernel y arranca con el nuevo kernel.

El esqueleto de un módulo sencillo

En primer lugar, busca el código fuente sobre el que fue compilado el kernel de Linux que usas actualmente. Cambia de directorio al directorio principal del código fuente de Linux. Copia y pega entonces el siguiente código en un fichero llamado "drivers/misc/mymodule.c":

#define MODULE

#include <linux/config.h>

Page 21: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>static int __init mymodule_init(void){printk ("Mi modulo funciona!n");return 0;}static void __exit mymodule_exit(void){printk ("Descargando mi modulo.n");return;}module_init(mymodule_init);module_exit(mymodule_exit);

Grabe el fichero y compila tu módulo: # make drivers/misc/mymodule.o

Cargue el módulo: # insmod ./drivers/misc/mymodule.o

Y compruebe que tu mensaje ha sido impreso: # dmesg | tail

Debería poder ver, al final del texto: Mi modulo funciona!

Ahora descarga el módulo del kernel: # rmmod mymodule

Comprueba de nuevo la salida de dmesg. Deberías poder leer: Descargando mi modulo.

Acabas de escribir y ejecutar un nuevo módulo del kernel.

El interfaz módulo/kernel

Vamos a hacer ahora cosas más interesantes con tu módulo. Una de las cosas claves de las que te tienes que dar cuenta es que los módulos solamente pueden "ver" las funciones y las variables que el kernel haga deliberadamente visibles para los módulos. Para comenzar, hagamos las cosas de la forma equivocada.Edita el fichero "init/main.c" y añade esta línea después de todos los ficheros incluidos, y cerca de las demás declaraciones de variables globales (pero fuera de las funciones):

Page 22: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

int my_variable = 0;

Ahora recompila tu kernel y arrácalo. A continuación, añade ésto al inicio de la función mymodule_init de tu módulo, antes del resto del código:

extern int my_variable;printk ("my_variable es %dn", my_variable);my_variable++;

Graba tus cambios y recompila tu módulo:

# make drivers/misc/mymodule.o

Y carga el módulo (esta operación fallará):

# insmod ./drivers/misc/mymodule.o

La carga del módulo debería haber fallado con el mensaje: ./drivers/misc/mymodule.o: unresolved symbol my_variable

Lo que ésto está indicando es que el kernel no permite a los módulos ver esa variable. Cuando el módulo es cargado, tiene que resolver todas sus referencias externas, como los nombres de las funciones o de las variables. Si no es capaz de encontrar todos los nombres no resueltos en la lísta de símbolos exportados por el kernel, el módulo no podrá escribir en esa variable, ni llamar a esa función. La variable "my_variable" tiene reservado espacio en algún lugar en el kernel, pero el módulo es incapaz de averiguar dónde.Para solucionar ésto, añadiremos "my_variable" a la lista de símbolos exportados por el kernel. Muchos directorios del kernel tienen un fichero específico para exportar los símbolos definidos en ese directorio. Abre el fichero "kernel/ksyms.c" y añade estas líneas justo antes de la primera línea "EXPORT_SYMBOL()":

extern int my_variable;EXPORT_SYMBOL(my_variable);

Recompila y arranca tu nuevo kernel. Ahora intenta cargar de nuevo tu módulo.: # insmod ./drivers/misc/mymodule.o

En esta ocasión, cuando compruebes con dmesg, deberías ver:

Page 23: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

my_variable es 0Mi modulo funciona!

Cada vez que recargues el módulo, my_variable debería incrementarse en uno. Estás leyendo y escribiendo en una variable definida en el kernel. Tu módulo puede acceder a cualquier variable o función definida en el kernel principal, siempre que sea exportada a través de la declaración "EXPORT_SYMBOL()". Por ejemplo, la función "printk()" está definida en el kernel y es exportada en el fichero "kernel/printk.c".

EjemploPuedes usar un módulo para activar o desacivar un printk, definiendo una variable "do_print" en el kernel, cuyo valor inicialmente sea cero. Esto har&aacuta; todos tus printk dependientes de "do_print": if (do_print)printk ("Big long obnoxious messagen");

Y activar "do_print" solamente cuando se cargue tu módulo. Puedes añadir una función definida en tu módulo a la lista de funciones a ser llamadas cuando el kernel recibe una interrupción determinada (usa "cat /proc/interrupts" para ver qué interrupciones están en uso). La función request_irq() añade tu función a la lista de handlers para una línea de irq seleccionada, lo que puedes usar para imprimir un mensaje cada vez que se recibe una interrupción en esa línea. Puedes investigar el valor actual de cualquier variable exportada cargando un módulo que lea esa variable y termine inmediatamente (devuelva un valor distinto de cero en la función module_init()). La variable "jiffies", que se incrementa cada centésima de segundo (en casi todas las plataformas), es una buena candidata para un módulo de este tipo.

Aplicando Parches

Introducción

Crear y aplicar parches puede ser delicado - se deben aprender un cúmulo de reglas y evitar numerosos errores habituales. Enviar un parche también requiere cierto trabajo. A primera vista, enviar parches puede parecer la parte más sencilla del desarrollo del kernel. Después de todo, no puede ser tan complicado como

Page 24: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

solucionar un error en el driver de ethernet. A menudo es más sencillo arreglar un problema en el kernel que conseguir que te acepten un parche en la línea principal del desarrollo del kernel.

Sencillez de aplicación

Si tu parche es difícil de aplicar, es casi seguro que no será aceptado. Además de crear el parche con el nivel adecuado de directorios, deberás crearlo con un kernel que sea idéntico (o casi) al que el resto de la gente va a aplicarle el parche. Así, si quieres que la persona XYZ aplique tu parche, averigua qué versión del kernel utiliza e intenta aproximarte a ella lo más posible. Habitualmente es la versión limpia del último release publicado por el mantenedor del kernel. Por ejemplo, si tienes un parche contra 2.4.18-pre3, y la última versión liberada es 2.4.18-pre7, deberías crearlo de nuevo contra la versión 2.4.18-pre7, La forma más sencilla de hacer ésto es aplicar el parche de la versión 2.4.18-pre3 a la versión 2.4.18-pre7 y arreglar los cambios que haya entre las dos versiones, para usar de nuevo diff contra 2.4.18-pre7.

¿Cómo funcionan los parches?

Un "parche" es un archivos que describe las diferencias existentes entre dos versiones de un archivo. El programa "diff" compara el archivos original y el nuevo línea a línea e imprime el resultado en la salida estándar en un formato específico. El programa "patch" es capaz de leer la salida de "diff" y aplicar esos cambios a otra copia del archivos original. (Fíjate que la palabra "parche" se refiere tanto a la salida del comando "diff" como a el comando que aplica el parche).

Ejemplo

val@evilcat <~>$ cat old/file.txtThis is a simple file.val@evilcat <~>$ cat new/file.txtThis is a slightly more complex file.val@evilcat <~>$ diff -uNr old newdiff -uNr old/file.txt new/file.txt--- old/file.txt Tue May 28 23:00:21 2002

Page 25: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

+++ new/file.txt Tue May 28 23:01:01 2002@@ -1,5 +1,5 @@This is a -simple +slightly more complex file.

Como puedes observar, los dos archivos se diferencian únicamente en una línea. La línea del primer archivos listado en la línea de comandos se muestra con un "-" delante, seguida de la línea del segundo archivo, en este caso con un "+" delante. De forma intuitiva, estás "restando" o eliminando la línea del archivo antiguo y "sumando" o añadiendo la línea del archivo nuevo. Recuerda, la línea del archivo antiguo siempre aparece en primero, y la del archivo nuevo en segundo lugar.

Aplicación de parches

Una de las razones habituales para tener que usar parches es para poder obtener una versión del kernel que no esté disponible como un fichero comprimido a descargar desde ftp.kernel.org, o para actualizar un kernel mediante parches incrementales y evitar tener que descargar un kernel nuevo completo, cuando la mayor parte de los ficheros del kernel siguen siendo los mismos.Los estándares de creación y nombres de los parches del kernel no son particularmente sencillos. Imagínate que quieres obtener el kernel 2.4.18-pre3 por alguna razón, y actualmente solo dispones de la versión completa descargable del kernel 2.4.15. Necesitarás los siguientes parches para pasar desde la versión 2.4.15 hasta la 2.4.18-pre3:

• 2.4.15 a 2.4.16

• 2.4.16 a 2.4.17

• 2.4.17 a 2.4.18-pre3

Cada preparche (los parches intermedios entre releases principales, normalmente llamados patch-2.4.x-preN, y que se encuentran habitualmente en un diectorio del ftp denominado "testing") es creado mediante el uso de diff con el release principal anterior. Un error habitual es descargar la versión del kernel 2.4.18 e intentar aplicar el preparche 2.4.18-pre3 sobre ella. Si quieres la versión del kernel 2.4.18-pre3, debes descargarte el kernel 2.4.17 y aplicar el preparche 2.4.18-pre3 sobre él. NOTA: la convención de nombres y ubicación de los preparches del kernel tiende a cambiar frecuentemente. Tal vez tengas que leerte la lista de correo linux-kernel para averiguar dónde están los últimos parches y cómo se llaman.

Page 26: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

Los parches oficiales del kernel están hechos de tal forma que lo único que necesitas hacer es: cd <arbol de codigo fuente de linux>patch -p1 < ../patchfile

En donde la opción "-p1" en en comando patch quiere decir "Elimina la parte del path en el nombre hasta la primera barra e intenta aplicar el parche con el nombre reducido de esa forma".

Ahora vamos a aplicar el parche que acabamos de crear. Un parche actualiza una versión antigua del archivo para transformarlo en una versión más moderna del mismo, por lo que queremos aplicar el parche a la versión antigua del archivo.

val@evilcat <~>$ diff -uNr old new > patchfileval@evilcat <~>$ cd oldval@evilcat <~/old>$ patch -p1 < ../patchfilepatching file file.txtval@evilcat <~/old>$ cat file.txtThis is a slightly more complex file.

Tras aplicar la salida del comando diff usando patch, el archivo "antiguo" es ahora igual que el "nuevo".

Envío de un parche

Una vez que hayas creado el parche, probablemente quieras compartirlo con otras personas. Lo ideal es que pruebes el parche tú misma, dárselo a otras personas para que también lo prueben, y que otras personas lean el propio parche. En resumen, que tu parche esté libre de errores, bien escrito, y sea sencillo de aplicar.

Pruebas

Compila y comprueba los parches tú mismo. Verás que hay gente que publica parches totalmente sin probar en la lista linux-kernel, pero no hagas caso. Un parche sin probar es muy probablemente un parche inutil. Incluso los mantenedores del kernel han liberado más de una vez parches que ni siquiera llegan a compilar. Nadie es perfecto, así que comprueba los parches que hagas.

Page 27: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

Estilo de programación

Asegúrate de que tu código encaja con el que lo rodea y que sigue las convenciones de estilo de programación del kernel. Consulta el fichero "Documentation/CodingStyle" para tener una guía específica, pero muchas veces mirar a otros ficheros del código fuente es la mejor forma de averiguar cuales son las convenciones actuales.

Creación de un parche

Lo primero que has de recordar es tener siempre una versión sin modificar del código fuente del kernel en alguna parte. No compiles en ella, ni edites ningún fichero allí, simplemente copialo para obtener una versión de trabajo del arbol de directorios del código fuente. El código fuente original del kernel debería estar en un directorio llamado "linux.vanilla" o "linux.orig", y tu directorio de trabajo debería estar en el mismo directorio que el del código original. Por ejemplo, si el código fuente original sin modificar está en "/usr/src/linux.vanilla", el código fuente de trabajo debería estar también en "/usr/src/".

Una vez que hayas realizado los cambios en la copia de trabajo del código, crearás un parche usando diff. Asumiendo que tu directorio de trabajo se llame "linux.new", ejecutarías:val@evilcat <~>$ diff -uNr linux.vanilla linux.new > patchfile

Todas las diferencias entre el código fuente original y el nuevo están ahora ne "patchfile". NOTA: No crees parches con directorios no equilibrados. Por ejemplo, no hagas ésto: val@evilcat <~>$ diff -uNr linux.vanilla working/usb/thing1/linux > patchfile

Esto no creará un parche con el formato estándar y nadie intentará probar tu parche debido a la complicación para aplicarlo.

Una vez que has creado un parche, ¡leelo! Es casi seguro que tu parche incluye ficheros que no deseas que formen parte de él, como copias viejas de seguridad creadas por el editor de textos, ficheros objeto, o cosillas varias que hayas creado durante el desarrollo. Para librarse de esos ficheros, le puedes indicar a diff que ignore ciertos tipos de fichero, puedes elmininarlos o incluso puedes editar el

Page 28: Unidad II – El Núcleo o Kernelindex-of.co.uk/SISTEMAS-OPERATIVOS/Unidad_2-SO.pdf · resto de las partes del kernel. El operador "&&" en bash es muy útil para la compilación del

parche directamente. Asegúrate de que entiendes el formato antes de modificar un parche manualmente, ya que es facil que crees un parche que no sea posible aplicar. Un comando util para deshacerse de la mayor parte de los ficheros extra creados durante la construcción de un kernel es:

make mrproper

Pero recuerda, este comando eliminará los ficheros .config y te obligará a hacer una recompilación completa del kernel. Además, asegúrate de que tu parche funciona en la dirección apropiada. ¿Tienen las líneas nuevas un "+" delante? Y, asegúrate de que esos son los cambios que quieres enviar. Es sorprendentemente facil realizar un diff con un directorio completamente equivocado.

Una vez que creas tener la versión final del parche, aplícala a una copia del arbol original del código fuente (no estropees la única copia limpia que tienes). Si no se aplica sin errores, rehaz el parche.

Consideraciones políticas

Si al distribuir tu parche no es aceptado, escucha lo que dice otra gente sobre él y trata de solucionar los problemas que pueda haber. Los parches más rechazados son aquellos que añaden características nuevas - añadir una característica nueva es considerado de mal gusto por los otros mantenedores. Si hay suficiente gente que encuentra útil tu parche, irás ganando una buena reputación entre la gente que lo descargue y lo use. A veces, un mantenedor no es capaz de aceptar un parche debido únicamente a su ego. Cuando esto ocurre, la única opción es mantener una versión mejorada del código independiente del kernel principal. A menudo, código mantenido externamente que demuestra ser mejor acaba reemplazando el código presente en el kernel tras un tiempo, el cual es un camino para llegar a ser mantenedor.