HowTo-Artikel zum Entwickeln eingebetteter Linux-Gerätetreiber als Kernelmodule. Der gesamte Inhalt dieses Artikels kann auf Raspberry Pi ausgeführt werden.
Ich denke, der erste Schritt in der Linux Devadler-Entwicklung ist schwierig. Es gibt nur wenige Materialien, und ich denke, die meisten Menschen werden frustriert sein, wenn sie das O'Reilly-Buch berühren. (Ich war ...)
In diesem Artikel werde ich gemäß dem Inhalt von "Linux Device Driver Programming (Yutaka Hirata)" fortfahren. Ich denke, dieses Buch ist sehr leicht zu verstehen und gut. Da es jedoch 2008 veröffentlicht wurde und alt ist, werde ich es überprüfen, während es tatsächlich auf dem Raspberry Pi ausgeführt wird, damit es in der aktuellen Umgebung (Dezember 2017) funktioniert. (Von der Mitte wird es vom Inhalt des Buches getrennt)
Außerdem wollte ich es so einfach wie möglich machen, damit ich keine entwicklungsübergreifende Umgebung vorbereite und mit Raspeye selbst entwickle. Unabhängig davon, um welches Host-Betriebssystem es sich handelt, können diejenigen, die einen Raspelkuchen haben, diesen sofort ausprobieren. (Wir empfehlen den Entwicklungsstil der Codierung auf einem Host-PC wie Windows und der Übertragung per SFTP an Raspeye.)
--__ 1. Mal: Vorbereiten der Build-Umgebung und Erstellen eines einfachen Kernelmoduls <-------------- ------- Inhalt dieser Zeit __
Lassen Sie uns zunächst die Umgebung vorbereiten und ein einfaches Kernelmodul erstellen.
https://github.com/take-iwiw/DeviceDriverLesson/tree/master/01_01 https://github.com/take-iwiw/DeviceDriverLesson/tree/master/01_02
Wie eingangs erwähnt, werden wir uns auf Raspeye entwickeln. Das heißt, bauen Sie in der nativen Umgebung. Daher können Sie im Grunde genommen gcc usw. für den Raspeltorte verwenden, so dass Sie keine Vorbereitung benötigen sollten. Für den Zugriff auf die Funktionen des Kernels sind jedoch Header usw. erforderlich. Installieren Sie mit dem folgenden Befehl. Dadurch werden der vollständige Header und das Makefile für die Erstellung hier installiert (/ usr / src / linux-headers-4.9.41-v7 + /
). Außerdem wird hier ein symbolischer Link zu hier erstellt (/ lib / modules / 4.9.41-v7 + / build
). (Dieses Verzeichnis ist für meine Umgebung)
sudo apt-get install raspberrypi-kernel-headers
Das ist alles, was es zu tun gibt, da es nicht den gesamten Kernel erstellt.
Schreiben wir zunächst nur das Verhalten, wenn das Kernelmodul geladen (insmod) und entladen (rmmod) wird. Es ist wie in Hello World. Nennen Sie die Datei test.c. Geben Sie den Einstiegspunkt für insmod mit module_init
und den Einstiegspunkt für rmmod mit module_exit
an. Da printf nicht im Kernel verwendet werden kann, wird printk verwendet.
test.c
#include <linux/module.h>
static int test_init(void)
{
printk("Hello my module\n");
return 0;
}
static void test_exit(void)
{
printk("Bye bye my module\n");
}
module_init(test_init);
module_exit(test_exit);
Ich denke, dass Sie das Kernelmodul erstellen können, indem Sie den Befehl gcc selbst eingeben, aber es ist mühsam, den Include-Pfad auf verschiedene Arten anzugeben. Wie oben erwähnt, wird das Makefile zum Erstellen vorbereitet. Verwenden Sie es daher. Erstellen Sie ein Makefile wie das folgende, legen Sie den Namen der Quelldatei fest und rufen Sie das Makefile in / lib / modules / 4.9.41-v7 + / build
auf. Tatsächlich ändert sich der Teil von 4.9.41-v7 + je nach Umgebung. Rufen Sie ihn also mit dem Befehl "uname" auf.
Makefile
obj-m := test.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
In dem Verzeichnis, das oben test.c und Makefile enthält, make
. Dann sollte test.ko abgeschlossen sein. Versuchen Sie danach, das Modul mit insmod
zu laden und das Modul mit rmmod
zu entladen.
make
sudo insmod test.ko
sudo rmmod test.ko
dmesg
Schauen wir uns zum Schluss das Ergebnis an, das printk mit dmesg ausgibt. Dann können Sie sehen, dass der implementierte Code wie unten gezeigt ausgeführt wird.
[ 2324.171986] Hello my module
[ 2327.753108] Bye bye my module
Wenn beim Drucken kein \ n
vorhanden ist, scheint es nicht in das dmesg-Protokoll ausgegeben zu werden. Anscheinend wird es zum Zeitpunkt von \ n
in den Puffer für dmesg ausgegeben.
printk druckt seinen Inhalt in einen Puffer im Speicher anstelle des Terminals. Der Puffer sieht aus wie ein Ringpuffer und wird überschrieben. dmesg druckt nur diesen Puffer. Es wird als Datei in cat / var / log / syslog
gespeichert. Bitte beachten Sie jedoch, dass es den Anschein hat, dass es mit einer angemessenen Häufigkeit geschrieben wird, anstatt sofort in diese Datei geschrieben zu werden. Im Falle eines Absturzes ist es möglich, dass das gewünschte Protokoll nicht geschrieben wurde.
Dies ist ein Beispiel für die Erstellung von MyModule.ko aus test01.c und test02.c. Erstellen Sie ein Makefile wie das folgende. Die zum Generieren von "MyModule.o" erforderliche .o-Datei ist in "MyModule-objs" angegeben. Daher muss das Präfix für "MyModule-objs" "MyModule" sein. Das resultierende Modul kann mit sudo insmod MyModule.ko
geladen werden.
CFILES = test01.c test02.c
obj-m := MyModule.o
MyModule-objs := $(CFILES:.c=.o)
all:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
Mit diesem Gefühl werde ich es nach und nach zusammenfassen. Dies ist meine Studiennotiz. Wenn Sie etwas falsch schreiben, lassen Sie es mich bitte wissen.
Recommended Posts