You are on page 1of 31

Integrao de Sistemas Embebidos

MECom :: 5 ano

- Criao e execuo de mdulos do kernel Antnio Joaquim Esteves www.di.uminho.pt/~aje

Device Drivers em Linux

Bibliografia: captulo 2, LDD 3ed, OReilly


DEP. DE INFORMTICA ESCOLA DE ENGENHARIA UNIVERSIDADE DO MINHO

Criao e execuo de mdulos do kernel


- Sumrio -

Exemplo: o mdulo Hello World Mdulos do kernel vs aplicaes Compilar e carregar um mdulo A tabela de smbolos do kernel Questes preliminares Inicializar e desinstalar um mdulo Mdulos com parmetros Drivers que funcionam no espao do utilizador

Criao e execuo de mdulos do kernel


- Introduo

Esta seco introduz todos os conceitos essenciais para desenvolver mdulos e programar o kernel. Atravs do mdulo Hello World vamos analisar o cdigo bsico e as fases envolvidas no desenvolvimento de qualquer mdulo, sem especificar uma classe de dispositivos. Os mdulos dados como exemplo funcionam na maioria dos kernels 2.6.x. Para construir mdulos para um kernel 2.6.x requer que se tenha criado e configurado toda a rvore dum kernel no sistema. Os mdulos para um kernel 2.6.x so linkados com ficheiros objecto que se encontram na rvore do cdigo fonte dum kernel.

Criao e execuo de mdulos do kernel


- Exemplo: o mdulo Hello World

Este exemplo j foi analisado na aula anterior:

#include "/usr/src/kernels/2.6.17-1.2187_FC5-i686/include/linux/init.h #include "/usr/src/kernels/2.6.17-1.2187_FC5-i686/include/linux/module.h /* MODULE_LICENSE() - Indica ao kernel que este modulo possui uma licenca livre, evitando assim que ele se queixe quando se carrega o modulo */ MODULE_LICENSE("Dual BSD/GPL"); static int hello_init (void) { /* printk() - e' uma funcao do kernel similar ao printf do C, mas que nao recorre a qualquer biblioteca standard do C. KERN_ALERT - e' uma string que indica a prioridade da mensagem, alta neste caso para garantir que a mensagem aparece em tempo util. */ printk(KERN_ALERT "Ola', o modulo foi carregado no kernel.\n"); return 0; } static void hello_exit (void) { printk(KERN_ALERT "Adeus, o modulo foi removido do kernel.\n"); } module_init (hello_init); module_exit (hello_exit);

Criao e execuo de mdulos do kernel


- Mdulos do kernel vs aplicaes

Enquanto a maioria das aplicaes executa uma nica tarefa do incio at ao fim, os mdulos do kernel apenas se registam de modo a responder a pedidos futuros. A tarefa da funo de inicializao dum mdulo prepar-lo para as evocaes futuras das suas funes. A funo de concluso (exit) dum mdulo evocada exactamente antes de o mdulo ser desinstalado. Esta abordagem anloga programao orientada a eventos. Nem todas as aplicaes so orientadas a eventos todos os mdulos do kernel so. Uma aplicao pode chamar funes que no define a fase de link resolve as referncias externas usando a biblioteca adequada. Um mdulo linkado apenas com o kernel s pode chamar as funes exportadas pelo kernel no se pode fazer o link com bibliotecas.

Criao e execuo de mdulos do kernel


- Mdulos do kernel vs aplicaes Espao do utilizador vs espao do kernel Enquanto os mdulos so executados no espao do kernel, as aplicaes so executadas no espao do utilizador. O sistema operativo deve garantir o funcionamento independente de vrios programas e protege-los de acessos no autorizados aos recursos. Isto s conseguido se o CPU proteger o software do sistema das aplicaes. Uma alternativa para conseguir esta proteco implementar vrios nveis de proteco no CPU. Cada nvel tem o seu papel e algumas operaes no so permitidas nos nveis inferiores. Um programa tem um nmero reduzido de formas de mudar de um nvel para outro. Os processadores actuais possuem pelo menos 2 nveis de proteco.

