Bagaimana mengkompilasi modul kernel yang dapat dimuat tanpa mengkompilasi ulang kernel

20

Saya telah membaca sedikit tentang cara mengkompilasi modul kernel pada (dan untuk) Raspberry Pi, tapi saya masih belum cukup tahu mengapa itu tidak bekerja. Saya sudah bisa membangun modul, tetapi ia melaporkan Invalid module formatketika saya mencoba insmodhasilnya. Inilah proses yang saya ikuti. Pertama, sebagai root di bawah /rootsaya menjalankan skrip shell berikut:

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 

Beberapa baris pertama berasal dari http://lostindetails.com/blog/post/Compiling-a-kernel-module-for-the-raspberry-pi-2

Selebihnya saya menulis untuk mengotomatisasi lebih banyak proses. Setelah semua itu berjalan dengan sukses, saya memiliki sumber yang harus sama persis dengan kernel yang berjalan, konfigurasi untuk mencocokkan dan symlink. Ada beberapa arahan ulang dari lokasi web github (tampaknya sekarang https://raw.githubusercontent.com/ ) tetapi tidak ada kesalahan aktual.

Kemudian saya menjadi pipengguna default dan dalam direktori bernama /home/pi/projects/lkmSaya memiliki kode sumber ini untuk modul mainan yang sangat sederhana:

hello.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);

Akhirnya, saya membangun modul dengan Makefile ini

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

Akhirnya, saya mencoba memuat modul:

sudo insmod hello.ko

Namun hasilnya mengecewakan:

insmod: ERROR: tidak bisa memasukkan modul hello.ko: Format modul tidak valid

Detail yang mungkin relevan

Saya menggunakan jessieversi terbaru dari Raspbian di 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) 

Sayangnya, saya tidak yakin bagaimana cara mengatasi masalah ini lebih lanjut atau memperbaikinya. Ada petunjuk?

Edward
sumber
Saya mengumpulkan semua temuan dan pengalaman saya menjadi skrip, lihat github.com/x29a/kernel/blob/master/rpi/prepare.sh dan blogpost terkait blog.chris007.de/…
x29a

Jawaban:

23

Pertama-tama, pastikan Anda menggunakan header kernel yang tepat. Saya berasumsi bahwa header kernel dan kode sumber Anda lebih diperbarui daripada kernel yang Anda jalankan.

Coba lakukan apt-get update && apt-get upgradekemudian instal ulang modul. Jika masalah berlanjut, periksa tiga kali apakah header kernel Anda cocok dengan kernel Anda saat ini, kompilasi ulang lagi lalu coba instal.


Catatan: Saya menggunakan Jessie.

UPDATE: Jalankan ini sebagai root.

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

# Update the kernel!
rpi-update

Anda mungkin perlu me-reboot. Setelah itu, lanjutkan dengan perintah di bawah ini, masih menggunakan akun 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

Jika rpi-sourcemelempar kesalahan GCC (sesuatu tentang ketidakcocokan versi), tidak apa-apa asalkan versi GCC Anda saat ini lebih tinggi . Jalankan rpi-source --skip-gccbukannyarpi-source

Kemudian, lanjutkan dengan contoh Hello World Anda. Buat folder dan cdke dalamnya. Lalu, buat file.

mkdir hello
cd hello

File:

hello.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 (case-sensitive?)

obj-m := hello.o

Sekarang setelah Anda memiliki file, Anda dapat melanjutkan dan menjalankan perintah membangun Hello World seperti biasa:

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

Anda sekarang harus memeriksa dmesg. Baris terakhir harus dicetak Hello World :)dengan warna merah.

Jika Anda melakukannya, selamat. Anda baru saja membuat dan menginstal modul kernel.

Sekarang hapus menggunakan rmmod hello. dmesgseharusnya sekarang cetak yang Goodbye World!disorot dengan warna merah.

Sumber: 1 2 3

PNDA
sumber
Ketika Anda mengatakan untuk "memeriksa apakah header kernel Anda cocok dengan kernel Anda saat ini" bagaimana sebenarnya yang Anda maksud saya harus melakukannya?
Edward
@Edward diperbarui.
PNDA
@Edward Perhatikan bahwa ini adalah contoh hello world. Saya membuat modul Anda, tetapi saya menyadari itu sama. Satu-satunya perbedaan adalah bahwa kode Anda tidak memiliki highlight merah.
PNDA
@Edward Dalam kasus Anda, saya pikir mengikuti petunjuk sampai rpi-sourcebagian cukup. Anda dapat mencoba membangun milik Anda dari titik itu.
PNDA
5

Ada versi yang jauh lebih sederhana di sini, diuji dengan jessie dan stretch .

sudo apt-get install raspberrypi-kernel-headers

dan kemudian ketika file Anda ada di tempat:

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

Contoh

Buat hellodirektori, masuk ke dalam dan buat file-file berikut: hello.cdan Makefile.

Saya sarankan bekerja sebagai user biasa Anda, bukan root , hanya insmod, rmmoddan make modules_installperintah memerlukan akses root, dan diperlukan sudoditampilkan dalam perintah berikut.


hello.c (tidak berubah, file Anda)

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

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)   

Pemakaian

  • Build: make(dalam direktori yang sama dengan Makefile)
  • Uji
    • Masukkan modul dengan sudo insmod hello.ko
    • Temukan Hello World :)di outputdmesg
    • Lepaskan modul dengan sudo rmmod hello
    • Temukan Goodbye, world.int output daridmesg
  • Instal, ketika modul Anda berfungsi, sudo make modules_installakan menginstal modul di tempatnya, jadi modprobeakan berfungsi
pim
sumber
1
bekerja sangat baik untuk kernel yang diinstal melalui paket 'raspberrypi-kernel'. Bertentangan dengan deskripsi yang dikeluarkan oleh 'pandalion98' mengacu pada kernel yang diinstal dengan 'rpi-update'. Kedua metode ini saling eksklusif bukan?
sparkie
1
Saya pikir ini adalah jawaban yang valid karena OP (Edward) tidak pernah membicarakannya rpi-update, rpi-updatedisarankan dalam jawaban pandalion98
pim
@sparkie Pada saat posting, kernel masih belum terintegrasi ke dalam aptrepositori Raspbian , jika saya tidak salah. Memperbarui kernel berarti menjalankan rpi-updateskrip Hexxeh . Saat ini, memperbarui raspberrypi-kernelatau menjalankan rpi-updatemelakukan hal yang hampir sama.
PNDA
Adapun raspberrypi-kernel-headers, biasanya menginstal header kernel yang tidak cocok, dari pengalaman (header cenderung menjadi versi yang lebih baru dari kernel), maka dari itu mengapa saya memilih untuk "pergi manual".
PNDA
tampaknya ada beberapa perbedaan antara 'raspberrypi-kernel' dan 'rpi-update': yang satu menghasilkan '4.9.66+' yang lain di '4.9.59+' saat ini. Jadi saya pikir kita masih harus menangani kedua prosedur pembuatan secara terpisah
sparkie
2

dalam getKernel.shfile add

sudo modprobe configs

sebelum

zcat /proc/config.gz >.config

(sekarang dalam gambar rpi default /proc/config.gz tidak ada)

Igor Nikolaev
sumber