Linux Devices Drivers Desarrollo de un char deviceafurfaro/Clases/TDIII/linuxdrivers.pdf ·...

38
Prerequisitos Primer Ejemplo Registro y par´ ametros Script de Instalaci ´ on, N o mayor Poniendo al proceso a dormir Manejando Interrupciones Linux Devices Drivers Desarrollo de un char device Alejandro Furfaro Noviembre 2010 Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

Transcript of Linux Devices Drivers Desarrollo de un char deviceafurfaro/Clases/TDIII/linuxdrivers.pdf ·...

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Linux Devices DriversDesarrollo de un char device

Alejandro Furfaro

Noviembre 2010

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Agenda

1 Prerequisitos.

2 Primer Ejemplo.

3 Registro y funcionalidades.

4 Script de Instalacion, No mayor

5 Poniendo al proceso a dormir

6 Manejando Interrupciones

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

¿Que tenemos que instalar antes de empezar?Instalando los headers del kernel¿Que mas?

Linux Headers

Dijimos que un driver es codigo de kernel.En consecuencia, un diver va a invocar funciones internasdel kernel, y utilizara sus esctructuras de datos.Necesitamos contar con las definiciones de los prototiposde estas funciones, y estructuras. ¿Donde encontramosestas definiciones?

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

¿Que tenemos que instalar antes de empezar?Instalando los headers del kernel¿Que mas?

Linux headers

En los headers del sistema operativoLos fuentes del Sistema Operativo proporcionan en susarchivos headers, las definiciones de prototipos de funciones yde estructuras de datos, que emplea el kernel. Y son las queempleara nuestro device driver. Por lo tanto hay que instalar losheaders.

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

¿Que tenemos que instalar antes de empezar?Instalando los headers del kernel¿Que mas?

Version exacta

Para saber exactamente que version de kernel tenemosinstalada en el sistema, el comando uname es la respuesta:˜ $ uname −r2.6.26−1−686˜ $

Usando la propiedad de encerrar un comando entre ‘ ‘˜ $ sudo apt−get i n s t a l l l i nux−headers− ‘uname −r ‘

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

¿Que tenemos que instalar antes de empezar?Instalando los headers del kernel¿Que mas?

Ya tenemos los headers ¿y ahora?

˜ $ sudo apt−get i n s t a l l l i nux−manual

E instalamos las man pages del kernel, en dondeecontraremos las funciones internas del kernel mas comunes.Mucas otras habra que rebuscar en otros medios.˜ $ sudo apt−get i n s t a l l kernel−i n t e r n a l−guide

Alguna doc, adicional del kernel.˜ $ sudo apt−get i n s t a l l ‘ ‘ L inux Device Dr ivers−3er . Ed ic i on−Alessandro Rubini− Ed . O’ r r e i l y ’ ’

:) Faltarıa que lo incluyan en el repo. “El libro” para aprender aprogramar drivers.

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Tiny exampleManos a la obra

includes y macros

#include < l i n u x / module . h>#include < l i n u x / i n i t . h>#include < l i n u x / ke rne l . h> /∗ p r i n t k ( ) ∗ //∗ ∗∗Macro que dec lara e l au tor de l modulo∗ ∗ /

MODULE AUTHOR( ” Fulano−de−t a l ” ) ;/∗ ∗∗Macro que dec lara e l t i p o de l i c e n c i a de l modulo .∗ ∗ /MODULE LICENSE( ” Dual BSD/GPL” ) ;

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Tiny exampleManos a la obra

init y exit (muy basicos)

i n t h e l l o i n i t ( void ){

p r i n t k (KERN INFO ” Hola mundo\n ” ) ;return 0;

}

void h e l l o e x i t ( void ){

p r i n t k (KERN INFO ”Chau mundo ! ! ! \ n ” ) ;}

m o d u l e i n i t ( h e l l o i n i t ) ;modu le ex i t ( h e l l o e x i t ) ;

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Tiny exampleManos a la obra

Makefile

obj−m := h e l l o . oKERNELDIR ?= / l i b / modules / $ ( s h e l l uname −r ) / b u i l dPWD := $ ( s h e l l pwd)

