módulos - Universitat Politècnica de Catalunya

Anuncio
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
Índice
•Concepto
•Mecanismos
– Estáticos
– Dinámicos
• Módulos de Linux
– Funcionalidad básica
– Operaciones disponibles
– Ejemplo de uso: Driver de dispositivo
SO2/SOA
Qué se entiende por extender el núcleo?
• 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
SO2/SOA
Mecanismos
•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
SO2/SOA
Linux modules
•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
SO2/SOA
Operaciones sobre módulos
•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:
SO2/SOA
Operaciones sobre módulos
•Listar modulos instalados en el sistema
– # lsmod
– # cat /proc/modules
• Listar información sobre un modulo
– # modinfo module.ko
SO2/SOA
Desarrollo de un módulo de Linux
•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
SO2/SOA
Desarrollo de un módulo de Linux
• 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
SO2/SOA
Ejemplo de un módulo
#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);
SO2/SOA
Macros varias para módulos
• 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'
SO2/SOA
Contador de referencias
• 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
SO2/SOA
Device Driver
• Los módulos son usados típicamente para
cargar drivers de dispositivos
SO2/SOA
Device Driver
• 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)
SO2/SOA
Operaciones del dispositivo
Tabla
Canales
read(fd)
fd
Tabla Ficheros
Abiertos
Caract.
dinámicas
Tabla Inodos
Caract.
Estáticas (DD)
DRIVER
file_operations
open
read
write
close
SO2/SOA
Open(..){
}
Read(…){
}
Write(…){
}
Identificación del dispositivo
• 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
SO2/SOA
Registro de device drivers
• 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
SO2/SOA
Asignar operaciones a dispositivos
• 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);
SO2/SOA
Operaciones del dispositivo
• 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
SO2/SOA
Device Driver's API
• 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
SO2/SOA
Insertar un device driver con un modulo
•
•
•
•
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
SO2/SOA
Como puede el usuario usar un nuevo dispositivo?
• 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
SO2/SOA
Descargar