Wie kompiliere ich ein ladbares Kernelmodul, ohne den Kernel neu zu kompilieren?

20

Ich habe einiges darüber gelesen, wie man ein Kernelmodul auf (und für) den Raspberry Pi kompiliert, aber ich bin immer noch nicht in der Lage herauszufinden, warum es nicht funktioniert. Ich konnte das Modul erstellen, aber es meldet sich, Invalid module formatwenn ich insmoddas Ergebnis versuche . Hier ist der Prozess, dem ich gefolgt bin. Zuerst habe /rootich als root unter das folgende Shell-Skript ausgeführt:

getKernel.sh

#! /usr/bin/bash
FIRMWARE_HASH=$(zgrep "* firmware as of" /usr/share/doc/raspberrypi-bootloader/changelog.Debian.gz | head -1 | awk '{ print $5 }')
KERNEL_HASH=$(wget https://raw.githubusercontent.com/raspberrypi/firmware/$FIRMWARE_HASH/extra/git_hash -O -)
git clone https://github.com/raspberrypi/linux 
cd linux
git checkout $KERNEL_HASH
wget https://raw.githubusercontent.com/raspberrypi/firmware/$FIRMWARE_HASH/extra/Module.symvers 
zcat /proc/config.gz >.config
make oldconfig
make modules_prepare
ln -s /root/linux /lib/modules/$(uname -r)/build 

Die ersten Zeilen stammen von http://lostindetails.com/blog/post/Compiling-a-kernel-module-for-the-raspberry-pi-2

Den Rest habe ich geschrieben, um mehr von dem Prozess zu automatisieren. Sobald das alles erfolgreich läuft, habe ich die Quelle, die genau zum laufenden Kernel passen sollte, die passende Konfiguration und einen Symlink. Es gab einige Weiterleitungen von der Github-Website (anscheinend ist es jetzt https://raw.githubusercontent.com/ ), aber keine tatsächlichen Fehler.

Dann werde ich zum Standardbenutzer piund habe in einem Verzeichnis mit dem Namen /home/pi/projects/lkmfolgenden Quellcode für ein sehr einfaches Spielzeugmodul:

Hallo c

#include <linux/init.h>  
#include <linux/kernel.h> 
#include <linux/module.h>

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Do-nothing test driver");
MODULE_VERSION("0.1");

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

static void __exit hello_exit(void){
   printk(KERN_INFO "Goodbye, world.\n");
}

module_init(hello_init);
module_exit(hello_exit);

Zum Schluss baue ich das Modul mit diesem Makefile

Makefile

MODSRC=/home/pi/projects/lkm
obj-m+=hello.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=${MODSRC} modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=${MODSRC} clean

Zum Schluss versuche ich das Modul zu laden:

sudo insmod hello.ko

Das Ergebnis ist jedoch enttäuschend:

insmod: ERROR: Modul konnte nicht eingefügt werden hello.ko: Ungültiges Modulformat

Möglicherweise relevante Details

Ich verwende die aktuellste jessieVersion von Raspbian auf einem Raspberry Pi2.

$ uname --kernel-release --kernel-version
4.1.13-v7+ #826 SMP PREEMPT Fri Nov 13 20:19:03 GMT 2015
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/4.9/lto-wrapper
Target: arm-linux-gnueabihf
Configured with: ../src/configure -v --with-pkgversion='Raspbian 4.9.2-10' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-armhf/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-armhf --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-armhf --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
Thread model: posix
gcc version 4.9.2 (Raspbian 4.9.2-10) 

Leider bin ich mir nicht sicher, wie ich das Problem weiter beheben oder beheben soll. Irgendwelche Hinweise?

Edward
quelle
Ich habe alle meine Erkenntnisse und Erfahrungen in einem Skript zusammengefasst, siehe github.com/x29a/kernel/blob/master/rpi/prepare.sh und den dazugehörigen Blogpost blog.chris007.de/…
x29a

Antworten:

23

Stellen Sie zunächst sicher, dass Sie die richtigen Kernel-Header verwenden. Ich gehe davon aus, dass Ihre Kernel-Header und der Quellcode aktueller sind als der Kernel, den Sie ausführen.

Versuchen Sie, apt-get update && apt-get upgradedas Modul erneut zu installieren. Wenn das Problem weiterhin besteht, überprüfen Sie dreimal, ob Ihre Kernel-Header mit Ihrem aktuellen Kernel übereinstimmen, kompilieren Sie erneut und versuchen Sie dann, ihn zu installieren.


Hinweis: Ich benutze Jessie.

UPDATE: Führen Sie diese als root aus.

# The usual update routine
apt-get update -y
apt-get upgrade -y

# Update the kernel!
rpi-update

Möglicherweise müssen Sie neu starten. Fahren Sie danach mit den folgenden Befehlen fort und verwenden Sie weiterhin das Root-Konto.

# Get rpi-source
sudo wget https://raw.githubusercontent.com/notro/rpi-source/master/rpi-source -O /usr/bin/rpi-source

# Make it executable
sudo chmod +x /usr/bin/rpi-source

# Tell the update mechanism that this is the latest version of the script
/usr/bin/rpi-source -q --tag-update

# Get the kernel files thingies.
rpi-source

Wenn rpi-sourceein GCC-Fehler auftritt (etwas über eine Versionsinkongruenz), ist dies in Ordnung , solange Ihre aktuelle GCC-Version höher ist . Laufen rpi-source --skip-gccstattrpi-source

Fahren Sie dann mit Ihrem Hello World-Beispiel fort. Erstellen Sie den Ordner und cdhinein. Erstellen Sie dann die Dateien.

mkdir hello
cd hello

Dateien:

Hallo c

#include <linux/module.h>
#include <linux/kernel.h>

int hello_init(void)
{
    pr_alert("Hello World :)\n");
    return 0;
}
void hello_exit(void)
{
    pr_alert("Goodbye World!\n");
}
module_init(hello_init);
module_exit(hello_exit);

Makefile (Groß- und Kleinschreibung beachten ?)

obj-m := hello.o

Jetzt, da Sie Ihre Dateien haben, können Sie die üblichen Hello World-Build-Befehle ausführen:

make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
insmod hello.ko

Sie sollten jetzt überprüfen dmesg. Die letzte Zeile sollte Hello World :)rot hervorgehoben werden.

Dann herzlichen Glückwunsch. Sie haben gerade ein Kernelmodul erstellt und installiert.

Entfernen Sie es nun mit rmmod hello. dmesgsollte jetzt Goodbye World!rot hervorgehoben drucken .

Quellen: 1 2 3

PNDA
quelle
Wenn Sie sagen: "Überprüfen Sie, ob Ihre Kernel-Header mit Ihrem aktuellen Kernel übereinstimmen", wie genau soll ich das tun?
Edward
@ Edward aktualisiert.
PNDA
@Edward Beachten Sie, dass dies das Beispiel für "Hallo Welt" ist. Ich habe Ihr Modul gebaut, aber mir ist klar geworden, dass es dasselbe ist. Der einzige Unterschied besteht darin, dass Ihr Code nicht die rote Markierung aufweist.
PNDA
@Edward In deinem Fall denke ich folge den Anweisungen bis das rpi-sourceTeil ausreicht. Sie können versuchen, Ihre von diesem Punkt aus aufzubauen.
PNDA
5

Hier gibt es eine viel einfachere Version, die auf Jessie und Stretch getestet wurde .

sudo apt-get install raspberrypi-kernel-headers

und dann, wenn Ihre Dateien vorhanden sind:

make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

Beispiel

Erstellen Sie das helloVerzeichnis, gehen Sie hinein und erstellen Sie die folgenden Dateien: hello.cund Makefile.

Ich empfehle als Ihre normalen Benutzer, nicht als root , nur insmod, rmmodund make modules_installBefehle erfordern root - Rechte, und die erforderlichen sudoist in den folgenden Befehlen angezeigt.


hallo.c (unverändert, deine Datei)

#include <linux/init.h>  
#include <linux/kernel.h> 
#include <linux/module.h>

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Do-nothing test driver");
MODULE_VERSION("0.1");

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

static void __exit hello_exit(void){
   printk(KERN_INFO "Goodbye, world.\n");
}

module_init(hello_init);
module_exit(hello_exit);

Makefile (geändert)

obj-m+=hello.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(pwd) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(pwd) clean

modules_install: all
    $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
    $(DEPMOD)   

Verwendung

  • Build: make(im selben Verzeichnis wie das Makefile)
  • Prüfung
    • Setzen Sie das Modul mit ein sudo insmod hello.ko
    • Finden Sie Hello World :)in der Ausgabe vondmesg
    • Entfernen Sie das Modul mit sudo rmmod hello
    • Finde Goodbye, world.int die Ausgabe vondmesg
  • Installieren, wenn Ihr Modul funktioniert, sudo make modules_installinstalliert das Modul dort, wo es hingehört, modprobeund funktioniert auch.