d e f a u l t :$ (MAKE) −C $ (KERNELDIR) M=$ (PWD) modules

clean :rm h e l l o .mod. c h e l l o . o modules . orderrm h e l l o . ko h e l l o .mod. o Module . symvers

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Tiny exampleManos a la obra

compilando...

1 Necesitamos solamente los archivos hello.c anterior yMakefile.˜ / DeviceDriverK2 . 6 / he l l o$ l s −l st o t a l 84 −rw−r−−r−− 1 a le jandro a le jandro 589 oct 19 2009 h e l l o . c4 −rw−r−−r−− 1 a le jandro a le jandro 246 nov 2 15:33 Makef i le˜ / DeviceDriverK2 . 6 / he l l o$

2 ¿Compilamos?˜ / DeviceDriverK2 . 6 / he l l o$ sudo make[ sudo ] password for a le jandro :make −C / l i b / modules/2.6.26−1−686/ b u i l d M=/home / a le jandro / DeviceDriverK2 . 6 / h e l l o modulesmake [ 1 ] : se ingresa a l d i r e c t o r i o ‘ / usr / s rc / l i nux−headers−2.6.26−1−686’

CC [M] / home / a le jandro / DeviceDriverK2 . 6 / h e l l o / h e l l o . oBu i l d i ng modules , stage 2.MODPOST 1 modulesCC / home / a le jandro / DeviceDriverK2 . 6 / h e l l o / h e l l o .mod. oLD [M] / home / a le jandro / DeviceDriverK2 .6 /2009 / h e l l o / h e l l o . ko

make [ 1 ] : se sa le de l d i r e c t o r i o ‘ / usr / s rc / l i nux−headers−2.6.26−1−686’˜ / DeviceDriverK2 . 6 / he l l o$

3 Listar el directorio y ver los archivos que se generaron.Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Registrando el dispositivoCapabilitiesPasando parametros al driver

haciendo cosas utiles en init y exit

i n t h e l l o i n i t ( void ){

i n t r e s u l t ;r e s u l t = r e g i s t e r c h r d e v ( he l lo ma jo r , ” he l l o2 ” ,& h e l l o f o p s ) ;p r i n t k (KERN INFO ” he l l o2 : e l numero mayor es %d\n ” , r e s u l t ) ;he l l o ma jo r = r e s u l t ;return 0;

}void h e l l o e x i t ( void ){

unreg i s te r ch rdev ( he l lo ma jo r , ” he l l o2 ” ) ;}m o d u l e i n i t ( h e l l o i n i t ) ;modu le ex i t ( h e l l o e x i t ) ;

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Registrando el dispositivoCapabilitiesPasando parametros al driver

variables importantes

/∗ ∗∗ v a r i a b l e donde se almacena e l Major number de l modulo .∗ Se i n i c i a l i z a a 0 para ped i r un numero a l sistema .∗ /

i n t he l l o ma jo r = 0 ;

/∗ ∗∗ Declarac i on de las func iones que usara e l d r i v e r∗ cuando sea accedido .∗ /

struct f i l e o p e r a t i o n s h e l l o f o p s = {. open = hel lo open ,. re lease = he l l o re l ease ,. owner = THIS MODULE} ;

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Registrando el dispositivoCapabilitiesPasando parametros al driver

Manejando funciones.../∗ Esta func i on es l a que contes ta r a l os l lamados a l a func i on∗ open ( char ∗ , i n t ) cuyo pr imer parametro corresponda a l nodo∗ en / dev cuyo major number corresponda a l de este d r i v e r ∗ /

i n t he l lo open ( struct inode ∗ inode , struct f i l e ∗ f i l p ){

p r i n t k (KERN INFO ” Hel lo2 : Apertura de Archivo\n ” ) ;return 0;

}

/∗ Esta func i on es l a que contes ta r a l os l lamados a l a func i on∗ open ( char ∗ , i n t ) cuyo pr imer parametro corresponda a l nodo∗ en / dev cuyo major number corresponda a l de este d r i v e r ∗ /

