mecanismos de extensión del núcleodocencia.ac.upc.edu/fib/grau/so2/documents/tema7.pdf · •...
TRANSCRIPT
SO2/SOA
Mecanismos de extensión del núcleo
Yolanda Becerra Fontal
Juan José Costa Prats
Facultat d'Informàtica de Barcelona
Universitat Politècnica de Catalunya
BarcelonaTech
2014-2015QT
SO2/SOA
•Concepto
•Mecanismos
– Estáticos
– Dinámicos
• Módulos de Linux
– Funcionalidad básica
– Operaciones disponibles
– Ejemplo de uso: Driver de dispositivo
Índice
SO2/SOA
• Añadir nuevas funcionalidades o características a un sistema operativo – Cambiar política planificación
– Arreglar un error de seguridad
– Añadir soporte para nueva tarjeta de red
• Añadir código (rutinas) y datos (estructuras y variables)
• Básicamente hay 2 mecanismos – Estáticos
– Dinámicos
Qué se entiende por extender el núcleo?
SO2/SOA
•Estáticos – En tiempo de compilación – Necesitamos acceso al código fuente – Añadir el nuevo código y los datos – Y generar nueva imagen del sistema operativo
•Dinámicos – En tiempo de ejecución – En algunos casos sin la necesidad de reiniciar la máquina – Nuevo código y datos encapsulados en algun formato
binario que permita su inserción dinámica – No todos los sistemas lo permiten
Mecanismos
SO2/SOA
•Linux permite inserción dinámica de código y datos a traves de los módulos
– La alternativa es recompilar el sistema
• Los módulos tienen las mismas limitaciones que cualquier otro desarrollo dentro del sistema: – Solo se pueden acceder/modificar los símbolos públicos del kernel
(aquellos que han estado exportados explícitament)
– No hay acceso a la libreria de C
– Herramientas de depuración limitadas (p.ej: chivatos con printk)
• Finalmente obtenemos un fichero binario (kernel object) que podemos insertar / quitar dinámicamente
Linux modules
SO2/SOA
•Instalar un módulo – # insmod mymodule.ko [param=value][,
param=value]*
•Quitar un módulo – # rmmod mymodule.ko
•Instalar un módulo resolviendo dependencias – # modprobe moduloA.ko
– # cat /lib/modules/version/modules.dep /path_completo/moduloA.ko: /path_completo/moduloB.ko
/path_completo/moduloB.ko:
Operaciones sobre módulos
SO2/SOA
•Listar modulos instalados en el sistema
– # lsmod
– # cat /proc/modules
• Listar información sobre un modulo
– # modinfo module.ko
Operaciones sobre módulos
SO2/SOA
•Programar los ficheros para implementar el módulo – Funciones de inicialización y finalización
• Se invocan al instalar/desinstalar un módulo
– Código/datos a incluir en el sistema – Exportar variables/funciones que vayan a ser usadas fuera del módulo
• EXPORT_SYMBOL( f ) → “ksyms -a” o “cat /proc/kallsyms”
– Puede usar cualquier variable/función exportada por el kernel u otros módulos
• Compilar los ficheros – Es necesario disponer de los fuentes del sistema – Produce un fichero objeto (.ko = kernel object)
• Insertarlo en el sistema – Cargar el módulo y sus dependencias – Pasar parametros de inicialización
• Usar el módulo
Desarrollo de un módulo de Linux
SO2/SOA
• Desde el módulo podeis acceder a muchas funciones para la gestión de estructuras de datos: – find_task_by_pid
– for_each_process
– …
– Antes de implementar algo, mirad que no exista!
• Desde el módulo accedeis al espacio de direcciones de usuario:
unsigned long copy_from_user(void *to, const void *from, unsigned long count);
unsigned long copy_to_user(void *to, const void *from, unsigned long count
Desarrollo de un módulo de Linux
SO2/SOA
#include <linux/module.h> #include <linux/kernel.h> /* * Module initialization. */ static int __init Mymodule_init(void)
{ . . . } /* * Finalization module. */ static void __exit Mymodule_exit(void)
{ . . . } module_init(Mymodule_init); module_exit(Mymodule_exit);
Ejemplo de un módulo
SO2/SOA
• module_param (parameter name and type)
– int pid=1; – module_param (pid, int, 0);
• MODULE_PARM_DESC (parameter description)
– MODULE_PARM_DESC (pid, "Process ID to monitor
(default 1)");
• MODULE_AUTHOR (author list)
• MODULE_DESCRIPTION • MODULE_LICENSE (GPL, BSD, …)
• Información visible con 'modinfo'
Macros varias para módulos
SO2/SOA
• Un módulo puede descargarse, sí y solo sí, ningún proceso lo esta usando
– Hay un contador de referencias, para quantificar el uso del módulo • Pero la gestión la tiene que hacer el programador del módulo :(
• try_module_get( THIS_MODULE ) – Incrementa contador: Alguien esta usando el módulo.
• module_put( THIS_MODULE ) – Decrementa contador: Alguien ha dejado de usar el módulo
• Hay que programar esta gestión en todas las rutinas públicas
Contador de referencias
SO2/SOA
• Los módulos son usados típicamente para cargar drivers de dispositivos
Device Driver
SO2/SOA
• El driver es un conjunto de variables y funciones para manejar un dispositivo (logico o físico)
• Utiliza una API estandar
– Interna (no visible para el usuario)
– Basado en el struct file_operations
• Solo hay que proporcionar las funciones requeridas por el dispositivo (p.ej: open, read)
Device Driver
SO2/SOA
Operaciones del dispositivo
read(fd)
Tabla Canales
Tabla Ficheros Abiertos
Caract. dinámicas
Tabla Inodos
Caract. Estáticas (DD)
fd
file_operations
open read write close
Open(..){ } Read(…){ } Write(…){ }
DRIVER
SO2/SOA
• Identificados por un major y un minor – Simples números
• dev_t MKDEV (major, minor)
– Históricamente, el major identificaba la clase de dispositivo (p.ej: una impresora) y el minor diferentes dispositivos dentro de la misma clase (p.ej: modelos diferentes de la misma impresora)
• Este identificador permite al kernel saber que driver tiene que usar para comunicarse con el dispositivo
• Hay un fichero visible para el usuario con ese major y minor
Identificación del dispositivo
SO2/SOA
• Los device drivers se tienen que registrar en el sistema asociándole su identificador
int register_chrdev_region (dev_t first, unsigned int count, const char *name);
• Y para eliminar su registro:
void unregister_chrdev_region (dev_t first, unsigned int count);
• El interfaz depende del tipo de dispositivo
Registro de device drivers
SO2/SOA
• Primero, crear una estructura cdev: struct cdev * cdev_alloc()
• Segundo, inicializar sus campos: – owner: con THIS_MODULE
• Para que el kernel se encargue de la gestion de los contadores
– ops: con la estructura file_operations del dispositivo
• Finalmente, asignar la estructura al dispositivo/s: int cdev_add (struct cdev *dev, dev_t num, unsigned int
count);
• Para borrarlo: void cdev_del (struct cdev *dev);
Asignar operaciones a dispositivos
SO2/SOA
• La estructura file_operations esta en <linux/fs.h> • struct file_operations my_operations = { owner: THIS_MODULE, read: my_read, ioctl: my_ioctl, open: my_open, release: my_release, }; • El campo owner automatiza gestión contadores
Operaciones del dispositivo
SO2/SOA
• Cuando usuario hace open/close sobre dispositivo: – int my_open (struct inode * i, struct file * f); – int my_release (struct inode * i, struct file * f);
• ssize t my_read (struct file * f, char * buffer, size t_size, loff_t * offset); – Es necesario usar copy_to_user para acceder al buffer – offset es un parám. de entrada/salida. Posición actual en
“file”
• int my_ioctl(struct inode * i, struct file * f, unsigned int request, unsigned long argp); – Usado para controlar las operaciones dentro del
dispositivo
Device Driver's API
SO2/SOA
• Variable de tipo dev_t con el major i minor del disp.
• Funciones del dispositivo
• Variable de tipo struct file_operations inicializada
• Variable de tipo cdev para ligar las operaciones y el dispositivo
• Al inicializar el módulo: – Registrar el dispositivo dentro del kernel y asociar las
operaciones
• Al finalizar el módulo: – Eliminar el registro y borrar el cdev
Insertar un device driver con un modulo
SO2/SOA
• Administrador crea el dispositivo con el comando 'mknod', usando el identificador del dispositivo:
– mknod <filename> <type> <major> <minor>
– p.ej: mknod mydevice c 255 1
• Crea un fichero 'mydevice' que usará el driver de caracteres identificado con el major 255 y minor 1
• Ahora el usuario puede acceder a este fichero con el API de entrada/salida estandar
Como puede el usuario usar un nuevo dispositivo?