Etiquetas

8/02/2007

Llamadas al sistema en el núcleo 2.6 de linux (escrito en octubre del 2005)

Esta mañana hemos realizado en clase de Diseño de Sistemas Operativos la práctica 2, de creación de llamadas de sistema en el núcleo (sin usar módulos).

Aunque el guión estaba preparado para un núcleo 2.4, hemos logrado adaptarlo para el 2.6.13.4 con unos cambios mínimos.

En primer lugar, hay que introducir la entrada de la llamada al sistema en la lista. Anteriormente se introducía en este archivo:

/usr/src/linux/arch/i386/kernel/entry.S


Pero ahora se han separado las entradas de llamadas al sistema en un archivo distinto, que es incluído en el anterior. El nuevo archivo es éste:

/usr/src/linux/arch/i386/kernel/syscall_table.S


La nueva llamada al sistema se introduce al final de la lista, con una entrada así:

.long sys_nueva_llamada /* 375 */


El comentario es el número de la llamada al sistema. Es opcional, pero se recomienda incluirlo cada 5 llamadas por legibilidad del código.

Una vez introducida en la tabla de llamadas, debemos introducir su prototipo en la cabecera unistd.h . En mi caso, lo añadí únicamente al unistd.h de la arquitectura i386, localizado en /usr/src/linux/include/asm-i386/unistd.h. El prototipo se incluye con esta entrada, nuevamente al final de la lista y siempre con cuidado de asignarle un número nuevo, no usado:

#define __NR_nueva_llamada 375


Justo debajo debería aparecer una línea que indica el número de llamadas al sistema en la lista. Debemos incrementar ese número tantas veces como llamadas nuevas hayamos introducido, o podrían darse problemas una vez compilado el núcleo:

#define NR_syscalls 376


Ahora que la nueva llamada consta en el sistema, podemos introducir el cuerpo de la llamada. Esto podemos hacerlo al final del archivo /usr/src/linux/kernel/sys.c . Por ejemplo:

asmlinkage long sys_nueva_llamada(void){
printk("Esta llamada es nueva\n");
return 0;
}


Ya sólo queda recompilar e instalar el núcleo con los cambios y hacer un programa que pruebe que nuestra llamada funciona.

Antes de ese paso, nos encontramos con problemas ya que el código estaba preparado para el núcleo 2.4, mientras que no era compatible con el 2.6.13. Por ejemplo, el puntero p_pptr (que apunta al padre de un proceso en la estructura task_struct) ahora es llamado parent.

También fue necesario cambiar la función verify_area (deprecada en el 2.6) por access_ok . Los parámetros son los mismos, pero el resultado es justo el contrario (mientras que verify_area devuelve 0 cuando se puede acceder al area de memoria indicada, access_ok devuelve 0 cuando no se puede acceder.

8/01/2007

Escribiendo código portable

Uno de los mayores problemas cuando un proyecto debe funcionar en varios sistemas es ver cómo diferentes compiladores se atragantan en código que funciona bien en otro compilador.

La guía de portabilidad en C++ del proyecto Mozilla es una buena lectura para evitarse quebraderos de cabeza después. Aunque está orientada a C++, tiene aspectos aplicables a C. Por ejemplo no hay que olvidar que el inlining de funciones es una lotería, especialmente en compiladores como el de HP-UX, donde directamente se sugiere aniquilar todo uso de inline.