Démon BSD

Documentation NetBSD :

Programmation noyau

Divers

Autres liens


Divers


Qu'est-ce que KNF ? (haut)

KNF veut dire «Kernel Normal Form». Il s'agit d'un style de codage en C, décrit dans /usr/share/misc/style, inclus dans l'arborescence sous /usr/src/share/misc/style.

Utiliser l'attribut «packed» (haut)

Utilisez toujours l'attribut «packed» dans les structures décrivant les format de données des protocoles réseau.

Utiliser printf() pour débugger (haut)

La plus simple façon d'obtenir des informations pour débugger un pilote est certainement d'utiliser printf(). Le noyau affichera les messages que vous voulez sur la console. Prenez garde de ne pas effectuer trop de demandes rendant ce système illisible.

Forcer le code à entrer dans DDB. (haut)

Assurez-vous que le fichier de configuration du noyau contienne «options DDB» et que votre fichier ait «#include "opt_ddb.h"» puis utilisez «Debugger()».

Ajouter un pilote au noyau (haut)

Tous les pilotes ont, au moins, besoin de

Une fois que les routines probe et attach sont écrites, ajoutez une entrée au fichier

/usr/src/sys/arch/<votre-arch>/<votre-arch>/conf.c.

Il existe deux tables :

La plupart des entrées se présenteront sous la forme cdev_xxx_init() qui correspond à une macro gérant les prototypes standards d'Unix des routines de changements de périphériques.

Les routines probe/attach sont appelées au démarrage. Les routines open(), close(), read() et write() sont appelées lorsque vous sollicitez le fichier du périphérique dont le nombre majeur correspond à l'index de cette table. Par exemple, si vous sollicitez le périphérique dont le nombre majeur est 18, la routine «open» du périphérique 18 dans cdevsw[]/bdevsw sera appelée.

La plupart des pilotes sont divisés en deux parties : l'une spécifique au bus et l'autre indépendante de la machine. Par exemple, le pilote ethernet lance PCI possède des entrées dans les fichiers suivants :

Ajouter un appel système (haut)

Ajoutez une entrée dans syscalls.master et ajoutez sa caractéristique à l'endroit approprié dans /usr/src/lib/libc/sys/Makefile.inc .

Implémenter un pseudo-périphérique mmap (haut)

Votre périphérique est probablement en mode caractères, vous devrez alors utiliser le périphérique de pagination (le système de mémoire virtuelle s'occupe de tout, ne vous en faites pas).

La première chose à faire est de choisir un offset quelconque pour votre interface mmap. Quelque chose comme «mmap offset 0-M gives object A, N-O gives object B», etc...

Ensuite, votre routine mmap ressemblera à :

int
foommap(dev, off, prot)
        dev_t dev;
        int off, prot;
{

        if (off & PAGE_MASK)
                panic("foommap");

        if ((u_int)off >= FOO_REGION1_MMAP_OFFSET &&
            (u_int)off < (FOO_REGION1_MMAP_OFFSET + FOO_REGION1_SIZE))
                return (atop(FOO_REGION1_ADDR + ((u_int)off -
                    FOO_REGION1_MMAP_OFFSET)));

        if ((u_int)off >= FOO_REGION2_MMAP_OFFSET &&
            (u_int)off < (FOO_REGION2_MMAP_OFFSET + FOO_REGION2_SIZE))
                return (atop(FOO_REGION1_ADDR + ((u_int)off -
                    FOO_REGION2_MMAP_OFFSET)));

        /* Page non trouvée. */
        return (-1);
}

Les choses vont maintenant se corser car vous allez «mmapper» ce qui n'est que des objets mémoire du noyau (c'est un pseudo-périphérique, n'est-ce pas ?).

Pour que cela marche, vous allez vous assurer que vous allouez les objets mémoire à mmapper à des limites alignées sur les pages. Ce sera toujours le cas si vous allouez une taille >= PAGE_SIZE. Autrement, vous devrez utiliser uvm_km_alloc() et arrondir la taille pour remplir la page.

Vous aurez alors quelque chose comme :

int
foommap(dev, off, prot)
        dev_t dev;
        int off, prot;
{
        paddr_t pa;

        if (off & PAGE_MASK)
                panic("foommap: offset not page aligned");

        if ((u_int)off >= FOO_REGION1_MMAP_OFFSET &&
            (u_int)off < (FOO_REGION1_MMAP_OFFSET + FOO_REGION1_SIZE)) {
                if ((vaddr_t)foo_object1 & PAGE_MASK)
                        panic("foommap: foo_object1 not page aligned");
                if (pmap_extract(pmap_kernel(), foo_object1 +
                    (u_int)off - FOO_REGION1_MMAP_OFFSET, &pa) == FALSE)
                        panic("foommap: foo_object1 page not mapped");
                return (atop(pa));
        }

        if ((u_int)off >= FOO_REGION2_MMAP_OFFSET &&
            (u_int)off < (FOO_REGION2_MMAP_OFFSET + FOO_REGION2_SIZE)) {
                if ((vaddr_t)foo_object2 & PAGE_MASK)
                        panic("foommap: foo_object2 not page aligned");
                if (pmap_extract(pmap_kernel(), foo_object2 +
                    (u_int)off - FOO_REGION2_MMAP_OFFSET, &pa) == FALSE)
                        panic("foommap: foo_object2 page not mapped");
                return (atop(pa));
        }

        /* Page non trouvée. */
        return (-1);
}

Accéder à la structure du noyau (haut)

L'exemple canonique est celui-ci : /usr/src/usr.bin/vmstat/dkstats.c , qui lit les statistiques d'un disque.

Exist-t-il un pilote PCI simple qui puisse me servir d'exemple ? (haut)

Regardez sys/dev/pci/puc.c, l'un des pilotes les plus simples. Les PUC sont des périphériques possédant un ou plusieurs ports série ou parallèle gérés par des puces standards (comme 16550 UART pour le port série). Le pilote se contente de localiser les adresses E/S des registres série ou parallèle pour les donner au pilote série ou parallèle.

Retour vers la Documentation NetBSD : le noyau
Accueil
Accueil Documentation

(Nous contacter) $NetBSD: programming.html,v 1.13 2006/06/22 15:49:07 jschauma Exp $
Copyright © 1998-2003 par la Fondation NetBSD, Inc. TOUS DROITS RÉSERVÉS.