Come compilare un modulo kernel caricabile senza ricompilare il kernel


20

Ho letto un po 'su come compilare un modulo del kernel su (e per) il Raspberry Pi, ma non riesco ancora a capire perché non funziona. Sono stato in grado di costruire il modulo, ma segnala Invalid module formatquando provo insmodil risultato. Ecco il processo che ho seguito. Innanzitutto, come root sotto /rootho eseguito il seguente script di shell:

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 

Le prime righe sono da http://lostindetails.com/blog/post/Compiling-a-kernel-module-for-the-raspberry-pi-2

Il resto l'ho scritto per automatizzare maggiormente il processo. Una volta che tutto ciò funziona correttamente, ho il sorgente che dovrebbe corrispondere esattamente al kernel in esecuzione, alla configurazione da abbinare e ad un link simbolico. Ci sono stati alcuni reindirizzamenti dalla posizione web di github (apparentemente ora è https://raw.githubusercontent.com/ ) ma nessun errore reale.

Poi divento l' piutente predefinito e in una directory chiamata /home/pi/projects/lkmho questo codice sorgente per un modulo giocattolo molto semplice:

Ciao 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);

Infine, costruisco il modulo con questo 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

Infine, provo a caricare il modulo:

sudo insmod hello.ko

Il risultato, tuttavia, è deludente:

insmod: ERRORE: impossibile inserire il modulo hello.ko: formato del modulo non valido

Dettagli possibilmente rilevanti

Sto usando l'ultima jessieversione di Raspbian su un 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) 

Sfortunatamente, non sono sicuro di come risolvere ulteriormente questo problema o risolverlo. Qualche indizio?


Ho raccolto tutte le mie scoperte ed esperienze in uno script, vedi github.com/x29a/kernel/blob/master/rpi/prepare.sh e il relativo blogpost blog.chris007.de/…
x29a

Risposte:


23

Prima di tutto, assicurati di usare le intestazioni del kernel appropriate. Presumo che le intestazioni del kernel e il codice sorgente siano più aggiornati rispetto al kernel in esecuzione.

Prova a fare un apt-get update && apt-get upgradequindi reinstallare il modulo. Se il problema persiste, controllare tre volte che le intestazioni del kernel corrispondano al kernel corrente, ricompilare nuovamente quindi provare a installare.


Nota: sto usando Jessie.

AGGIORNAMENTO: eseguili come root.

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

# Update the kernel!
rpi-update

Potrebbe essere necessario riavviare. Successivamente, procedi con i comandi seguenti, usando ancora l'account root.

# 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

Se rpi-sourcegenera un errore GCC (qualcosa a causa di una mancata corrispondenza della versione), va bene finché la tua versione GCC attuale è superiore . Esegui rpi-source --skip-gccinvece dirpi-source

Quindi, procedi con il tuo esempio Hello World. Crea la cartella e cdin essa. Quindi, crea i file.

mkdir hello
cd hello

File:

Ciao 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 (sensibile al maiuscolo / minuscolo?)

obj-m := hello.o

Ora che hai i tuoi file, puoi andare avanti ed eseguire i soliti comandi di build di Hello World:

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

Ora dovresti controllare dmesg. L'ultima riga dovrebbe essere Hello World :)evidenziata in rosso.

Se lo fai, congratulazioni. Hai appena creato e installato un modulo kernel.

Ora rimuovilo usando rmmod hello. dmesgdovrebbe ora stampare Goodbye World!evidenziato in rosso.

Fonti: 1 2 3


Quando dici di "verificare che le intestazioni del tuo kernel corrispondano al tuo kernel corrente" come intendi esattamente che dovrei farlo?
Edward

@Edward aggiornato.
PNDA

@Edward Prendi nota che questo è l'esempio ciao mondo. Ho creato il tuo modulo, ma mi sono reso conto che è lo stesso. L'unica differenza è che il tuo codice non ha l'evidenziazione rossa.
PNDA

@Edward Nel tuo caso, penso che seguire le istruzioni fino a quando la rpi-sourceparte è sufficiente. Puoi provare a costruire il tuo da quel punto.
PNDA

5

Esiste una versione molto più semplice qui, testata su jessie e stretch .

sudo apt-get install raspberrypi-kernel-headers

e poi quando i tuoi file sono a posto:

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

Esempio

Creare la hellodirectory, andare all'interno e creare i seguenti file: hello.ce Makefile.

Mi raccomando di lavorare come utente normale, non radice , solo insmod, rmmode make modules_installcomandi richiedono i permessi di root, e la necessaria sudoè mostrata nelle seguenti comandi.


ciao.c (invariato, il tuo file)

#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 (modificato)

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)   

uso

  • Build: make(nella stessa directory del Makefile)
  • Test
    • Inserire il modulo con sudo insmod hello.ko
    • Trova Hello World :)nell'output didmesg
    • Rimuovere il modulo con sudo rmmod hello
    • Trova Goodbye, world.int l'output didmesg
  • Installa, quando il tuo modulo funziona, sudo make modules_installinstallerà il modulo a cui appartiene, quindi modprobefunzionerà.

1
funziona molto bene con i kernel installati tramite il pacchetto 'raspberrypi-kernel'. Contrariamente a quanto descritto da 'pandalion98' si riferisce ai kernel installati mediante 'rpi-update'. Entrambi i metodi si escludono a vicenda, giusto?
Sparkie il

1
Penso che questa sia una risposta valida poiché OP (Edward) non ne ha mai parlato rpi-update, è rpi-updatestato suggerito nella risposta del pandalion98
pim

@sparkie Al momento della pubblicazione, il kernel non era ancora integrato nel aptrepository di Raspbian , se non sbaglio. Aggiornare il kernel significava eseguire lo rpi-updatescript di Hexxeh . In questi giorni, l'aggiornamento raspberrypi-kernelo l'esecuzione rpi-updatefanno praticamente la stessa cosa.
PNDA

Per quanto riguarda raspberrypi-kernel-headers, di solito installa le intestazioni del kernel non corrispondenti, per esperienza (le intestazioni tendono ad essere una versione più recente rispetto al kernel), quindi perché ho optato per "andare manuale".
PNDA

sembra esserci qualche differenza tra 'raspberrypi-kernel' e 'rpi-update': l'uno risulta in '4.9.66+' l'altro in '4.9.59+' in questo momento. Quindi penso che dobbiamo ancora gestire entrambe le procedure di costruzione separatamente
sparkie

2

nel getKernel.shfile aggiungere

sudo modprobe configs

prima

zcat /proc/config.gz >.config

(ora nell'immagine rpi predefinita /proc/config.gz non esiste)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.