i n t h e l l o r e l e a s e ( struct inode ∗ inode , struct f i l e ∗ f i l p ){

return 0;}

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Registrando el dispositivoCapabilitiesPasando parametros al driver

Como se hace...

Se pasan por lınea de comandos al instalar el driverinsmod . / he l l o2 . ko he l l o ma jo r =355

Se reciben en el codigo del modulo en una variable/∗ ∗∗ Declarac i on de parametro de l modulo , \ r e f td3 major .∗ Puede ser seteado por e l user a l hacer e l insmod .∗ ∗ /

module param ( he l lo ma jo r , int , 0 ) ;

module param tiene tres argumentos: nombre, tipo de dato, y lamascara de permisos con la que se creara la entrada en sysfsEl tipo de dato es bool, asociado a una variable que debe ser detipo int, (evaluada como TRUE o FALSE), o invbool queinvierte el valor de la variable, o charp, para manejar strings.luego los tipos clasicos del C: int, long, short, uint,ulong, ushort

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Automatizando la instalacionComo obtenemos en No Mayor

Alojando dinamicamente el No Mayor

Al fuente hello3.c y a Makefile, en este tercer ejemplosumamos un shell script para obtener dinamicamente elNumero Mayor, y con el crear automaticamente los nodosnecesarios en el /dev.˜ / DeviceDriverK2 . 6 / d r i ve r3$ cat h e l l o 3 d r i v e r . i n i t

En particular importan las lıneas 59 a 63 del script (activarlasen el editor que esten usando!!)i f $INSMOD $devpath $OPTIONS; then

MAJOR= ‘awk ” \\$2==\ ”$DEVICE\ ” { p r i n t \\$1} ” / proc / devices ‘remove f i l es $FILESc r e a t e f i l e s $FILES

else

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Automatizando la instalacionComo obtenemos en No Mayor

Alojando dinamicamente el No Mayor

Al fuente hello3.c y a Makefile, en este tercer ejemplosumamos un shell script para obtener dinamicamente elNumero Mayor, y con el crear automaticamente los nodosnecesarios en el /dev.˜ / DeviceDriverK2 . 6 / d r i ve r3$ cat h e l l o 3 d r i v e r . i n i t

En particular importan las lıneas 59 a 63 del script (activarlasen el editor que esten usando!!)i f $INSMOD $devpath $OPTIONS; then

MAJOR= ‘awk ” \\$2==\ ”$DEVICE\ ” { p r i n t \\$1} ” / proc / devices ‘remove f i l es $FILESc r e a t e f i l e s $FILES

else

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Automatizando la instalacionComo obtenemos en No Mayor

Alojando dinamicamente el No Mayor

Al fuente hello3.c y a Makefile, en este tercer ejemplosumamos un shell script para obtener dinamicamente elNumero Mayor, y con el crear automaticamente los nodosnecesarios en el /dev.˜ / DeviceDriverK2 . 6 / d r i ve r3$ cat h e l l o 3 d r i v e r . i n i t

En particular importan las lıneas 59 a 63 del script (activarlasen el editor que esten usando!!)i f $INSMOD $devpath $OPTIONS; then

MAJOR= ‘awk ” \\$2==\ ”$DEVICE\ ” { p r i n t \\$1} ” / proc / devices ‘remove f i l es $FILESc r e a t e f i l e s $FILES

else

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Automatizando la instalacionComo obtenemos en No Mayor

awk... mucho mas que un comando

La base es el potente awk (o gawk en Linux, por GNU awk).Veamos un ejemplo desde el shell:˜ / $ awk ” \$2==\ ” sound\ ” { p r i n t \$1} ” / proc / devices14˜ / $ l s −l as / dev / dsp0 crw−rw−−−− 1 roo t audio 14 , 3 nov 8 13:58 / dev / dsp˜ / $

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

el metodo que pone el proceso a dormir es,tıpicamente, read

Primer paso: agregamos los metodos en File Operations.struct f i l e o p e r a t i o n s h e l l o f o p s = {

. read = he l lo read , / / read ( ) es bloqueante .

. open = hel lo open ,

. re lease = he l l o re l ease ,

. owner = THIS MODULE} ;

