View Single Post
Old 07-01-2005, 10:11   #4
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
Hello world in kernel space

Ora che avete capito come compilare un modulo per inserirlo nel kernel, vediamo come è fatto lo scheletro di un driver. Partiamo dal comune hello world:
Codice:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

static int __init hello_init(void)
{
	printk(KERN_INFO "Hello world!\n");
	return 0;
}

static void __exit hello_exit(void)
{
	printk(KERN_INFO "Goodbye!\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ilsensine");
MODULE_DESCRIPTION("hello-world module");
Esaminiamo in dettaglio le varie righe:
Codice:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
Gli include sono ricercati nella directory "include/" dei sorgenti. Dentro questa esistono, tra tutte, due sottodirectory principali:
linux/ contenente gli header piattaforma-indipendenti del kernel
asm/ contenente gli header piattaforma-dipendenti
Per nessun motivo un driver può includere gli header userspace, ovviamente.
I tre #include inseriti sono il minimo necessario per un modulo.
Quote:
static int __init hello_init(void)
static void __exit hello_exit(void)
Queste due funzioni sono invocate al caricamento e allo scaricamento del driver. La funzione di caricamento può fallire, ritornando con un valore negativo l'errore avvenuto (ad es. -ENOMEM, -ENODEV...). La seconda funzione non può mai fallire: notate però che lo scaricamento di un driver è consentito solo se non esistono reference count (quindi "utenti") del driver. Il controllo lo fa automaticamente il kernel, quindi non dovete preoccuparvene.
Le macro __init ed __exit servono ad indicare che le funzioni hanno validità solo in fase di inizializzazione o di finalizzazione: quindi ad esempio la funzione hello_init può essere scartata dopo l'inizializzazione del modulo (liberando così un pò di memoria); la hello_exit invece può non essere proprio compilata se inserite il vostro driver staticamente nel kernel.
Codice:
printk(KERN_INFO "Hello world!\n");
Questa funzione è equivalente alla funzione printf in user space. Tuttro ciò che stampa finisce nel kernel log, e può essere visualizzato tramite dmesg.
La macro (opzionale) KERN_INFO indica il livello di priorità del messaggio; esistono 8 livelli di priorità, definiti in kernel.h.
Codice:
module_init(hello_init);
module_exit(hello_exit);
Tramite queste macro informiamo il kernel sui nomi delle nostre funzioni di inizializzazione e finalizzazione.
Codice:
MODULE_AUTHOR("ilsensine");
MODULE_DESCRIPTION("hello-world module");
Informazioni opzionali descrittive. Vengono visualizzate se eseguite un modinfo sul vostro driver.
Codice:
MODULE_LICENSE("GPL");
Non avete intenzione di "tainteggiare" il vostro kernel, vero?
Notate inoltre che alcune funzionalità del kernel sono disponibili solo ai driver con licenza GPL.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12

Ultima modifica di ilsensine : 07-01-2005 alle 10:16.
ilsensine è offline