Criao e execuo de mdulos do kernel


- Mdulos do kernel vs aplicaes Espao do utilizador vs espao do kernel Em Linux, o kernel executado no nvel mais alto (modo supervisor), em que tudo permitido. As aplicaes executam-se no nvel mais baixo (modo user), onde o processador controla o acesso directo ao h/w e impede o acesso no autorizado memoria. Os modos de execuo so normalmente designados de espao do kernel e espao do utilizador. A cada modo esto associados os privilgios de execuo e um espao de endereamento prprio. O Linux transfere a execuo do espao do utilizador para o do kernel sempre que a aplicao fizer uma chamada ao sistema ou a aplicao for suspensa por uma interrupo de h/w. Num driver, alguma funes so executadas usando chamadas ao sistema e outras servem interrupes.

Criao e execuo de mdulos do kernel


- Mdulos do kernel vs aplicaes Concorrncia no kernel

A maioria das aplicaes executada sequencialmente do incio ao fim. O cdigo do Kernel no executa dessa forma to simples deve estar preparado para que ocorram vrios eventos em simultneo. Em Linux, vrios processos podem tentar usar um driver ao mesmo tempo. A maioria dos dispositivos capaz de interromper o processador. As rotinas de servio a interrupes funcionam assincronamente e podem ser evocadas enquanto o driver executa outra tarefa. Como o Linux pode correr em sistemas multi-processador, um driver pode estar a executar concorrentemente em vrios CPUs.

Criao e execuo de mdulos do kernel


- Mdulos do kernel vs aplicaes Concorrncia no kernel

No kernel 2.6, o cdigo do kernel passou a ser preemptivo as questes de concorrncia dum sistema uni-processador so similares s dum sistema multi-processador. Em consequncia, o cdigo do kernel em Linux deve ser reentrante pode ser executado em vrios contextos (processos) ao mesmo tempo. Os mltiplos fios de execuo (threads) devem ser mantidos separados e deve evitar-se corromper os dados partilhados. No kernel 2.6, o cdigo do kernel no deve assumir que dispe do processador atribudo a si durante um determinado intervalo.

Criao e execuo de mdulos do kernel


- Mdulos do kernel vs aplicaes O processo actual

Embora os mdulos do kernel no sejam executados sequencialmente, como so as aplicaes, o grosso da actividade do kernel decorre no mbito de um processo especfico. O cdigo do Kernel pode referenciar o processo actual acedendo varivel global current, definida em <asm/current.h>. current guarda um apontador para struct task_struct, definida em <linux/sched.h>. A instruo seguinte imprime o ID e o comando do processo actual, acedendo aos campos de struct task_struct:
printk (KERN_INFO O processo e \"%s\" (pid %i)\n", current->comm, current->pid);

Criao e execuo de mdulos do kernel


- Mdulos do kernel vs aplicaes Programao do kernel vs programao no modo user

As aplicaes executam em memria virtual e com uma pilha enorme. O kernel possui uma pilha muito reduzida ex: 1 pgina de 4k bytes. As funes de todos os mdulos kernel vo partilhar a mesma pilha. Funes da API do kernel assinaladas com __ costumam ser de baixo nvel devem ser usadas com cuidado. O cdigo do Kernel no pode usar aritmtica em virgula flutuante.

Criao e execuo de mdulos do kernel


- Compilar e carregar um mdulo Compilar mdulos

Primeiro, vamos ver como se constri um mdulo. Depois de instalar as fontes do kernel, escreve-se uma makefile para o mdulo. Para o exemplo Hello World a seguinte linha suficiente: obj-m := hello.o Esta atribuio indica que se vai construir um mdulo a partir do ficheiro objecto hello.o. O mdulo gerado ter o nome hello.ko. Se um mdulo module.ko for gerado a partir de 2 ficheiros fonte (file1.c e file2.c), as instrues a usar so: obj-m := module.o module-objs := file1.o file2.o

Criao e execuo de mdulos do kernel