Segundo paso: Escribimos la funcion read.s s i z e t he l l o read ( struct f i l e ∗ f i l p , char use r ∗buf ,

s i z e t count , l o f f t ∗ f pos ){i n t r e s u l t ;r e s u l t =copy to user ( buf , kbu f fe r , s t r l e n ( k b u f f e r ) ) ;p r i n t k (KERN INFO ” he l l o4 : d i s p o s i t i v o l e ı do con numero menor

%d\n ” , im inor ( f i l p −>p r i v a t e d a t a ) ) ;return s t r l e n ( k b u f f e r ) ;

}Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

el metodo que pone el proceso a dormir es,tıpicamente, read

Primer paso: agregamos los metodos en File Operations.struct f i l e o p e r a t i o n s h e l l o f o p s = {

. read = he l lo read , / / read ( ) es bloqueante .

. open = hel lo open ,

. re lease = he l l o re l ease ,

. owner = THIS MODULE} ;

Segundo paso: Escribimos la funcion read.s s i z e t he l l o read ( struct f i l e ∗ f i l p , char use r ∗buf ,

s i z e t count , l o f f t ∗ f pos ){i n t r e s u l t ;r e s u l t =copy to user ( buf , kbu f fe r , s t r l e n ( k b u f f e r ) ) ;p r i n t k (KERN INFO ” he l l o4 : d i s p o s i t i v o l e ı do con numero menor

%d\n ” , im inor ( f i l p −>p r i v a t e d a t a ) ) ;return s t r l e n ( k b u f f e r ) ;

}Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

el metodo que pone el proceso a dormir es,tıpicamente, read

Primer paso: agregamos los metodos en File Operations.struct f i l e o p e r a t i o n s h e l l o f o p s = {

. read = he l lo read , / / read ( ) es bloqueante .

. open = hel lo open ,

. re lease = he l l o re l ease ,

. owner = THIS MODULE} ;

Segundo paso: Escribimos la funcion read.s s i z e t he l l o read ( struct f i l e ∗ f i l p , char use r ∗buf ,

s i z e t count , l o f f t ∗ f pos ){i n t r e s u l t ;r e s u l t =copy to user ( buf , kbu f fe r , s t r l e n ( k b u f f e r ) ) ;p r i n t k (KERN INFO ” he l l o4 : d i s p o s i t i v o l e ı do con numero menor

%d\n ” , im inor ( f i l p −>p r i v a t e d a t a ) ) ;return s t r l e n ( k b u f f e r ) ;

}Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

copy to user y copy from user

A copy from user la utilizaremos cuando nos ocupemos delmetodo write

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

Hace falta retocar el resto

Tercer paso: en el metodo open (), conseguimos la referenciaa filp->private data./∗ ∗∗ puntero a b u f f e r de cada device .∗ ∗ /

char ∗ k b u f f e r ;i n t he l lo open ( struct inode ∗ inode , struct f i l e ∗ f i l p ) {

unsigned i n t minor number = im inor ( inode ) ;p r i n t k (KERN INFO ” he l l o4 : device %d opened\n ” , minor number ) ;/∗ ∗∗ Para que los o t ros metodos puedan obtener e l numero menor ,∗ l o guardo en e l campo p r i v a t e d a t a de l a e s t r u c t u r a f i l e .∗ ∗ /f i l p −>p r i v a t e d a t a = inode ;k b u f f e r = kmal loc ( s t r l e n ( INIT STRING ) , GFP KERNEL ) ;memcpy ( ( char ∗ ) kbu f fe r , INIT STRING , s t r l e n ( INIT STRING ) + 1 ) ;return 0;

}Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

Semaforos del kernel

Primero instanciamos la estructura semaphore que define un semaforodel kernel, e inicializamos el semaforo en el metodo open().

/∗ ∗∗ puntero a b u f f e r de cada device .∗ ∗ /

char ∗ k b u f f e r ;/∗ ∗∗ Semaforos para s i n c r o n i z a r e l acceso a l b u f f e r .∗ ∗ /

