Descargar el tutorial completo

Anuncio
Drivers para Linux
embebido
Martin Ribelotta
www.emtech.com.ar
Temario
Drivers en Linux
Hola System-land Mundo!
Recursos del Kernel
IO-MEM, Direcciones Virtuales vs Reales
Comunicándose con el user-land
Ejemplo practico: Chalten amba_dev
Drivers en Linux
User-Land
App-0
App-1
Socket
Video4Linux
USB
driver
Driver
Lib
Daemon
System-Land
FireWire
driver
WebCam
App-3
App-2
Driver
Lib
Kernel Trap Gates (Syscalls)
Virtual
File System
SATA USB
driver driver
Disco
Rígido
GEM
Kernel
Modesetting
Framebuffer
Video
Placa de
Audio
ALSA
Hola 'system-land'
Mundo!
Codigo minimo de nuestro driver
hola_kernel.c
#include <linux/module.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
static int __init hola_init(void) {
static int __init hola_init(void) {
printk("Hola system-land!.\n");
printk("Hola system-land!.\n");
return 0; // 0 Ok, No 0 fallo
return 0; // 0 Ok, No 0 fallo
}
}
static void __exit hola_done(void) {
static void __exit hola_done(void) {
printk("Chau system-land!\n");
printk("Chau system-land!\n");
}
}
module_init(hola_init);
module_init(hola_init);
module_exit(hola_done);
module_exit(hola_done);
Hola 'system-land'
Mundo!
Makefile
obj-m += hola_kernel.o
obj-m += hola_kernel.o
all:
all:
clean:
clean:
make -C /lib/modules/$(KDIR)/build M=$(PWD) modules
make -C /lib/modules/$(KDIR)/build M=$(PWD) modules
make -C /lib/modules/$(KDIR)/build M=$(PWD) clean
make -C /lib/modules/$(KDIR)/build M=$(PWD) clean
Hola 'system-land'
Mundo!
Así se compila:
$~/:
$~/: make
make KDIR=/home/devel/kernel-2.6.37-chalten
KDIR=/home/devel/kernel-2.6.37-chalten
Hola 'system-land'
Mundo!
Así se compila:
$~/:
$~/: make
make KDIR=/home/devel/kernel-2.6.37-chalten
KDIR=/home/devel/kernel-2.6.37-chalten
!Debemos tener los headers
del nucleo a mano!
O los fuentes directamente ;-)
Hola 'system-land'
Mundo!
Copiamos al target (nfs o ssh)
devel@host$~/:
devel@host$~/: scp
scp hola_kernel.ko
hola_kernel.ko user@target:/root
user@target:/root
Hola 'system-land'
Mundo!
Copiamos al target (nfs o ssh)
devel@host$~/:
devel@host$~/: scp
scp hola_kernel.ko
hola_kernel.ko user@target:/root
user@target:/root
Y por fin ejecutamos (en el target)
root@target
root@target $~/:
$~/: insmod
insmod /root/hola_kernel.ko
/root/hola_kernel.ko
Hola 'system-land'
Mundo!
Copiamos al target (nfs o ssh)
devel@host$~/:
devel@host$~/: scp
scp hola_kernel.ko
hola_kernel.ko user@target:/root
user@target:/root
Y por fin ejecutamos (en el target)
root@target
root@target $~/:
$~/: insmod
insmod /root/hola_kernel.ko
/root/hola_kernel.ko
Ahora el log nos dice que el modulo está cargado
root@target $~/: dmesg | tail -n 1
[66668.270161] Hola system-land!.
Hola 'system-land'
Mundo!
Cuando queramos removerlo:
root@target
root@target $~/:
$~/: rmmod
rmmod hola_kernel
hola_kernel
Hola 'system-land'
Mundo!
Cuando queramos removerlo:
root@target
root@target $~/:
$~/: rmmod
rmmod hola_kernel
hola_kernel
Al revisar el log y vemos que
se descargó correctamente
root@target $~/: dmesg | tail -n 2
[66668.270161] Hola system-land!.
[66679.457397] Chau system-land!
Recursos del Kernel
Interface para “char devices”
Interface para “block devices”
Memoria dinámica en el núcleo
Threads del núcleo
Manejo de direcciones virtuales/reales
Acceso a buses (pci, usb, scsi, etc.)
Abstracción de DMA
Acceso a userland (/proc, /dev, /sysfs)
Recursos del Kernel
Interface para “char devices”
Interface para “block devices”
Memoria dinámica en el núcleo
Threads del núcleo
Manejo de direcciones virtuales/reales
Acceso a buses (pci, usb, scsi, etc.)
Abstracción de DMA
Acceso a userland (/proc, /dev, /sysfs)
IO-MEM, Direcciones
Virtuales vs Reales
Repaso a Memoria Virtual
Bus del sistema
MEM
CPU
Dirección
logica
TLB
Page
table
I/O
Periférico
Dirección
fisica
IO-MEM, Direcciones
Virtuales vs Reales
Pasos para acceder a un area de memoria
Adqurir la reguion para uso privado
memreg
memreg == request_mem_region(STARTADDR,
request_mem_region(STARTADDR, SIZE,
SIZE, "name");
"name");
IO-MEM, Direcciones
Virtuales vs Reales
Pasos para acceder a un area de memoria
Adqurir la reguion para uso privado
memreg
memreg == request_mem_region(STARTADDR,
request_mem_region(STARTADDR, SIZE,
SIZE, "name");
"name");
Mapear las direcciónes fisicas al area virtual
void
void *memptr
*memptr == ioremap(STARTADDR,
ioremap(STARTADDR, SIZE);
SIZE);
IO-MEM, Direcciones
Virtuales vs Reales
Pasos para acceder a un area de memoria
Adqurir la reguion para uso privado
memreg
memreg == request_mem_region(STARTADDR,
request_mem_region(STARTADDR, SIZE,
SIZE, "name");
"name");
Mapear las direcciónes fisicas al area virtual
void
void *memptr
*memptr == ioremap(STARTADDR,
ioremap(STARTADDR, SIZE);
SIZE);
STARTADDR debe estar alineado a 4K
SIZE esta dado en bloques de 4K
IO-MEM, Direcciones
Virtuales vs Reales
Ahora accedemos como si fuera un
area adquirida com malloc o similar
void
void *memptr
*memptr
TLB
Primitivas
Primitivasde
delectura
lectura
unsigned
unsigned int
int ioread8(void
ioread8(void *addr);
*addr);
unsigned
int
ioread16(void
unsigned int ioread16(void *addr);
*addr);
unsigned
int
ioread32(void
*addr);
unsigned int ioread32(void *addr);
IO-MEM, Direcciones
Virtuales vs Reales
Ahora accedemos como si fuera un
area adquirida com malloc o similar
void
void *memptr
*memptr
TLB
Primitivas
Primitivasde
deescritura
escritura
void
void iowrite8(u8
iowrite8(u8 value,
value, void
void *addr);
*addr);
void
iowrite16(u16
value,
void
void iowrite16(u16 value, void *addr);
*addr);
void
iowrite32(u32
value,
void
*addr);
void iowrite32(u32 value, void *addr);
IO-MEM, Direcciones
Virtuales vs Reales
Al terminar de usar las cosas: Limpiar!
Desmapeamos la memoria fisica
iounmap(memptr);
iounmap(memptr);
Desbloqueamos la región
release_mem_region(STARTADDR,
release_mem_region(STARTADDR, SIZE);
SIZE);
Comunicándose con el
user-land
Directorio /dev tipico
dev_t device; // major/minor
Comunicándose con el
user-land
Necesitamos:
#include <linux/fs.h>
#include <linux/uaccess.h>
Comunicándose con el
user-land
Creamos un dev_t
dev = register_chrdev(0, “nombre_sugerido”, &fops);
Número mayor asignado automáticamente
struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = func_llseek,
.read = func_read,
.write = func_write,
.ioctl = func_ioctl,
.open = func_open,
.release = func_release,
};
Comunicándose con el
user-land
Ejemplos de prototipos de callbacks
ssize_t read(struct file *filp, char __user *buff,
size_t count, loff_t *offp);
ssize_t write(struct file *filp, const char __user *buff,
size_t count, loff_t *offp);
Comunicándose con el
user-land
Tus aimgas son:
unsigned long copy_to_user(void __user *to,
const void *from, unsigned long count);
unsigned long copy_from_user(void *to,
const void __user *from, unsigned long count);
Comunicándose con el
user-land
Comunicándose con el
user-land
Al remover el modulo:
unregister_chrdev(MAJOR(device), “nombre”);
Comunicándose con el
user-land
Referencias:
Linux Device Drivers 3rd edition
http://lwn.net/Kernel/LDD3/
Kernel API
http://www.gnugeneration.com/mirrors/kernel-api/book1.html
Contacto
EmTech
[email protected]
www.emtech.com.ar
Descargar