- Compilar e carregar um mdulo Compilar mdulos

Se as fontes do kernel estiverem no directrio ~/kernel-2-6, o comando make a usar na gerao do mdulo ser: make -C ~/kernel-2-6 M=`pwd` modules Este comando comea por mudar para o directrio para indicado pela opo C. A opo M= faz a makefile regressar ao directrio do mdulo em causa, antes de construir o mdulo alvo especificado pela varivel obj-m module.o neste exemplo. O comando make anterior pode ser substitudo por uma makefile:

Criao e execuo de mdulos do kernel


- Compilar e carregar um mdulo Compilar mdulos
# If KERNELRELEASE is defined, we've been invoked from the # kernel build system and can use its language. ifneq ($(KERNELRELEASE),) obj-m := hello.o # Otherwise we were called directly from the command # line invoke the kernel build system. else KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif

Criao e execuo de mdulos do kernel


- Compilar e carregar um mdulo Compilar mdulos

Normalmente, esta makefile lida 2 vezes. Primeiro localiza-se o directrio com as fontes do kernel. Se o kernel alvo diferente do kernel em execuo, deve indicar-se onde se encontra este directrio com:

A opo KERNELDIR= na linha de comandos. A varivel de ambiente KERNELDIR. Uma linha da makefile em que se atribui um valor a KERNELDIR.

A makefile evoca default: target, que executa o comando make pela 2 vez. Na 2 leitura, a makefile define obj-m e as makefiles geram o mdulo alvo.

Criao e execuo de mdulos do kernel


- Compilar e carregar um mdulo Carregar e remover mdulos Depois de o mdulo estar construdo, preciso carreg-lo no kernel o programa insmod realiza esta tarefa. O insmod Faz o link dos smbolos por resolver com a tabela de smbolos do kernel.

Aceita opes da linha de comandos. Atribui valores aos parmetros do mdulo antes de fazer o link com o kernel. Baseia-se numa chamada ao sistema definida em kernel/module.c. Aloca memria do kernel para guardar o mdulo (com vmalloc). Copia o cdigo do mdulo para essa zona de memria. Resolve as referncias do mdulo ao kernel usando a tabela de smbolos. Chama a funo de inicializao do mdulo.

A funo sys_init_module

O programa rmmod permite remover mdulos do kernel. O programa lsmod gera uma lista com os mdulos carregados no kernel.

Criao e execuo de mdulos do kernel


- Compilar e carregar um mdulo Dependncias da verso do kernel

Os mdulos esto fortemente ligados s estruturas de dados e funes de uma determinada verso do kernel. Num dos passos da construo, faz-se o link entre o mdulo em causa e o ficheiro vermagic.o do kernel. Este ficheiro objecto contm informao acerca do kernel: a sua verso, o compilador usado e algumas variveis de configurao. Ao tentar carregar um mdulo, a informao relativa ao kernel e ao mdulo comparada se no houver compatibilidade o mdulo no carregado surge uma mensagem de erro:
> insmod hello.ko Error inserting './hello.ko': -1 Invalid module format

Criao e execuo de mdulos do kernel


- Compilar e carregar um mdulo

Quando existe preocupaao com a verso do kernel, deve usar-se as definies de linux/version.h. Este ficheiro, includo automaticamente ao usar linux/module.h, define as seguintes macros: UTS_RELEASE, LINUX_VERSION_CODE, KERNEL_VERSION(major,minor,release).

Dependncias da arquitectura alvo

O cdigo do kernel pode ser optimizado para um processador especfico de modo a obter o melhor desempenho com a arquitectura alvo. Quando se carrega um mdulo, o kernel verifica se as configuraes relativas ao processador so compatveis recorrendo a vermagic.o . Se o mdulo tiver sido compilado com opes diferentes, no carregado.

Criao e execuo de mdulos do kernel


- A tabela de smbolos do kernel

