Sistemas Informáticos de Tiempo Real

Lectura/Escritura de puerto de E/S en Linux:

Interferencias con el núcleo del S.O.:
Hay que resaltar primero que el acceso directo a un puerto de E/S por parte de un proceso de usuario puede interferir gravemente con el funcionamiento del núcleo del S.O. (llegando incluso al bloqueo) ya que este puede estar controlando el estado del hardware que manipulamos bajo la hipótesis de que nadie más puede acceder simultáneamente. Para evitar estas interferencias debemos estar seguros de que el S.O. no va a acceder al controlador en cuestión:
  • Si el controlador al que accedemos no está soportado por el núcleo, es poco probable que este acceda a sus puertos (quizás es posible durante el arranque del S.O.). Un ejemplo de esto es una tarjeta de E/S digital que no esté soportada por el Kernel.
  • Si el controlador está soportado debemos deshabilitar todos los servicios que puedan generar accesos al mismo, y si es posible deshabilitar el soporte de dicho hardware en el núcleo. Esto último se suele hacer reconfigurando el núcleo (en Linux se hace recompilando los fuentes del núcleo después de haber modificado la lista de hardware soportado). Un ejemplo de esto sería el puerto paralelo, soportado por el núcleo y usado por el servicio de impresión. En este caso deberíamos deshabilitar dicho servicio y si es posible recompilar el Kernel sin soporte de puerto paralelo.
  • Habilitación de acceso a un puerto en Linux:
    Las instrucciones para acceder a los puertos de E/S (in y out) solo pueden ejecutarse en el modo privilegiado del procesador, modo en el cual solamente se ejecuta el código del núcleo del S.O. Si un proceso ejecuta una de estas instrucciones generará una excepción por instrucción ilegal que dará lugar a que el S.O. aborte la ejecución del proceso.
    En Linux existe una llamada al sistema que permite habilitar el acceso a varios puertos consecutivos durante la ejecución de un proceso. Una vez habilitado, las instrucciones in y out a dichos puertos podrán ser ejecutadas en el proceso hasta que se deshabilite o hasta que termine el proceso. Esta llamada solo permite especificar puertos entre 0000 y 03FF. Otro detalle importante es que la llamada solo funciona cuando la ejecuta un proceso del administrador del sistema (root). De este modo evita que cualquier usuario pueda manipular el hardware de la máquina.
    ioperm(dirección_de_puerto, número_de_bytes_consecutivos, 1=habilitar/0=deshabilitar)
    La forma de programar es sencilla:
    if (ioperm(0x378,3,1))
      {
        fprintf(stderr,"Error obteniendo acceso al puerto paralelo.\n");
        exit(1);
      }
    c=inb(0x379);
    outb(c,0x378);
    Es necesario tener en cuenta que el acceso a los puertos no lo hace realmente la instrucción del proceso de usuario. La realidad es que se genera una excepción por instrucción ilegal donde el Kernel consulta si el puerto accedido está en la lista de autorizados, llevando a cabo dentro del núcleo (donde sí están permitidas las instrucciones in  y out) el acceso. Por último, el Kernel devuelve el control al proceso en la siguiente instrucción como si nada hubiera pasado. La diferencia es que el tiempo empleado por la instrucción pasa de unos pocos ciclos de reloj a unos cientos.
     
    Nota: Las funciones inb y outb empleadas en los ejemplos de arriba son macros definidas con el header
    #include <asm/io.h>
    Solo están disponibles cuando no se compila con información para depuración. Es decir, que no podemos compilar estos programas con la opción -g para usar un debugger. En cambio tendremos que usar la opcion de compilación con optimización (-O).


    El fichero /home/soitrpr/unix/ioport.c muestra un ejemplo de uso de ioperm y de las funciones inb y outb para generar un pulso cuadrado en un bit del puerto paralelo del PC. Se puede compilar con la linea de comandos:
    $ cc -O -o ioport ioport.c
    generando el ejecutable ioport.


    © 1999 Guillermo Pérez Trabado
    Departamento de Arquitectura de Computadores
    Universidad de Málaga