Linux Device Drivers Técnicas Digitales III Ing. Gustavo Nudelman 2011

 
SEGUIR LEYENDO
Linux Device Drivers

Técnicas Digitales III
Ing. Gustavo Nudelman
2011

                         Universidad Tecnológica Nacional - Facultad Regional Buenos Aires
Conceptos Generales

Subtitulo o nombre del
Capitulo 1
capitulo
                                               Universidad
 Universidad Tecnológica Nacional - Facultad
                                               Tecnológica
           Regional Buenos Aires
                                                Nacional
Introducción – Que es un driver ?

 •   Un kernel no puede contemplar estáticamente todos los dispositivos
     existentes ni menos los que se desarrollan a futuro.

 •   El kernel debe permitir ser reestructurado en forma dinámica

                           Universidad Tecnológica Nacional - Facultad
                                     Regional Buenos Aires
Introducción – Extendiendo el kernel
•   Una de las grandes prestaciones de Linux reside en la posibilidad
    de extender las funcionalidades del kernel extendiendo su
    estructura.

     •   Recompilar el kernel
          •   Obtenemos un nuevo kernel monolítico que incorporará nuevas
              funcionalidades (Built in)

     •   Utilizar módulos insertables
          •   Permite agregar y/o quitar funcionalidades con módulos
              compilados aparte, sin necesidad de reiniciar el sistema ni
              interrumpir la actividad del kernel.

          •   Si los módulos interactúan con el hardware se dice que son
              “Device Drivers”

          •   Los módulos son implementados con código objeto, (no
              ejecutable) que es enlazado dinámicamente mediante a
              herramientas que provee el sistema
                              Universidad Tecnológica Nacional - Facultad
                                        Regional Buenos Aires
Características de un device driver
 •   Provee mecanismo de acceso a dispositivos. No políticas

 •   Se ejecutará en el contexto del proceso que lo invoque y será
     parte de dicho proceso

 •   Cualquier error de programación que en aplicaciones pueda
     significar un “Segmentation fault”, producirá un “kernel panic”.

 •   No se puede invocar a funciones que se encuentran en bibliotecas
     del sistema, ya que no se realiza un proceso de linking. (ej. No se
     puede usar printf())

 •   Se tiene accesos a estructuras del sistema operativo

 •   Se debe disponer de los fuentes del kernel.

 •   ESTAMOS MODIFICANDO KERNEL

                            Universidad Tecnológica Nacional - Facultad
                                      Regional Buenos Aires
Tipos de drivers
•   Carácter:
     •    Acceden a las direcciones I/O transfiriendo una sucesión (stream) de
          bytes
     •    Pueden ser invocados por encuesta (pooling) o interrupción
     •    Se accede a los bytes en forma secuencial

•   Bloque
     •    Dispositivos que almacenan grandes cantidades de información
     •    Las operaciones de I/O se realizan por bloques que poseen un
          tamaño mínimo de 512 bytes o potencias de 2 sucesivas.
     •    Las operaciones de I/O las realizan con DMA
     •    El descriptor de archivo que representa el punto de entrada al driver,
          permite “moverse” hacia adelante y hacia atrás.

•   Red
     •    Interactúan con los dispositivos de red pero también con dispositivos
          virtuales y estructuras de kernel que comprende al protocolo de la
          capa superior siguiente (Campo type)

                               Universidad Tecnológica Nacional - Facultad
                                         Regional Buenos Aires
Identificación de un driver

                            Major              Minor

•   Los inodos mostrados en la figura (directorio /dev) identifican los puntos de
    entrada a los drivers para realizar operaciones (Open, Read, Write y close con los
    dispositivos)

•   Numero Major: Identifica a una unidad funcional separada

•   Número Minor: Identifica subunidades funcionales que se pueden controlar con el
    mismo driver, o diferentes modos de uso de un mismo dispositivo.

•   El archivo /proc/devices muestra los dispositivos con su número major
                               Universidad Tecnológica Nacional - Facultad
                                         Regional Buenos Aires
Estructura y diseño de
un char device driver

Subtitulo o nombre del
Capitulo 2
capitulo
                                               Universidad
 Universidad Tecnológica Nacional - Facultad
                                               Tecnológica
           Regional Buenos Aires
                                                Nacional
Estructura de un device driver
•   Se trata de un conjunto de funciones normalizado, ya que un driver
    debe responder a una interface bien definida con el kernel que posea
    determinados puntos de entrada

•   Carece de función main() – No necesita un punto de entrada
    autónomo

•   Las funciones son llamadas desde quien invoca al driver, o desde
    eventos del sistema

