web-dev-qa-db-fra.com

Espace utilisateur vs pilote d'espace noyau

Je cherche à écrire un pilote PWM. Je sais qu'il existe deux façons de contrôler un pilote matériel:

  1. Pilote d'espace utilisateur.
  2. Pilote d'espace noyau

Si en général (ne considérez pas un cas de pilote PWM), nous devons prendre une décision entre l'espace utilisateur ou le pilote d'espace noyau. Alors quels facteurs devons-nous prendre en considération en dehors de ceux-ci?

  1. Le pilote d'espace utilisateur peut directement mmap ()/dev/mem mémoire sur leur espace d'adressage virtuel et n'a pas besoin de changement de contexte.
  2. Le pilote de l'espace utilisateur ne peut pas avoir de gestionnaires d'interruption implémentés (ils doivent interroger une interruption).
  3. Le pilote de l'espace utilisateur ne peut pas exécuter DMA (As DMA peut être allouée à partir de l'espace du noyau)).
30
Katoch

De ces trois facteurs que vous avez énumérés, seul le premier est en fait correct. Quant au reste - pas vraiment. Il est possible pour un code d’espace utilisateur d’effectuer des opérations DMA) - pas de problème avec cela. De nombreuses sociétés d’appliance matérielle utilisent cette technique dans leurs produits. Il est également possible d’avoir une interruption entraînée application de l'espace utilisateur, même lorsque toutes les E/S sont effectuées avec un bypass complet du noyau Bien sûr, il n'est pas aussi facile de faire simplement une mmap() sur /dev/mem.

Vous devriez avoir une partie minimale de votre pilote dans le noyau - ce qui est nécessaire pour fournir à votre espace utilisateur le strict minimum dont il a besoin du noyau (car si vous y réfléchissez - /dev/mem Est également sauvegardé par un pilote de périphérique de caractères).

Pour DMA, c'est en fait trop facile - tout ce que vous avez à faire est de gérer la requête mmap et de mapper un tampon DMA dans l'espace utilisateur. Pour les interruptions - c'est un un peu plus délicat, l'interruption doit être gérée par le noyau quoi qu'il arrive, cependant, le noyau peut ne pas faire de travail et simplement réveiller le processus qui appelle, disons, epoll_wait(). Une autre approche consiste à livrer un signal au processus comme fait par DOSEMU, mais qui est très lent et n'est pas recommandé.

Quant à votre question réelle, un facteur que vous devez prendre en considération est le partage des ressources. Tant que vous n'avez pas à partager un appareil entre plusieurs applications et qu'il n'y a rien que vous ne puissiez pas faire dans l'espace utilisateur, optez pour l'espace utilisateur. Vous gagnerez probablement beaucoup de temps pendant le cycle de développement car l'écriture du code de l'espace utilisateur est extrêmement facile. Cependant, lorsque deux applications ou plus doivent partager l'appareil (ou ses ressources), il y a de fortes chances que vous passiez énormément de temps à le rendre possible - imaginez simplement que plusieurs processus forcent, plantent, mappent (la même?) Mémoire simultanément, etc. . Et après tout, IPC est généralement effectué via le noyau, donc si une application doit commencer à "se parler", les performances peuvent se dégrader considérablement. Cela se fait toujours dans la vie réelle pour certaines applications critiques pour les performances, mais je ne veux pas entrer dans ces détails.

Un autre facteur est l'infrastructure du noyau. Supposons que vous souhaitiez écrire un pilote de périphérique réseau. Ce n'est pas un problème de le faire dans l'espace utilisateur. Cependant, si vous faites cela, vous devrez également écrire une pile réseau complète car il ne sera pas possible d'utiliser celle par défaut de Linux qui réside dans le noyau.

Je dirais opter pour l'espace utilisateur si cela est possible et que l'effort nécessaire pour faire fonctionner les choses est inférieur à l'écriture d'un pilote de noyau, et en gardant à l'esprit qu'un jour, il sera peut-être nécessaire de déplacer du code dans le noyau. En fait, c'est une pratique courante d'avoir le même code en cours de compilation pour l'espace utilisateur et l'espace noyau selon qu'une macro est définie ou non, car les tests dans l'espace utilisateur sont beaucoup plus agréables.

35
user405725

Autre considération: il est beaucoup plus facile de déboguer les pilotes de l'espace utilisateur. Vous pouvez utiliser gdb, valgrind, etc. Heck, vous n'avez même pas besoin d'écrire votre pilote en C.

Il existe une troisième option au-delà de l'espace utilisateur ou des pilotes d'espace noyau: certains des deux. Vous pouvez faire juste les choses réservées à l'espace noyau dans un pilote de noyau et faire tout le reste dans l'espace utilisateur. Vous n'aurez peut-être même pas besoin d'écrire le pilote de l'espace noyau si vous utilisez le framework de pilote Linux UIO (voir https://www.kernel.org/doc/html/latest/driver-api/uio-howto.html ).

J'ai eu de la chance d'écrire un pilote compatible DMA presque complètement dans l'espace utilisateur. UIO fournit l'infrastructure pour que vous puissiez simplement lire/sélectionner/epoll sur un fichier pour attendre une interruption.

Vous devez être conscient des implications de sécurité de la programmation des DMA descripteurs à partir de l'espace utilisateur: à moins que vous ne disposiez d'une protection dans le périphérique lui-même ou dans un IOMMU, le pilote de l'espace utilisateur peut entraîner la lecture du périphérique à partir de ou écrire à n'importe quelle adresse de la mémoire physique.

8
Nic Watson