2013-03-08 5 views
24

Ich bin auf der Suche nach einem PWM-Treiber zu schreiben. Ich weiß, dass es zwei Möglichkeiten gibt, einen Hardware-Treiber zu steuern:Userspace vs Kernel-Space-Treiber

  • Benutzerraumtreiber.
  • Kernel Raum Treiber
  • Wenn im Allgemeinen (keine PWM-Treiber Fall betrachtet) haben wir eine Entscheidung treffen, ob für User-Space oder Kernel-Space-Treiber zu gehen. Welche Faktoren müssen wir dann außer Acht lassen?

    1. Benutzerraumtreiber kann mmap()/dev/mem-Speicher direkt in ihren virtuellen Adressraum setzen und benötigt keinen Kontextwechsel.
    2. Der Userspace-Treiber kann keine Interrupt-Handler implementiert haben (sie müssen nach Interrupts fragen).
    3. Userspace-Treiber kann DMA nicht ausführen (da DMA-fähiger Speicher aus Kernel-Space zugewiesen werden kann).
    +1

    Sicherheit: Dateiberechtigungen des Geräteknotens steuern, welche Benutzer das Gerät öffnen/lesen/schreiben können. Dateioperationen verweigern oder erlauben gleichzeitige Operationen. – sawdust

    +1

    Die Entscheidung kann stark davon abhängen, was Sie PWMing sind und welche Hardware verwenden. –

    Antwort

    31

    Von diesen drei Faktoren, die Sie aufgelistet haben, ist nur die erste tatsächlich korrekt. Wie für den Rest - nicht wirklich. Es ist möglich, dass ein Benutzer-Space-Code DMA-Operationen ausführt - kein Problem damit. Es gibt viele Hardware-Appliance-Unternehmen, die diese Technik in ihren Produkten einsetzen. Es ist auch möglich, eine interruptgesteuerte Benutzerraumanwendung zu verwenden, selbst wenn alle E/A mit einem vollständigen Kernel-Bypass ausgeführt werden. Natürlich ist es nicht so einfach, einfach eine mmap() auf /dev/mem zu tun.

    Sie müssten einen minimalen Teil Ihres Treibers im Kernel haben - das ist notwendig, um Ihrem Benutzer einen minimalen Speicherplatz zu verschaffen, den er vom Kernel benötigt (denn wenn Sie darüber nachdenken - /dev/mem ist auch von einem Zeichengerätetreiber unterstützt).

    Für DMA ist es eigentlich zu einfach - alles, was Sie tun müssen, ist die mmap Anforderung zu behandeln und einen DMA-Puffer in den Benutzerraum abzubilden. Für Interrupts - es ist ein wenig komplizierter, der Interrupt muss vom Kernel gehandhabt werden, egal was, aber der Kernel macht vielleicht keine Arbeit und weckt nur den Prozess auf, der zB epoll_wait() aufruft. Ein anderer Ansatz besteht darin, ein Signal an den Prozess zu senden, wie es DOSEMU getan hat, aber das ist sehr langsam und wird nicht empfohlen.

    Was Ihre eigentliche Frage betrifft, ist ein Faktor, den Sie beachten sollten, die gemeinsame Nutzung von Ressourcen. Solange Sie ein Gerät nicht für mehrere Anwendungen freigeben müssen und nichts anderes im Benutzerbereich möglich ist, wählen Sie den Benutzerbereich aus. Sie werden wahrscheinlich während des Entwicklungszyklus viel Zeit sparen, da das Schreiben von Benutzercode sehr einfach ist. Wenn jedoch zwei oder mehr Anwendungen das Gerät (oder seine Ressourcen) gemeinsam nutzen müssen, ist es wahrscheinlich, dass Sie viel Zeit dafür aufwenden werden - stellen Sie sich einfach vor, dass mehrere Prozesse gleichzeitig ablaufen, abstürzen, gleichzeitig Speicher ablegen (usw.) Und schließlich wird IPC im Allgemeinen über den Kernel ausgeführt, sodass, wenn die Anwendung mit dem "Sprechen" beginnen müsste, die Leistung stark beeinträchtigt sein könnte. Für einige performancekritische Anwendungen wird das zwar immer noch im wirklichen Leben gemacht, aber ich möchte nicht auf diese Details eingehen.

    Ein weiterer Faktor ist die Kernel-Infrastruktur. Nehmen wir an, Sie möchten einen Netzwerkgerätetreiber schreiben. Das ist kein Problem, es im Benutzerraum zu tun. Wenn Sie dies tun, müssen Sie jedoch auch einen vollständigen Netzwerkstapel schreiben, da es nicht möglich ist, Linux-Standardbenutzernamen zu verwenden, der im Kernel vorhanden ist.

    Ich würde sagen, gehen Sie für Benutzerraum, wenn es möglich ist und die Menge an Aufwand, um Dinge zu arbeiten, ist weniger als das Schreiben eines Kernel-Treibers und im Hinterkopf, dass es eines Tages notwendig sein könnte, Code in den Kernel zu verschieben . Tatsächlich ist es eine gängige Praxis, denselben Code sowohl für den Benutzerraum als auch für den Kernelraum zu kompilieren, je nachdem, ob ein Makro definiert ist oder nicht, da das Testen im Benutzerbereich viel angenehmer ist.

    +0

    Große Antwort. Ich war auf der Suche nach diesen Informationen und Ihre Antwort war sehr hilfreich. –

    +0

    Allerdings hat epoll einen schnellen Mechanismus, schließlich ist es eine Poll-Struktur, kein Interrupt-Handler. Dies kann zu Problemen mit zeitkritischen Operationen führen. – obayhan

    6

    Eine weitere Überlegung: Es ist viel einfacher, User-Space-Treiber zu debuggen. Sie können gdb, valgrind, etc. verwenden. Heck, Sie müssen nicht einmal Ihren Treiber in C schreiben.

    Es gibt eine dritte Option, die über die Benutzer-Space- oder Kernel-Space-Treiber hinausgeht: einige von beiden. Sie können nur den Kernel-Space-Only-Kram in einem Kernel-Treiber ausführen und alles andere im Benutzerbereich erledigen. Sie müssen möglicherweise nicht einmal den Kernel-Space-Treiber schreiben, wenn Sie das Linux UIO-Treiberframework verwenden (siehe https://www.kernel.org/doc/html/latest/driver-api/uio-howto.html).

    Ich hatte Glück, einen DMA-fähigen Treiber fast vollständig in Benutzerraum zu schreiben. UIO stellt die Infrastruktur zur Verfügung, so dass Sie/epoll nur in einer Datei lesen/auswählen können, um auf einen Interrupt zu warten.

    Sie sollten die Sicherheitsauswirkungen der Programmierung der DMA-Deskriptoren aus dem Benutzerbereich kennen: Wenn Sie nicht über einen Schutz im Gerät selbst oder einer IOMMU verfügen, kann der Benutzer-Space-Treiber das Lesen oder Schreiben von Adressen veranlassen im physischen Gedächtnis.