•   Si bien un usuario normal puede programar y compilar un driver, la
    tarea de incorporar este al kernel solo puede ser efectuada por root.

•   Lo que agregamos es código objeto puro  No debemos linkear

•   UN DRIVER NO ES UN PROCESO SINO PARTE DEL PROCESO Y
    CONTEXTO QUE LO INVOCA

                             Universidad Tecnológica Nacional - Facultad
                                       Regional Buenos Aires
Estructura de un char device driver
    module_init([Funcion_Init]);                    Funciones básicas (constructor y
    module_exit([Funcion_cleanup]);                 destructor). Siempre deben estar

    struct file_operations [name] =
     {
       .read = [Funcion_read],                        Estructura con los puntos de
       .write = [Funcion_Write],                      entrada. (Los que no se utilicen se
       .open = [Funcion_Open],                        mapean a NULL)
       .release = [Funcion_Close],
       .owner = THIS_MODULE
    };

    Funcion_Init( . . .)
      {
       ......
       }
    Funcion_Cleanup( . . .)                            Desarrollo de las funciones
      {
       ......
       }
    Funcion_ Read(. . .)
                              Universidad Tecnológica Nacional - Facultad
    .                                   Regional Buenos Aires
Descripción de los métodos - Inserción
 •   module_init:
       •   La función asociada con este evento será invocada al momento de insertar el
           módulo en el kernel (modprobe o insmod)

       •   La función no recibe argumentos pero puede devolver un entero indicando si
           tuvo éxito la inserción

       •   Se acostumbra a registrar en driver en este evento mediante register_chrdev

       •   Podemos revisar el driver insertado con el comando lsmod

     Int register_chrdev (unsigned int major, const char *name, const struct file_operations)

Devuelve el                                         Nombre con                  Puntero a la estructura
numero            Numero major                      el que se
                  requerido. (si es cero                                        file_operations donde
“major”                                             registra el                 quedan definidas las
asignado          el sistema busca el               módulo
                  primero disponible)                                           funciones

                                  Universidad Tecnológica Nacional - Facultad
                                            Regional Buenos Aires
Descripción de los métodos - Apertura
    •   .open:
          •   La función asociada con este método será invocada al momento que
              se efectue la llamada “open” sobre inodo que funciona como punto de
              entrada al driver.

          •   Dado que esté es el evento donde se “pide” por un recurso, es en esta
              función donde se debe reservar todo lo inherente a dicho recurso

        Int [Funcion_Open] (struct inode *inode, struct file *filp)

                                                                                   :
                                                                                   struct file {
Devolvemos el                                                                      mode_t f_mode;
éxito o fracaso      Datos de inode por el                                         loff_t pos;
de la                cual accede el usuario                                        unsigned int f_flags;
implementación       (estado                                                       struct file_operations *f_op;
                     del fichero, hora de                                          void *private_data;
                     creación y modificación,                                      ...
                     etc.)           Universidad Tecnológica Nacional - Facultad
                                                 Regional Buenos Aires             }
Método .Open – Estructuras asociadas
  Definidas en     :

  struct file
  {
    mode_t f_mode;                            Modo de lectura/escritura
    loff_t pos;                               posición actual para read/write
    unsigned int f_flags;                     Opciones del fichero usadas al abrir
    struct file_operations *f_op;             Estructura f_op
    void *private_data;                       Memoria reservada para guardar datos
  ...                                          (Muchas veces se guarda el minor para
  }                                            que este disponible para otros métodos)

  struct inode
   {
  kdev_t i_rdev;                              Contiene la inf. del número major y minor
  ...
  }

                            Universidad Tecnológica Nacional - Facultad
                                      Regional Buenos Aires
Método .Open – utilización

 •   Chequear errores del dispositivo

 •   Inicializar el dispositivo

 •   Comprueba disponibilidad de recursos necesarios

 •   Reserva recursos del sistema (ej., IRQ, semáforos, etc.)

 •   Comprueba el numero minor y actualiza contadores

                                  Universidad Tecnológica Nacional - Facultad
                                            Regional Buenos Aires
Método .Open – Reserva de IRQ
int request_irq (unsigned int irq, void (*handler) (int, void *, struct pt_regs *),
unsigned long irqflags, const char *devname, void *dev_id)

    •   Irq: Número de IRQ que estamos solicitando

    •   Handler: Puntero al handler de la IRQ

    •   Irq flag: Comportamiento de la IRQ (Ej. IRQF_SHARED si es compartida)

    •   devname: Es el string que se muestra en /proc/interrupts

    •   Dev_id: Es un puntero, especialmente utilizado en interrupciones de tipo
        compartidas, sirve para colocar allí información privada de manejador de
        interrupción

  Si la asignación puede realizarse, la función devuelve 0

  También podemos observar /proc/interrupts
                                 Universidad Tecnológica Nacional - Facultad
                                           Regional Buenos Aires