struct semaphore sem;i n t he l lo open ( struct inode ∗ inode , struct f i l e ∗ f i l p ) {

unsigned i n t minor number = im inor ( inode ) ;p r i n t k (KERN INFO ” he l l o5 : device %d opened\n ” , minor number ) ;k b u f f e r =NULL ;sema in i t (&sem , 1 ) ; / / l i be rado , para c o n t r o l de acceso a k b u f f e rreturn 0;

}

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

Tomando el semaforo

Una vez creado lo manejamos desde el metodo read (). Usamos lafamilia de funciones down () del kernel

s s i z e t he l l o read ( struct f i l e ∗ f i l p , char use r ∗buf ,s i z e t count , l o f f t ∗ f pos )

{i f ( ! d o w n i n t e r r u p t i b l e (&sem ) ){

k b u f f e r = kmal loc ( s t r l e n ( INIT STRING )+1 , GFP KERNEL ) ;memcpy ( ( char ∗ ) kbu f fe r , INIT STRING , s t r l e n ( INIT STRING ) + 1 ) ;/∗ copio e l contenido a l b u f f e r de l usuar io ∗ /i f ( copy to user ( buf , kbu f fe r , s t r l e n ( k b u f f e r ) ) ){

up(&sem ) ;p r i n t k (KERN INFO ” he l l o5 : E r ro r de Lectura en copy to user \n ” ) ;return −EFAULT;

}

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

liberando el semaforo

La funcion de liberacion de un semaforo es: voidup(struct semaphore *sem);

else{

up(&sem ) ;p r i n t k (KERN INFO ” he l l o5 : Lectura ex i tosa , %d bytes \n ” , s t r l e n ( k b u f f e r ) ) ;return s t r l e n ( k b u f f e r ) ;

}}else{

p r i n t k (KERN INFO ” he l l o5 :Lectura con e r r o r toma de semaforo \n ” ) ;

return −EFAULT;}

}

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

funciones down

En el mundo Linux, la funcion P se llama down (o algunavariedad de ese nombre).‘‘down’’ se refiere al hecho que su operacion consisteen:

decrementar el valor del semaforo,por lo general pone a “dormir” al proceso que invoco almetodo del modulo, hasta que el semaforo se libere,permitir el acceso a un recurso de manera segura

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

funciones down

Hay tres variantes o versiones de downvoid down(struct semaphore *sem);int down interruptible(struct semaphore*sem);int down trylock(struct semaphore *sem);

down decrementa el valor del semaforo y espera lo queresulte necesario.down interruptible hace lo mismo pero la operaciones interrumpible.down trylock nunca duerme. Si el semaforo noesta disponible al momento de la llamada, retornaimmediatamente un valor no nulo.

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

Versiones Interrumpibles vs. No Interrumpibles

..

Debemos siempre tratar de utilizar la version interrumpiblede cualquier llamada para dormir un proceso, ya que permiteque desde el espacio de usuario, el proceso que esta dor-mido esperando (por un semaforo en este caso), pueda serinterrumpido por el usuario.

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

Versiones Interrumpibles vs. No Interrumpibles

Regla generalNo usar operaciones No interrumpibles, a menos que seaabsolutamente necesario. Las operaciones No Interrumpiblesson una excelente forma de crear procesos que no puedan serterminados de ninguna manera posible (aparecen en estado Dpor Dreaded en la salida de ps).El uso de down interruptible requiere algunasprecaucionea adicionales, sin embargo, al ser interrumpida laoperacion, la funcion retorna un valor no nulo, y el procesollamante no mantiene el semaforo.Por lo tanto, el uso correcto de down interruptible requieresiempre chequear el valor retornado, y responder de maneraacorde al proceso invocante.

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

Durmiendo y despertando al escribir

Antes de mirar este tramo de codigo, conviene abrirhello5.c y mirar la definicion de file operations ;)