J vimos que insmod resolve os smbolos por definir atravs da tabela de smbolos pblicos do kernel. A tabela contm o endereo de itens globais do kernel, necessrios para implementar drivers modulares. Ao carregar um mdulo, os smbolos por ele exportados passam a fazer parte da tabela de smbolos do kernel. Exportam-se smbolos quando eles forem teis a outros mdulos. Quando se usa mdulos empilhados sobre outros mdulos, conveniente usar o programa modprobe. modprobe funciona de forma anloga a insmod mas alm do mdulo em causa, carrega todos os que lhe so necessrios. Para exportar smbolos pode usar-se as macros seguintes:
EXPORT_SYMBOL(name); OU EXPORT_SYMBOL_GPL(name);

Criao e execuo de mdulos do kernel


- Questes preliminares

A maior parte do cdigo kernel inclui vrios ficheiros header. habitual um mdulo usar as seguintes linhas:
#include <linux/module.h> #include <linux/init.h>

module.h contm definies de smbolos e funes necessrios para carregar mdulos. init.h til para e especificar as funes de inicializao e remoo. moduleparam.h permite passar parmetros quando se carrega o mdulo. O mdulo deve especificar a licena que se aplica ao seu cdigo:
MODULE_LICENSE ("GPL");

Outras definies descritivas passveis de incluir num mdulo:

MODULE_AUTHOR, MODULE_DESCRIPTION, MODULE_VERSION, MODULE_ALIAS e MODULE_DEVICE_TABLE.

Criao e execuo de mdulos do kernel


- Inicializar e desinstalar um mdulo

A funo de inicializao regista as facilidades oferecidas pelo mdulo. Facilidade uma funcionalidade nova, que pode ser acedida pelas aplicaes. A definio da funo de inicializao sempre assim:
static int __init initialization_function (void) { /* Initialization code here */ } module_init (initialization_function);

Uma funo de inicializao deve ser declarada static no precisa ser visvel no exterior do ficheiro em que definida. O token __init indica ao kernel que a funo s usada durante a inicializao. Para assinalar dados que s so usados durante a inicializao existe o token __initdata.

Criao e execuo de mdulos do kernel


- Inicializar e desinstalar um mdulo

obrigatrio utilizar a macro module_init. Esta macro adiciona ao cdigo objecto do mdulo a localizao da sua funo de inicializao. Existe uma funo para registar cada facilidade oferecida pelo mdulo. Os argumentos passados a essas funes so apontadores para estruturas de dados que descrevem a nova facilidade e o nome da facilidade a registar. A estrutura de dados contm apontadores para as funes que podem ser chamadas do mdulo.

Criao e execuo de mdulos do kernel


- Inicializar e desinstalar um mdulo A funo de remoo (cleanup)

Qualquer mdulo no trivial requer uma funo de remoo. Esta funo apaga os registos das interfaces e devolve os recursos ao sistema antes de o mdulo ser removido. A definio da funo :
static void __exit cleanup_function (void) { /* Cleanup code here */ } module_exit (cleanup_function);

A funo de remoo no devolve qualquer valor. O token __exit indica que o cdigo s usado para remover o mdulo. A macro module_exit indica ao kernel a localizao da funo de remoo.

Criao e execuo de mdulos do kernel


- Inicializar e desinstalar um mdulo Gesto de erros durante a inicializao

O registo das facilidades no kernel pode falhar. Assim, o mdulo deve verificar sempre os valores devolvidos, para saber se as operaes requisitadas tiveram sucesso. Mesmo que ocorra um erro, o mdulo deve disponibilizar as facilidades que lhe for possvel. Se o mdulo no puder ser carregado, deve anular-se os registos efectuadas antes da falha. Para implementar a recuperao de erros comum usar a instruo goto.

Criao e execuo de mdulos do kernel


- Inicializar e desinstalar um mdulo Gesto de erros durante a inicializao O cdigo seguinte funciona correctamente se a inicializao falhar em alguma posio:
int __init my_init_function (void) {
int err; /* registration takes a pointer and a name */ err = register_this(ptr1, "skull"); if (err) goto fail_this; err = register_that(ptr2, "skull"); if (err) goto fail_that; err = register_those(ptr3, "skull"); if (err) goto fail_those; return 0; /* success */ fail_those: unregister_that(ptr2, "skull"); fail_that: unregister_this(ptr1, "skull"); fail_this: return err; /* propagate the error */ }