Método .read - Introducción
•   La función asociada con este método será invocada al momento que
    se efectúe una operación de lectura (read) a través del descriptor de
    archivo del inodo asociado.

•   La información a entregar, se copia desde un buffer en modo Kernel
    al buffer correspondiente en modo usuario.

•   Se acostumbra a entregar la información requerida si esta está
    disponible, o a bloquear el proceso si no lo está.

•   No es de buena práctica no bloquear al proceso si la
    información no está disponible

                            Universidad Tecnológica Nacional - Facultad
                                      Regional Buenos Aires
Método .read

ssize_t [Func Read] (struct file *flip, char *buff, size_t count, loff_t *offp)

    •   flip : Puntero a la estructura tipo FILE (Idem al método .open)

    •   buff: Buffer de usuario donde debemos depositar los datos

    •   count : Se le indica al driver la cantidad de bytes que debe leer

    •   offp : Se actualiza la posición del puntero a archivo.

                                Universidad Tecnológica Nacional - Facultad
                                          Regional Buenos Aires
Método .read (2)

              Universidad Tecnológica Nacional - Facultad
                        Regional Buenos Aires
Semáforos del Kernel
•   La manera de poner a dormir un proceso en modo kernel es con
    semáforos

•   Se trata de semáforos del kernel – NO SYSTEM V

•   Debemos Instanciarlo
                            struct semaphore [semName]

•   Debemos Inicializarlo
                            Sema_init (&semName, valor )

•   Se decrementa (toma) el semáforo previo a una operación. Si el
    semaforo estaba en 0, el proceso pasa a “sleeping”
         down_interruptible(&semName)  El proceso puede ser interrumpido por señal
         down(&semName)                El proceso no puede ser interrumpido
                              Universidad Tecnológica Nacional - Facultad
                                        Regional Buenos Aires
Poniendo a dormir al proceso en .read
ssize_t [Func Read] (struct file *flip, char *buff, size_t
count, loff_t *offp)
{
  char byte_read;

    down_interruptible (&sem);

    byte_read=inb(0x2f8);

    copy_to_user(buff,&byte_read,(unsigned long) 1);

}

    •   También podemos reservar memoria dinámica en modo kernel
        (según el tamaño especificado para leer)
                Kbuffer = kmalloc(TAMAÑO,GFP_KERNEL);

           (En modoo kernel, usamos kmalloc para reservar memoria)
                            Universidad Tecnológica Nacional - Facultad
                                      Regional Buenos Aires
Despertando al proceso
static irqreturn_t [intr_handler](int IRQ, void *dev_id, struct pt_regs *regs)

                     N de IRQ                                                Estructura
                     (por si lo             Misma
IRQ_NONE                                    estructura                       con los
                     queremos                                                registros de
IRQ_HANDLED          informar en            que en la
                                            función                          la CPU antes
                     algún log)                                              de la
                                            request_irq()
                                                                             interrupción

Uso práctico
Irqreturn_t[handler] (int irq, void *devid, struct pt_regs
*regs)
{
  up (&sem);

    return IRQ HANDLED

}
                               Universidad Tecnológica Nacional - Facultad
                                         Regional Buenos Aires
Método .write - Introducción
•   La función asociada con este método será invocada al momento que
    se efectue una llamada “write” a través del descriptor de archivo del
    inodo asociado.

•   La información entregada por el proceso, se copia desde el buffer de
    usuario al buffer correspondiente en modo kernel.

•   El driver debe bloquear al proceso con semáforos en el caso de que
    el dispositivo no esté disponible.

                            Universidad Tecnológica Nacional - Facultad
                                      Regional Buenos Aires
Método .write – función asociada

ssize_t [Funcion Write](struct file *filp, const char *buff, size_t count, loff_t
*offp)
  •   flip : Puntero a la estructura tipo FILE (Idem al método .open)

  •   buff: Buffer de usuario donde recibimos los datos

  •   count : Es usuario especifica la cantidad de bytes a escribir

  •   offp : Se actualiza la posición del puntero a archivo.

  •   Como ya sabemos, debemos retornar la cantidad de bytes realmente
      escritos

  •   Los datos recibidos pasan al kernel utilizando la función
 unsigned long copy_from_user(void *to, const void *from, unsigned long count)

                                Universidad Tecnológica Nacional - Facultad
                                          Regional Buenos Aires
