Programação de Sistemas Módulos do núcleo Programação de Sistemas Módulos : 1/15 Introdução (1) Desenvolvimentos do núcleo, como a criação de novos dispositivos, podem ser incorporados no Linux em duas formas: Compilar nova versão do núcleo e fazer o boot : pesado! (unica opção disponível até Linux 1.2) Criar um LKM ( Loadable Kernel Module ) e instalar com o sistema operativo a correr. Vantagens: erros não impedem carregamento do sistema operativo, depuração e alteração mais fáceis, núcleo mais leve, porque carregados apenas os módulos necessários, Interface fixa permite desenvolvimentos por equipas exteriores à GPL. Programação de Sistemas Módulos : 2/15
Introdução (2) Principais diferenças entre um módulo e um programa de utilizador a) Inicialização/Finalização Um módulo não é inicializado pela função main, mas por init_module.um módulo é finalizado obrigatoriamente pela função cleanup_module. b) Bibliotecas: os módulos não podem ser usadas bibliotecas do C (printf, ), mas têm à sua disposição funções do núcleo (printk, ) c) Os parâmetros não são passados como argumento de função, mas como directivas. d) Protecção: os programas de utilizador correm em modo protegido. O crash de um programa afecta apenas o processo a executar, mas num módulo pode levar ao shutdown do sistema operativo. Programação de Sistemas Módulos : 3/15 Formato Um módulo tem de possuir as seguintes componentes int init_module(void); void cleanup_module(void); Exemplo: // Executado na instalação // em sucesso, retornar 0 // Executado na retirada #include <linux/module.h> /* para todos os modulos */ #include <linux/kernel.h> /* para KERN_INFO */ MODULE_LICENSE("GPL"); int init_module(void){ printk(kern_info "Hello world!\n"); return 0; // valor distinto de 0 significa falha no init_module } void cleanup_module(void) { printk(kern_info "Goodbye world!\n"); } Programação de Sistemas Módulos : 4/15
Compilação (1) Módulos gerados de forma diferente dos programas de utilizador As funções de ambiente usadas (printf, ) não são válidas. Usar apenas as directivas em <linux/ > disponibilizadas no directório /usr/src/kernels/ uname -r /include). Mensagens enviadas apenas para o ficheiro /var/log/messages pela função printk(kern_info ); O módulo executável possui extensão.ko O ficheiro Makefile (nota: obrigatório M maiúsculo) deve conter as linhas obj-m := id.o module-objs := fich1.o fich2.o Ficheiro executável (na realidade possui extensão.ko) Ficheiros objecto gerados directamente a partir das fontes Programação de Sistemas Módulos : 5/15 Compilação (2) Geração executada pelo comando make -C /lib/modules/`uname -r`/build M=`pwd` modules Tipicamente são geradas as frases manitoba.ist.utl.pt> make -C /lib/modules/`uname -r`/build M=`pwd` modules make: Entering directory `/lib/modules/2.6.189-1.2798.fc-i686/build' CC [M] /home/rgc/linuxdriver/simple/hello-1.o Building modules, stage 2. MODPOST CC /home/rgc/linuxdriver/simple/hello-1.mod.o LD [M] /home/rgc/linuxdriver/simple/hello-1.ko módulo make: Leaving directory `/lib/modules/ 2.6.189-1.2798.fc-i686 /build' manitoba.ist.utl.pt> Programação de Sistemas Módulos : 6/15
Compilação (3) O núcleo possui uma única pilha de apenas 4KB, usada por todos os módulos. Logo, o programador deve minimizar as variáveis locais ao módulo. Código do núcleo não efectua operações em vírgula flutuante. Para o módulo aceder à informação do processo que está em execução, usar a variável task_struct *current. printk(kern_info Process is \ %s\ (pid %i)\n, current->comm, current->pid); Programação de Sistemas Módulos : 7/15 Gestão (1) Gestão feita pelo administrador do sistema por comandos instalados em /sbin insmod fich instala módulo no núcleo rmmod fich retira módulo do núcleo lsmod lista módulos instalados modinfo informação sobre um módulo (versão do núcleo e compilador, directivas MODULE_) Nota: comandos de instalação e eliminação de módulos são válidos apenas na secção de trabalho. Ex: extracto do ficheiro /var/log/messages com comandos insmod e rmmod Feb 2 18:08:39 manitoba kernel: Hello world! Feb 2 18:09:59 manitoba kernel: Goodbye world! Programação de Sistemas Módulos : 8/15
Gestão (2) O módulo fonte pode conter as seguintes directivas: MODULE_DESCRIPTION(" ") MODULE_VERSION(" ") MODULE_ALIAS(" ") MODULE_LICENSE Valores possíveis: "GPL" "GPL v2" "GPL and additional rights" "Dual BSD/GPL" "Dual MIT/GPL" "Dual MPL/GPL Proprietary" Programação de Sistemas Módulos : 9/15 Gestão (3) Para alterar módulos de forma permanente, usar comando /sbin/modprobe Os comandos de instalação/remoção passam a residir no ficheiro/etc/modprobe.conf asterix.ist.utl.pt> more /etc/modprobe.conf alias eth0 8139too alias snd-card-0 snd-via82xx Adição opções options snd-card-0 index=0 install snd-via82xx /sbin/modprobe --ignore-install sndvia82xx && /usr/sbin/alsactl restore >/dev/null 2>&1 : remove snd-via82xx { /usr/sbin/alsactl store >/dev/null 2>&1 : ; }; /sbin/modprobe -r --ignore-remove snd-via82xx alias usb-controller uhci-hcd Nome alternativo Programação de Sistemas Módulos : 10/15
Inserção de módulos no boot No arranque do Linux RedHat são carregados os módulos existentes em /lib/modules/`uname -r`/kernel/ Módulos correntes listados no ficheiro /proc/modules manitoba.ist.utl.pt> more /proc/modules lp 17033 0 - Live 0xd0b16000 autofs4 25413 2 - Live 0x12a20000 i2c_ec 9281 1 sbs, Live 0xd0a00000 i2c_i801 11853 0 - Live 0xd0888000 i2c_core 25537 2 i2c_ec,i2c_i801 Live 0xd0891000 button 10961 0 - Live 0xd0991000 battery a4405 0 - Live 0xd0923000 Em alternativa usar comando lsmod Endereço base Estado (Live, Loading ou Unloading) Módulos que acedem Identificador Dimensão (B) Instâncias o módulo corrente Programação de Sistemas Módulos : 11/15 Parâmetros (1) Módulos não possuem main(). Parâmetros são declarados por directivas module_param(var,type,access) Tipos podem ser: bool, invbool (valor booleano invertido), charp (ponteiro para string), int, uint (inteiro sem sinal), short, ushort, long, ulong Os acessos podem ser: S_IRUGO (apenas leitura), S_IRUGO S_IWUSR (leitura e escrita). Definições em /lib/modules/ uname r /build/include/linux/stat.h O módulo deve importar o ficheiro de definições #include <linux/moduleparam.h> Parâmetros dados na linha de comando insmod na forma insmod fich par=val Programação de Sistemas Módulos : 12/15
Parâmetros (2) Exemplo: #include <linux/moduleparam.h> /* para parâmetros */ static int howmany = 1; module_param(howmany, int, S_IRUGO); int init_module(void) { int aux; for(aux=0; aux<howmany; aux++) printk(kern_info "Hello world %d!\n", aux); return 0;} Programação de Sistemas Módulos : 13/15 Exportação (1) Por omissão, variáveis de funções são locais ao módulo. Pode haver necessidade de separar módulos, por exemplo um dependendente ao hardware e outro mais abstracto (independente do hardware) parport parport_pc Kernel API baixo lp elevado Nível abstracção No Linux, parport exporta funções para os módulos lp e parport_pc Programação de Sistemas Módulos : 14/15
Exportação (2) As funções exportadas são armazenadas numa tabela de dispersão, denominada kernel symbol table, pelas directivas: EXPORT_SYMBOL(identificador) EXPORT_SYMBOL_GPL(identificador) Apenas para outros módulos com licença GPL Programação de Sistemas Módulos : 15/15