pim
quelle
1
funktioniert sehr gut für Kernel, die mit dem Paket 'raspberrypi-kernel' installiert wurden. Im Gegensatz dazu bezieht sich die Beschreibung von 'pandalion98' auf Kernel, die mit 'rpi-update' installiert wurden. Beide Methoden schließen sich gegenseitig aus, oder?
Sparkie
1
Ich denke, dies ist eine gültige Antwort, da OP (Edward) nie darüber gesprochen hat rpi-update, rpi-updatewurde in der Antwort von
pandalion98
@sparkie Zum Zeitpunkt der Veröffentlichung war der Kernel immer noch nicht in Raspbians aptRepository integriert, wenn ich mich nicht irre. Das Aktualisieren des Kernels bedeutete, Hexxehs rpi-updateSkript auszuführen . Heutzutage machen Aktualisierungen raspberrypi-kerneloder das Ausführen rpi-updateso ziemlich dasselbe.
PNDA
Was raspberrypi-kernel-headers, installiert es in der Regel nicht übereinstimmen Kernel - Header, aus Erfahrung (die Header sind in der Regel eine neuere Version als der Kernel sein), warum also entschied ich mich auf „manuell gehen“.
PNDA
Es scheint einen Unterschied zwischen 'raspberrypi-kernel' und 'rpi-update' zu geben: das eine ergibt '4.9.66+', das andere '4.9.59+'. Ich denke also, wir müssen beide Build-Prozeduren immer noch separat behandeln
sparkie
2

in getKernel.shDatei hinzufügen

sudo modprobe configs

Vor

zcat /proc/config.gz >.config

(jetzt im Standard rpi image /proc/config.gz nicht vorhanden)

Igor Nikolaev
quelle