Download Práctica 2. Módulos del núcleo de Linux: acceso a recursos de
Document related concepts
no text concepts found
Transcript
Arquitectura y Tecnologı́a de Ordenadores Personales (IS37 - II37) Ingenierı́a Técnica en Informática de Sistemas - Ingenierı́a Informática Práctica 2. Módulos del núcleo de Linux: acceso a recursos de dispositivos. 1. Objetivos Con el desarrollo de esta práctica, además de continuar con el estudio de la estructura de los módulos de Linux –versión 2.6.x del núcleo– se verá cómo acceder a los registros de los dispostivos, mapeados en memoria o en entrada/salida del bus PCI. 2. Introducción El núcleo accede a los registros de los dispositivos mediante accesos al mapa de memoria o de entrada/salida del sistema. Los drivers programados especı́ficamente –módulos en caso de linux– conocen estos registros, sus direcciones relativas y su función. En el caso de un dipositivo PCI, el driver debe primero encontrar las direcciones base del dispositivo, que el núcleo ha asignado durante el proceso de configuración del bus PCI. Una vez obtenida la dirección base, en el caso de tratarse de registros en el mapa de memoria, el driver debe remapear el bloque de memoria fı́sica en una zona de memoria virtual del núcleo. En el caso de la entrada/salida, se accederá normalmente usando las funciones intrı́nsecas que el compilador traduce a las instrucciones de E/S de la arquitectura. En esta práctica se verá cómo se obtiene la información del dispositivo –proceso que se estudió en la práctica 1–, cómo se realiza el mapeo de la memoria y cómo se llevan a cabo los accesos. Se trabajará con el dispositivo controlador de bus USB EHCI y con el puente al bus SMB, presentes ambos en el ICH del chipset. Se compilará un módulo y un programa de prueba para cada uno de ellos. 3. Estructura de los módulos ejemplo accesoMEM.c y accesoES.c El módulo implementa las funciones básicas que se vieron en la práctica 1. Más adelante se describirán sus particularidades. A nivel general, en este ejemplo se ha hecho uso de las macros MODULE LICENSE(), MODULE AUTHOR() y MODULE DESCRIPTION() para evitar los avisos del núcleo y para dar información acerca del módulo. A continuación se comentan las funciones más importantes, haciendo hincapié en sus diferencias con respecto a lo visto en la primera práctica. init module(): Es la función que carga el módulo en memoria del núcleo. En este caso, como el manejador de un dispositivo real, lo primero que se hace es ver que el dispositivo existe, identificar los recursos y crear las direcciones de acceso. Todo esto se hace en la función prueba(). Es interesante estudiar el uso de la llamada pci get device() y de la estructura que devuelve, ası́ como de la función ioremap() que permite proyectar la memoria fı́sica del dispositivo PCI en el mapa de memoria del núcleo. Como en un caso real, si el dispositivo no se encuentra o los recursos no son los esperados, el módulo indica esta circunstancia y no se carga. cleanup module(): Es la función que se invoca al eliminar el módulo del núcleo. No ofrece ninguna particularidad. acceso read(): La llamada read() en este caso accede realmente a los recursos del dispositivo, y nos devuelve el valor del registro que previamente hemos seleccionado –con write(). Es interesante constatar cómo se accede a memoria mediante la función readw() –de la que existen las versiones de 8 y 32 bits, readb() y readl() respectivamente– o al mapa de entrada/salida mediante la función intrı́nseca inb() –de la que también existen las versiones de 16 y 32 bits, inw() y inl() respectivamente. acceso write(): La llamada write() selecciona un registro para efectuar luego la lectura con read(). Verifica que el registro esté dentro de la zona de recursos reservada y en el caso de acceso a memoria, fuerza que sea múltiplo de 4 –dado que los accesos son de 32 bits. acceso open(): A diferencia de la función de la práctica 1, esta llamada indica al núcleo que el módulo está siendo usado, mediante la llamada try module get(THIS MODULE), para que no pueda ser descargado por error. acceso módulo módulo módulo 4. release(): En este caso también, la llamada close() indica al núcleo que el tiene un usario menos –en este ejemplo que no permite más que uno, que el no está en uso– mediante la función module put(THIS MODULE) para que el pueda ser descargado sin problemas. Trabajo a desarrollar 1. Descargad el código de los módulos y de los programas de prueba, en el fichero acceso.v2.tgz. En el archivo acceso.h será necesario eliminar el comentario de la lı́nea que identifica el chipset de los ordenadores del laboratorio. Observad el fichero Makefile; permite generar los programas de prueba para ambos módulos invocando el objetivo correspondiente prES o prMEM. Sin embargo es necesario eliminar el comentario de una de las dos lı́neas iniciales para generar el módulo correspondiente. Compilad todos los programas y módulos y cargadlos en el núcleo. 2. Cread los dispositivos adecuados en /dev –consultad para ello el código del programa de prueba– con las caracterı́sticas correspondientes, y ejecutad las pruebas. Cotejad los valores devueltos con lo esperado según el manual del chip ICH del chipset del laboratorio. 3. Observad el código de los módulos, las funciones más significativas y los textos que se imprimen en los mensajes núcleo. Recompiladlos sin la opción de depuración y probarlo de nuevo. 4. Crear un nuevo módulo para acceder a memoria o a entrada/salida de algún otro dispositivo del chipset. 5. Bibliografı́a Se puede encontrar más información acerca de los módulos, su creación y la forma de acceder a ellos en el documento The Linux Kernel Module Programming Guide disponible en http://www.tldp.org o en la web de la asignatura.