s s i z e t h e l l o w r i t e ( struct f i l e ∗ f i l p , const char use r ∗buf ,s i z e t count , l o f f t ∗ f pos ) {

i f ( ! d o w n i n t e r r u p t i b l e (&sem ) ) {k f ree ( k b u f f e r ) ; /∗ destruyo e l b u f f e r ac tua l ∗ // / p ido ( count ) bytes , espec i f i cados por e l usuar io .k b u f f e r = kmal loc ( count , GFP KERNEL ) ;i f ( ! k b u f f e r ) {

/∗ s i hubo un er ro r , devuelvo −ENONMEM∗ /p r i n t k (KERN INFO ” he l l o5 : E s c r i t u r a con e r r o r acceso a memoria \n ” ) ;k b u f f e r = NULL ;up(&sem ) ;return −ENOMEM;}

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Antes que nada...recursos del kernelMandando a dormir al proceso desde el kernelManejando eficientemente los bloqueos a procesosEscritura del dispositivo

Durmiendo y despertando al escribir/∗ copio a k b u f f e r e l buf de l usuar io ,∗ s i hay e r r o r devuelvo −EFAULT ∗ /i f ( copy from user ( kbu f fe r , buf , count ) ) {

p r i n t k (KERN INFO ” he l l o5 : E s c r i t u r a con e r r o r en copy from user \n ” ) ;k f ree ( k b u f f e r ) ;up(&sem ) ;return −EFAULT;}

else {p r i n t k (KERN INFO ” he l l o5 : E s c r i t u r a kmal loc para %d bytes \n ” , count ) ;p r i n t k (KERN INFO ” he l l o5 : %s \n ” , k b u f f e r ) ;up(&sem ) ;return count ;}

}else {

p r i n t k (KERN INFO ” he l l o5 : E s c r i t u r a con e r r o r toma de semaforo \n ” ) ;return −EFAULT;}

return 0;} Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Para usar una IRQ se la pedimos al kernelel handlerbloquenado procesos

¿Donde se pide?

Abrir holla6.c e ir al metodo open ().

i n t he l lo open ( struct inode ∗ inode , struct f i l e ∗ f i l p ) {unsigned i n t minor number = im inor ( inode ) ;p r i n t k (KERN INFO ” he l l o6 : device %d opened\n ” , minor number ) ;k b u f f e r =NULL ;sema in i t (&sem , 0 ) ; / / tomado , para c o n t r o l de acceso a k b u f f e rt i c k c o u n t e r = TICK RELOAD ;p r i n t k ( KERN INFO ” he l l o6 : Opening i r q device\n ” ) ;i f ( r e q u e s t i r q ( IRQ USED, &my handler , IRQF SHARED, ” he l l o6 ” , ” ufa ” ) )

return −EBUSY;p r i n t k ( KERN INFO ” he l l o6 : i r q t i c k c o u n t e r = %d\n ” , t i c k c o u n t e r ) ;p r i n t k ( KERN INFO ” he l l o6 : Salgo de l Opening i r q device\n ” ) ;return 0;

}

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Para usar una IRQ se la pedimos al kernelel handlerbloquenado procesos

que hacemos en el hadnler?

Accedemos al hardware, ydespertamos al proceso que ha sido bloqueado cuandosolicito los datos disponibles

i r q r e t u r n t my handler ( i n t i r q , void ∗dev id ) / / , s t r u c t p t regs ∗ regs ){

t i c k c o u n t e r −−;p r i n t k (KERN INFO ” he l l o6 : my handler con t i c k c o u n t e r= %d \n ” , t i c k c o u n t e r ) ;i f ( ! t i c k c o u n t e r ) {

p r i n t k (KERN INFO ” he l l o6 : t i c k c o u n t e r =0 l i b e r o sem \n ” ) ;t i c k c o u n t e r = TICK RELOAD ;up(&sem ) ;w a k e u p i n t e r r u p t i b l e (& td ig wa i tqueue ) ;}

return IRQ HANDLED;}

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Para usar una IRQ se la pedimos al kernelel handlerbloquenado procesos

No lo habıamos hecho con semaforos? que mas?

Utilizamos colas de mensaje/∗ ∗∗ Waitqueue que usaremos en e l modo de espera .∗ /

DECLARE WAIT QUEUE HEAD( td ig wa i tqueue ) ;

