Módulos do kernel: carregando, descarregando e escrevendo módulos básicos
1. Introdução aos Módulos do Kernel Linux
Módulos do kernel são pedaços de código que podem ser carregados e descarregados do kernel Linux em execução, sem necessidade de recompilar ou reiniciar o sistema. Eles permitem estender funcionalidades do kernel de forma dinâmica, adicionando suporte a novos dispositivos, sistemas de arquivos ou chamadas de sistema.
O kernel Linux adota uma abordagem híbrida: embora seja monolítico, seu design modular permite que componentes sejam compilados separadamente como módulos. O ciclo de vida de um módulo é simples: ele é carregado na memória, executado (geralmente registrando-se para atender a eventos do sistema) e, quando não for mais necessário, descarregado.
2. Estrutura de um Módulo Básico
Todo módulo do kernel precisa incluir cabeçalhos fundamentais:
#include <linux/module.h> // macros e funções para módulos
#include <linux/kernel.h> // funções do kernel como printk()
#include <linux/init.h> // macros module_init() e module_exit()
As funções de entrada e saída são declaradas com as macros module_init() e module_exit(). A função de inicialização retorna 0 em sucesso ou um código de erro negativo. A função de saída libera recursos alocados.
Informações do módulo são declaradas com macros de licenciamento:
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Seu Nome");
MODULE_DESCRIPTION("Um módulo exemplo");
A licença GPL é obrigatória para distribuição de módulos que usam símbolos exportados como GPL-only.
3. Compilação e Construção de Módulos
Módulos do kernel não são compilados como programas comuns. Eles usam o sistema de build do kernel (Kbuild). Um Makefile típico:
obj-m := meu_modulo.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
A variável obj-m lista os módulos a serem compilados. KDIR aponta para a árvore de fontes do kernel em execução. O comando make invoca o sistema de build do kernel para compilar o módulo. O resultado é um arquivo .ko (kernel object).
4. Carregando e Descarregando Módulos
Para carregar um módulo, use insmod:
sudo insmod meu_modulo.ko
Para descarregar:
sudo rmmod meu_modulo
O comando modprobe é mais inteligente: resolve dependências automaticamente e carrega módulos adicionais necessários:
sudo modprobe meu_modulo
Para ver módulos carregados:
lsmod
Ou examine /proc/modules:
cat /proc/modules
lsmod mostra o nome, tamanho, uso e módulos dependentes.
5. Parâmetros de Módulo e Comunicação com o Usuário
Módulos podem aceitar parâmetros na linha de comando durante o carregamento. Use module_param() para parâmetros simples e module_param_array() para arrays:
#include <linux/moduleparam.h>
static int valor = 0;
static char *nome = "padrao";
static int arr[3];
module_param(valor, int, 0644);
module_param(nome, charp, 0644);
module_param_array(arr, int, NULL, 0644);
O terceiro argumento define as permissões do arquivo em /sys/module/<nome>/parameters/. Para passar parâmetros:
sudo insmod meu_modulo.ko valor=42 nome="teste"
6. Registro de Dispositivos e Interfaces com o Kernel
Para criar um dispositivo virtual, use a API de char devices. Exemplo mínimo:
#include <linux/cdev.h>
#include <linux/fs.h>
static dev_t dev_num;
static struct cdev meu_cdev;
static int meu_open(struct inode *inode, struct file *filp) {
return 0;
}
static ssize_t meu_read(struct file *filp, char __user *buf, size_t len, loff_t *off) {
return 0;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = meu_open,
.read = meu_read,
};
static int __init init_modulo(void) {
alloc_chrdev_region(&dev_num, 0, 1, "meu_dev");
cdev_init(&meu_cdev, &fops);
cdev_add(&meu_cdev, dev_num, 1);
return 0;
}
static void __exit exit_modulo(void) {
cdev_del(&meu_cdev);
unregister_chrdev_region(dev_num, 1);
}
alloc_chrdev_region() aloca dinamicamente um número de dispositivo. cdev_init() e cdev_add() registram as operações do dispositivo.
7. Boas Práticas e Depuração de Módulos
Use printk() para depuração, com níveis de log:
printk(KERN_INFO "Módulo carregado com sucesso\n");
printk(KERN_ERR "Erro ao alocar memória\n");
As mensagens aparecem no buffer do kernel. Visualize com:
dmesg
Ou acompanhe em tempo real:
dmesg -w
Cuidados importantes:
- Nunca use bibliotecas padrão C (glibc) dentro do kernel
- Gerencie memória com kmalloc()/kfree(), não malloc()/free()
- Evite deadlocks usando spinlocks ou mutexes corretamente
- Sempre libere recursos na função de saída
- Teste o descarregamento com rmmod forçado apenas em último caso: sudo rmmod -f modulo
8. Exemplo Completo: Módulo "Hello World" com Parâmetros
Código fonte (hello.c):
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Exemplo");
MODULE_DESCRIPTION("Módulo Hello World com parâmetros");
static int vezes = 1;
static char *mensagem = "Olá, Kernel!";
module_param(vezes, int, 0644);
module_param(mensagem, charp, 0644);
static int __init hello_init(void) {
int i;
for (i = 0; i < vezes; i++) {
printk(KERN_INFO "Hello: %s (iteração %d)\n", mensagem, i+1);
}
return 0;
}
static void __exit hello_exit(void) {
printk(KERN_INFO "Hello: módulo descarregado\n");
}
module_init(hello_init);
module_exit(hello_exit);
Makefile:
obj-m := hello.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
Passo a passo:
- Compile:
make - Carregue com parâmetros:
sudo insmod hello.ko vezes=3 mensagem="Teste" - Verifique as mensagens:
dmesg | tail -5 - Saída esperada no
dmesg:
[12345.678901] Hello: Teste (iteração 1)
[12345.678902] Hello: Teste (iteração 2)
[12345.678903] Hello: Teste (iteração 3)
- Descarregue:
sudo rmmod hello - Confirme:
dmesg | tail -1deve mostrarHello: módulo descarregado
Módulos do kernel são ferramentas poderosas para estender o Linux. Dominar seu carregamento, descarregamento e escrita permite criar desde pequenos utilitários de depuração até drivers completos de dispositivos.
Referências
- Documentação Oficial do Kernel: Módulos — Guia oficial sobre a API de módulos do kernel Linux, incluindo carregamento e parâmetros.
- Linux Device Drivers, Third Edition (LDD3) — Livro clássico e gratuito sobre desenvolvimento de drivers Linux, com capítulos dedicados a módulos.
- The Linux Kernel Module Programming Guide — Tutorial prático e atualizado sobre como escrever módulos do kernel, do básico ao avançado.
- The Linux Documentation Project: Kernel Modules — HOWTO clássico sobre carregamento, descarregamento e gerenciamento de módulos do kernel.
- Kernel Newbies: First Kernel Module — Guia passo a passo para iniciantes criarem seu primeiro módulo do kernel.