Método .release
•   La función asociada con este evento será invocada al momento que
    se invoque a la llamada close a través del descriptor de archivo del
    inodo asociado.
       void [Funcion Close] (struct inode *inodep, struct file *filp)
                Utiliza los mismos argumentos que el método .open

•   Suele decrementarse el contador de uso en el caso de que
    tengamos diferentes dispositivos actuando con el mismo driver

•   Se liberan recursos como memoria alocada, interrupciones
    reservadas, etc.
                    void free_irq (unsigned int irq, void *dev_id);

•   Se apaga el dispositivo si se trata del último cierre

                              Universidad Tecnológica Nacional - Facultad
                                        Regional Buenos Aires
Método .ioctl
•    Utilizado para configurar dispositivos una vez abiertos

•   La configuración se hace por medio de comandos

•   El comando de configuración es propietario el dispositivo y para
    quien diseñe el driver (Este debe proveer el set)

int ptr_ioctl (struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg)

                                Universidad Tecnológica Nacional - Facultad
                                          Regional Buenos Aires
module_exit - Remoción del módulo
    •   La función asociada con este método será invocada al
        momento de remover el módulo del kernel (rmmod)

    •   La función no recibe argumentos pero puede devolver un
        entero indicando si tuvo éxito la remoción

    •   Se acostumbra a quitar el driver del registro del sistema

 int unregister_chrdev (unsigned int major, const char *name);

                           Universidad Tecnológica Nacional - Facultad
                                     Regional Buenos Aires
Compilación y gestión
del módulo

Subtitulo o nombre del
Capitulo 3
capitulo
                                               Universidad
 Universidad Tecnológica Nacional - Facultad
                                               Tecnológica
           Regional Buenos Aires
                                                Nacional
Requerimientos previos

    Fuentes del kernel

        •   Redhat/fedora

             # yum install kernel-devel

             # yum install doc

        •   Debian /Ubuntu

             # apt-get install linux-headers-$(uname -r)

 Los fuentes se instalan en /usr/src

                            Universidad Tecnológica Nacional - Facultad
                                      Regional Buenos Aires
Compilación - Makefile

  file=[nombre del archivo fuente]
  obj-m := fent.o
  KERNELDIR := /lib/modules/$(shell uname -r)/build
  PWD := $(shell pwd)

  default:
  $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

    •   obj-m es el nombre del módulo a crear(se creará un .o y un .ko)

    •   KERNELDIR es el directorio donde se encuentran las fuentes del kernel que
        se necesitan para compilar los módulos

    •   PWD es el directorio actual

    •   default la orden con la que crearemos los módulos

                              Universidad Tecnológica Nacional - Facultad
                                        Regional Buenos Aires
Inserción y remoción del módulo

      •   Inserción
           •   modprobe  (Controla dependencias)
           •   Insmod    (no controla dependencias)

      •   Remoción
           •   rmmod  remueve el módulo
           •   modprobe  -r

Podemos ver la salida de estos comandos en /var/log/messages o en la consola si
esta es de texto

                             Universidad Tecnológica Nacional - Facultad
                                       Regional Buenos Aires
Inodo de acceso en /dev

   •   El inodo de acceso o punto de entrada al driver, se crea y
       vincula con el módulo mediante el comando mknod

          # mknod /dev/          c            

                           Especifica                       Es el parámetro que vincula al
                           que es un                        inodo con el driver
                           char device

                          Universidad Tecnológica Nacional - Facultad
                                    Regional Buenos Aires
Utilidades de consola

   •   lsmod muestra los módulos instalados en el kernel

   •   El archivo /proc/devices muestra los dispositivos con su
       número major asignado

   •   El archivo /proc/interrupts permite ver las interrupciones
       asociadas al driver (útil para chequear si la asignación fue
       exitosa)

   •   Se recomienda monitorear la salida de cada método mediante

                      # tail –f /var/log/messages

                           Universidad Tecnológica Nacional - Facultad
                                     Regional Buenos Aires
Resumen
  •   Un driver no deja de ser un módulo compuesto por un
      conjunto de funciones que responden a un standard de la
      arquitectura del S.O.

  •   Las interacciones con el sistema operativo son pocas,
      simples y bien definidas

  •   El arte consiste en el manejo del dispositivo en si mismo

                         Universidad Tecnológica Nacional - Facultad
                                   Regional Buenos Aires
Ref: http://lwn.net/Kernel/LDD3/

      Universidad Tecnológica Nacional - Facultad
                Regional Buenos Aires
También puede leer