introdução ao desenvolvimento com linux: módulos do kernel · compilando o kernel linux...
Post on 27-Jul-2020
16 Views
Preview:
TRANSCRIPT
16 de Jul de 2008 1Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Introdução ao Desenvolvimentocom LINUX: Módulos do Kernel
Lucas Wanner, Antônio Augusto Fröhlichguto@lisha.ufsc.br
http://www.lisha.ufsc.br/~guto
16 de Jul de 2008
16 de Jul de 2008 2Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Desmotivação para Desenvolver Software de Sistema Já temos Windows e Unix e MacOS!
● Que são sistemas multiusuário, multitarefa com interfaces gráficas legais que nos permitem acessar a Web...
● E fazem uso de modernas técnicas de engenharia de software, como programação estruturada!
● E há inúmeras histórias de SOs fracassados ... E temos ótimos padrões de SO!
● APIs fortes como Posix e Win32 ● Hardware se fixando na novíssima arquitetura IA32● Como disse Pike: pesquisa em SO é irrelevante!
16 de Jul de 2008 3Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Motivação para Desenvolver Software de Sistema
Where are the processors?(Tennenhouse, CACM 43(5):44)
interactive2%
robots6%
vehicles12%
embedded80%
8bit63%
16bit12%
>= 32bit3%
4bit22%
Sistemas de propósito geral● Prontos para o que der e vier
●Qualquer aplicação● Muitos serviços
Sistemas dedicados● Aplicações particulares● Requisitos específicos e
poucos serviços● São a grande MAIORIA!
16 de Jul de 2008 4Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Sistemas Dedicados na Forma de Placas PCI
16 de Jul de 2008 5Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Drivers de dispositivos “Caixa preta” que esconde a interação com o
hardware atrás de uma interface de software comum (API/SPI)
Implementados através de módulos carregáveis no kernel dos UNIXes modernos (e.g. LINUX)
16 de Jul de 2008 6Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Kernel LINUX
16 de Jul de 2008 7Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Kernel LINUX
16 de Jul de 2008 8Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Drivers de dispositivos no LINUX API inspirada em arquivos●Dispositivos representados por pseudo arquivos●Operações típicas de arquivos●Open / Close, Read / Write
Implementados através de módulos carregáveis ou lincados diretamente ao kernel
Categorias● Dispositivos orientados à caractere● Dispositivos orientados a bloco● Dispositivos de rede
16 de Jul de 2008 9Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Pseudo Arquivos deDispositivos de Hardware Por convenção, no diretório /dev Kernel redireciona as operações realizadas nos
pseudo arquivos para os serviços correspondentes do driver do dispositivo
Pseudoarquivos são “amarrados” com os dispositivos através dos números major e minor
16 de Jul de 2008 10Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Pseudo Arquivos deDispositivos de Hardware Número Major
● Identifica o driver (módulo) que deve ser acessado● Número de 8 bits
Número Minor● Identifica o dispositivo (unidade) dentro do contexto do
módulo Exemplo
● Driver IDE: major = 3● Primeira partição do primeiro disco IDE: minor = 1
16 de Jul de 2008 11Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Dispositivos Orientados à Caractere Vistos como fluxos de bytes Operação similar a arquivos comuns
● Exceção: não é possível avançar/retroceder na leitura/escrita (i.e. seek)
Exemplos● /dev/console● /dev/ttyS0
16 de Jul de 2008 12Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Dispositivos orientados a blocos Dispositivos que, durante as operações de I/O,
acessam dados em blocos Dispositivos relacionados com sistemas de
arquivos (e.g. discos) Interface comum com dispositivos orientados à
caractere, mas com semântica distinta● Orientados a blocos● Poder avançar ou retroceder a leitura/escrita
Operações adicionais para suportar sistemas de arquivos
16 de Jul de 2008 13Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Dispositivos de Rede Não se encaixam no esquema de pseudo
arquivos● Geralmente não são um nodo no sistema de arquivos● Integrados a uma pilha de protocolos
Interface de rede genérica● Operações relacionadas a comunicação (e.g. envio de
dados, recepção, manipulação de timeouts, agrupamento de estatísticas)
● Otimizada para integração a pilha TCP/IP
16 de Jul de 2008 14Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Inicialização de Módulos Inicialização
● int init_module(void)●Ponto de entrada do módulo●Chamado na carga (pelo comando insmod)●Registra o módulo no kernel
Finalização● void cleanup_module(void)
●Ponto de saída do módulo●Chamado na finalização (pelo comando rmmod)●Deregistra o módulo
16 de Jul de 2008 15Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Compilação de Módulos Sistema de compilação do Kernel 2.6
● Usa um sistema estendido de “make” com Makefiles simplificados para os drivers:
● Compilando módulos de fora da árvore do kernelmake -C $LINUX_SRC/ M='pwd' modules
● Exige uma árvore configurada do kernel!
$ cat Makefile obj-m := hello.o
16 de Jul de 2008 16Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Compilando o Kernel LINUX Preparação
● Pacotes necessários●sudo apt-get install linux-kernel-devel
fakeroot qt3-dev-tools libqt3-mt-dev (Ubuntu)● Download do código fonte do kernel
●sudo apt-get install linux-source (Ubuntu)●Download disponível em kernel.org
● Criação de diretório para compilação●mkdir ~/src●cd ~/src●tar xjvf /usr/src/linux-source-VERSAO.tar.bz2●cd linux-source-VERSAO
16 de Jul de 2008 17Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Compilando o Kernel LINUX Processo de Compiliação
● Cópia da configuração atual●cp -vi /boot/config-`uname -r` .config
● Configuração●make xconfig
● Compilação●make
● Utilização do kernel compilado (não é necessário para compilar os módulos)●make kernel-image●Atualização da configuração do bootloader
16 de Jul de 2008 18Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Exercício: Hello Module Crie um módulo “Hello World”
● Defina as funções de entrada e saída do módulo:●static int hello_init(void)●static void hello_exit(void)
● No corpo destas funções, imprima uma mensagem●Exemplo: printk(KERN_ALERT "Hello, world.\n");
● Registre as funções com as macros module_init(x) e module_exit(y)
● Crie um módulo “Hello World”● Headers
●#include <linux/init.h>, #include <linux/module.h>
16 de Jul de 2008 19Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Exercício: Hello Module
#include <linux/init.h> #include <linux/module.h>
static int hello_init(void) { printk(KERN_ALERT "Hello, kernel\n"); return 0; }
static void hello_exit(void) { printk(KERN_ALERT "Goodbye, kernel\n"); }
module_init(hello_init); module_exit(hello_exit);
16 de Jul de 2008 20Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Exercício: Hello Module
$ ls hello.c Makefile
$ make -C /lib/modules/`uname -r`/build M=`pwd` modules make: Entering directory `~/src/linux-source-2.6.24' CC [M] /home/lucas/tmp/linux-dev/modules/hello/hello.o Building modules, stage 2. MODPOST 1 modules CC /home/lucas/tmp/linux-dev/modules/hello/hello.mod.o LD [M] /home/lucas/tmp/linux-dev/modules/hello/hello.ko make: Leaving directory `~/src/linux-source-2.6.24'
$ ls hello.c hello.ko hello.mod.c hello.mod.o hello.o Makefile Module.symvers
16 de Jul de 2008 21Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Hello Module: Saída Saída gerada pela biblioteca do kernel (método printk)
Mensagens visíveis através do comando dmesg $ sudo insmod hello.ko
$ dmesg | grep Hello [ 9326.866732] Hello, kernel
$ sudo rmmod hello
$ dmesg | grep Goodbye [ 9356.192375] Goodbye, kernel
16 de Jul de 2008 22Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Hello Module: Trace Quando insmod é chamado, o kernel
● Aloca memória para o módulo● Abre o arquivo que contem o código● Lê o arquivo para a memória alocada● Chama o método init_module()
16 de Jul de 2008 23Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Hello Module: Trace sudo strace insmod hello.ko execve("/sbin/insmod", ["insmod", "hello.ko"], [/* 16 vars */]) = 0 brk(0) = 0x804a000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f0a000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=78806, ...}) = 0 mmap2(NULL, 78806, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7ef6000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/tls/i686/cmov/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\260e\1"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1364388, ...}) = 0 mmap2(NULL, 1369712, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7da7000 mmap2(0xb7ef0000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x149) = 0xb7ef0000 mmap2(0xb7ef3000, 9840, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7ef3000 close(3) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7da6000 set_thread_area({entry_number:-1 -> 6, base_addr:0xb7da66b0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 mprotect(0xb7ef0000, 4096, PROT_READ) = 0 munmap(0xb7ef6000, 78806) = 0 brk(0) = 0x804a000 brk(0x806b000) = 0x806b000 open("hello.ko", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\1\0\3\0\1\0\0\0\0\0\0\0"..., 16384) = 16384 read(3, "\0\0\rM\1$\0\0\0\3#\354@\32\325\31\0\0\rN\1\3\n\0\0\3#"..., 16384) = 16384 read(3, "r_cpu_pages\0___vm86_gs\0io_bitmap"..., 32768) = 17068 read(3, "", 15700) = 0 close(3) = 0 init_module(0x804a018, 49836, "") = 0 exit_group(0) = ? Process 29221 detached
16 de Jul de 2008 24Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Registro de Módulos Liga um módulo à interface de chamadas de
sistema do kernel Registro
● int register_chrdev(unsigned int major, const char *name, struct file_operations *fops)
Deregistro● int unregister_chrdev(unsigned int major, const char *name)
Pseudoarquivo● mknod /dev/devname0 c major minor
16 de Jul de 2008 25Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Parâmetros do Módulo Variáveis globais acessíveis externamente
● Declaradas através da macro MODULE_PARM(variavel, tipo, permissões)
int irq = 10;char * name = “Unknown”;/*declara irq como int */MODULE_PARM(irq, ”i”, 0); /*declara name como string */MODULE_PARM(name, ”s”, 0);
Definidas em tempo de cargainsmod mod.o irq=9 name= ”The Module”
16 de Jul de 2008 26Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Informações do Módulo Declarações do módulo visíveis externamente,
que fornecem informações aos clientes do módulo
MacrosMODULE_LICENSE("GPL");MODULE_AUTHOR("Alguem");MODULE_DESCRIPTION("Este modulo não faz nada");
MODULE_PARM_DESC(irq, "Device IRQ (3/4)"
16 de Jul de 2008 27Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Operações de arquivo
struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); : : };
16 de Jul de 2008 28Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Estrutura arquivo
struct file { struct list_head f_list; struct dentry *f_dentry; struct vfsmount *f_vfsmnt; struct file_operations *f_op; atomic_t f_count; unsigned int f_flags; mode_t f_mode; loff_t f_pos; unsigned long f_reada, f_ramax, f_raend,f_ralen,f_rawin; struct fown_struct f_owner; unsigned int f_uid, f_gid; int f_error; : };
MINOR(f_dentry->d_inode->i_rdev)
16 de Jul de 2008 29Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Contador de Referências Contador de Referências do Módulo
● Contabiliza automaticamente o número de clientes que um módulo tem em um determinado momento
● Evita que um modulo que está sendo utilizado seja descarregado
Manipulado pelas funções:● int try_module_get(&module);● module_put();
16 de Jul de 2008 30Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Gerência de Memória Código do kernel roda no contexto do processo
de usuário que fez a chamada#include <asm/uaccess.h>unsigned long copy_to_user(to, from, count);unsigned long copy_from_user(to, from, count);
Alocação de memória dentro do kernel#include <linux/malloc.h>void *kmalloc(unsigned int size, int priority);void kfree(void *obj);
16 de Jul de 2008 31Antônio Augusto Fröhlich (http://www.lisha.ufsc.br)
Dicas de Programação Não utilizar bibliotecas (e cabeçalhos) padrão
● printk no lugar de printf#include <linux/x.h>#include <asm/y.h>
Sinalizar código de kernel● #define __KERNEL__
Evitar conflitos de nomes● Símbolos locais (static)● Símbolos préfixados (mod_sym)EXPORT_NO_SYMBOLS;
top related