Criao e execuo de mdulos do kernel


- Inicializar e desinstalar um mdulo Gesto de erros durante a inicializao

Outra alternativa, que no requer instrues goto, consiste em saber o que foi registado at ao momento actual e chamar a funo de remoo quando ocorrer um erro. O valor devolvido por my_init_function, err, um cdigo de erro. No Linux, os cdigos de erro so nmeros negativos definidos em <linux/errno.h>. A funo de remoo dum mdulo deve anular todos os registos efectuados pela funo de inicializao:
void __exit my_cleanup_function (void) {
unregister_those (ptr3, "skull"); unregister_that (ptr2, "skull"); unregister_this (ptr1, "skull"); return; }

Criao e execuo de mdulos do kernel


- Inicializar e desinstalar um mdulo -

Conflitos ao carregar mdulos

Deve ter-se em ateno que outras partes do kernel podem comear a utilizar as facilidades imediatamente aps a concluso do registo. No se deve registar uma facilidade antes que toda a inicializao necessria ao seu funcionamento esteja concluda. Se a funo de inicializao falhar, mas alguma parte do kernel j estiver a utilizar uma facilidade registada, no se deve anular a inicializao.

Criao e execuo de mdulos do kernel


- Mdulos com parmetros

Alguns dos parmetros necessrios a um driver podem variar de sistema para sistema. Os valores dos parmetros pode ser definidos na fase de carregar por insmod ou modprobe. Para demonstrar esta possibilidade, pode usar-se a verso alterada do mdulo Hello World o mdulo hellop dos exemplos do livro LDD3. Neste exemplo foram adicionados 2 parmetros: um valor inteiro (howmany) e uma string de caracteres (whom). Quando se carrega hellop, enviada uma mensagem a whom howmany vezes. Este mdulo carregado com uma linha de comandos como: insmod hellop howmany=10 whom="Mom" Antes que insmod possa alterar os parmetros do mdulo, o mdulo tem que os disponibilizar.

Criao e execuo de mdulos do kernel


- Mdulos com parmetros

Os parmetros so declarados com a macro module_param, definida em moduleparam.h. module_param possui 3 parmetros: o nome da varivel, o seu tipo e uma mscara de permisses. hellop declara os seus parmetros e disponibiliza-os a insmod com seguinte cdigo: static char *whom = "world"; static int howmany = 1; module_param(howmany, int, S_IRUGO); module_param(whom, charp, S_IRUGO); Os parmetros dum mdulo pode ser de inmeros tipos: bool, invbool, charp, int, long, short, uint, ulong, ushort.

Criao e execuo de mdulos do kernel


- Mdulos com parmetros

Tambm permitido carregar mdulos com parmetros do tipo array, em que os valores so fornecidos com uma lista separada por vrgulas. Para declarar um parmetros do tipo array usa-se: module_param_array (name, type, num, perm); O ltimo campo de module_param/module_param_array uma permisso. As alternativas possveis neste campo encontram-se em <linux/stat.h>. Exemplos:

S_IRUGO define um parmetro que pode ser lido de fora mas no pode ser alterado. S_IRUGO | S_IWUSR permite que a root altere o parmetro.

- Drivers que funcionam no espao do utilizador Algumas das limitaes de um driver em modo do utilizador so:

Criao e execuo de mdulos do kernel

As interrupes no esto disponveis no espao do utilizador. O acesso directo memria s possvel fazendo mmapping de /dev/mem, e apenas um utilizador privilegiado o pode fazer. O acesso a portas de I/O s est disponvel aps evocar ioperm ou iopl. Nem todas as plataformas suportam estas chamadas ao sistema, ficando o acesso a /dev/port bastante lento. O tempo de resposta elevado. Pior, se o driver tiver sido mudado para disco, o tempo de resposta inaceitavelmente elevado.

You might also like