Cuando el proceso requiere los datos (invoca el metodoread () de nuestro modulo), lo bloqueamos hasta que losdatos esten disponibles, utilizando otras funciones algomas poderosas que los semafoross s i z e t he l l o read ( struct f i l e ∗ f i l p , char use r ∗buf , s i z e t count , l o f f t ∗ f pos ) {

p r i n t k (KERN INFO ” he l l o6 : Lectura ingreso\n ” ) ;i f ( ! d o w n i n t e r r u p t i b l e (&sem ) ){

k b u f f e r = kmal loc ( s t r l e n ( INIT STRING )+1 , GFP KERNEL ) ;memcpy( ( char ∗ ) kbu f fe r , INIT STRING , s t r l e n ( INIT STRING ) + 1 ) ;

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Para usar una IRQ se la pedimos al kernelel handlerbloquenado procesos

No lo habıamos hecho con semaforos? que mas?

Utilizamos colas de mensaje/∗ ∗∗ Waitqueue que usaremos en e l modo de espera .∗ /

DECLARE WAIT QUEUE HEAD( td ig wa i tqueue ) ;

Cuando el proceso requiere los datos (invoca el metodoread () de nuestro modulo), lo bloqueamos hasta que losdatos esten disponibles, utilizando otras funciones algomas poderosas que los semafoross s i z e t he l l o read ( struct f i l e ∗ f i l p , char use r ∗buf , s i z e t count , l o f f t ∗ f pos ) {

p r i n t k (KERN INFO ” he l l o6 : Lectura ingreso\n ” ) ;i f ( ! d o w n i n t e r r u p t i b l e (&sem ) ){

k b u f f e r = kmal loc ( s t r l e n ( INIT STRING )+1 , GFP KERNEL ) ;memcpy( ( char ∗ ) kbu f fe r , INIT STRING , s t r l e n ( INIT STRING ) + 1 ) ;

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Para usar una IRQ se la pedimos al kernelel handlerbloquenado procesos

No lo habıamos hecho con semaforos? que mas?

Utilizamos colas de mensaje/∗ ∗∗ Waitqueue que usaremos en e l modo de espera .∗ /

DECLARE WAIT QUEUE HEAD( td ig wa i tqueue ) ;

Cuando el proceso requiere los datos (invoca el metodoread () de nuestro modulo), lo bloqueamos hasta que losdatos esten disponibles, utilizando otras funciones algomas poderosas que los semafoross s i z e t he l l o read ( struct f i l e ∗ f i l p , char use r ∗buf , s i z e t count , l o f f t ∗ f pos ) {

p r i n t k (KERN INFO ” he l l o6 : Lectura ingreso\n ” ) ;i f ( ! d o w n i n t e r r u p t i b l e (&sem ) ){

k b u f f e r = kmal loc ( s t r l e n ( INIT STRING )+1 , GFP KERNEL ) ;memcpy( ( char ∗ ) kbu f fe r , INIT STRING , s t r l e n ( INIT STRING ) + 1 ) ;

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device

PrerequisitosPrimer Ejemplo

Registro y parametrosScript de Instalacion, No mayor

Poniendo al proceso a dormirManejando Interrupciones

Para usar una IRQ se la pedimos al kernelel handlerbloquenado procesos

No lo habıamos hecho con semaforos? que mas?i f ( copy to user ( buf , kbu f fe r , s t r l e n ( k b u f f e r ) ) ) /∗ copio e l contenido a l b u f f e r de l usuar io ∗ /{

up(&sem ) ;p r i n t k (KERN INFO ” he l l o6 : Lectura con e r r o r en copy to user \n ” ) ;return −EFAULT;}

else{

/ / up(&sem ) ;p r i n t k (KERN INFO ” he l l o6 : Lectura ex i tosa , %d bytes \n ” , s t r l e n ( k b u f f e r ) ) ;return s t r l e n ( k b u f f e r ) ;}

}else{p r i n t k (KERN INFO ” he l l o6 : Lectura con e r r o r toma de semaforo \n ” ) ;return −EFAULT;}

}

Alejandro Furfaro Linux Devices DriversDesarrollo de un char device