Cách biên dịch một mô-đun hạt nhân có thể tải mà không cần biên dịch lại kernel


20

Tôi đã đọc khá nhiều về cách biên dịch mô-đun hạt nhân trên (và cho) Raspberry Pi, nhưng tôi vẫn không thể hiểu tại sao nó không hoạt động. Tôi đã có thể xây dựng mô-đun, nhưng nó báo cáo Invalid module formatkhi tôi cố gắng để insmodkết quả. Đây là quá trình tôi làm theo. Đầu tiên, với quyền root /roottôi đã thực thi kịch bản shell sau:

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 

Một vài dòng đầu tiên là từ http://lostindetails.com/blog/post/Compiling-a-kernel-module-for-the-raspberry-pi-2

Phần còn lại tôi đã viết để tự động hóa nhiều hơn của quá trình. Khi tất cả điều đó chạy thành công, tôi có nguồn phù hợp chính xác với kernel đang chạy, cấu hình phù hợp và symlink. Có một số chuyển hướng từ vị trí web github (dường như bây giờ là https://raw.githubusercontent.com/ ) nhưng không có lỗi thực tế.

Sau đó, tôi trở thành pingười dùng mặc định và trong một thư mục có tên /home/pi/projects/lkmtôi có mã nguồn này cho một mô-đun đồ chơi rất đơn giản:

chào 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);

Cuối cùng, tôi xây dựng mô-đun với Makefile này

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

Cuối cùng, tôi cố gắng tải mô-đun:

sudo insmod hello.ko

Tuy nhiên, kết quả thật đáng thất vọng:

insmod: ERROR: không thể chèn mô-đun hello.ko: Định dạng mô-đun không hợp lệ

Chi tiết có thể liên quan

Tôi đang sử dụng jessiephiên bản mới nhất của Raspbian trên 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) 

Thật không may, tôi không chắc chắn làm thế nào để khắc phục sự cố này hoặc sửa nó. Bất kì manh mối nào?


Tôi đã tổng hợp tất cả những phát hiện và kinh nghiệm của mình vào một kịch bản, xem github.com/x29a/kernel/blob/master/rpi/prepare.sh và blogpost blog có liên quan.chris007.de/ tựa
x29a

Câu trả lời:


23

Trước hết, hãy chắc chắn rằng bạn sử dụng các tiêu đề kernel thích hợp. Tôi giả sử rằng các tiêu đề kernel và mã nguồn của bạn được cập nhật nhiều hơn kernel bạn đang chạy.

Hãy thử làm một apt-get update && apt-get upgradesau đó cài đặt lại mô-đun. Nếu sự cố vẫn còn, hãy kiểm tra ba lần xem các tiêu đề kernel của bạn có khớp với kernel hiện tại của bạn không, biên dịch lại sau đó thử cài đặt.


Lưu ý: Tôi đang sử dụng Jessie.

CẬP NHẬT: Chạy chúng như root.

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

# Update the kernel!
rpi-update

Bạn có thể cần phải khởi động lại. Sau đó, tiến hành các lệnh bên dưới, vẫn sử dụng tài khoản 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

Nếu rpi-sourceném lỗi GCC (một cái gì đó không phù hợp với phiên bản), thì miễn là phiên bản GCC hiện tại của bạn cao hơn . Chạy rpi-source --skip-gccthay vìrpi-source

Sau đó, tiến hành với ví dụ Hello World của bạn. Tạo thư mục và cdvào nó. Sau đó, tạo các tập tin.

mkdir hello
cd hello

Các tập tin:

chào 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 (phân biệt chữ hoa chữ thường?)

obj-m := hello.o

Bây giờ bạn đã có tệp của mình, bạn có thể tiếp tục và chạy các lệnh xây dựng Hello World thông thường:

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

Bây giờ bạn nên kiểm tra dmesg. Dòng cuối cùng nên in Hello World :)nổi bật màu đỏ.

Nếu bạn làm, xin chúc mừng. Bạn vừa thực hiện và cài đặt một mô-đun hạt nhân.

Bây giờ loại bỏ nó bằng cách sử dụng rmmod hello. dmesgBây giờ nên in Goodbye World!nổi bật màu đỏ.

Nguồn: 1 2 3


Khi bạn nói "kiểm tra xem các tiêu đề kernel của bạn có khớp với kernel hiện tại của bạn không" ý bạn chính xác là tôi nên làm điều đó như thế nào?
Edward

@Edward cập nhật.
PNDA

@Edward Hãy lưu ý rằng đây là ví dụ xin chào thế giới. Tôi đã xây dựng mô-đun của bạn, nhưng tôi nhận ra nó giống nhau. Sự khác biệt duy nhất là mã của bạn không có màu đỏ nổi bật.
PNDA

@Edward Trong trường hợp của bạn, tôi nghĩ làm theo hướng dẫn cho đến khi rpi-sourcephần đó là đủ. Bạn có thể thử xây dựng của bạn từ thời điểm đó.
PNDA

5

Có một phiên bản đơn giản hơn nhiều ở đây, được thử nghiệm trên jessiekéo dài .

sudo apt-get install raspberrypi-kernel-headers

và sau đó khi tệp của bạn được đặt đúng chỗ:

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

Thí dụ

Tạo hellothư mục, vào bên trong và tạo các tệp sau: hello.cMakefile.

Tôi khuyên bạn nên làm việc như người dùng bình thường của bạn, không rễ , chỉ insmod, rmmodmake modules_installlệnh yêu cầu quyền root, và cần thiết sudođược trình bày trong các lệnh sau.


hello.c (không thay đổi, tập tin của bạn)

#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 (đã thay đổi)

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)   

Sử dụng

  • Build: make(trong cùng thư mục với Makefile)
  • Kiểm tra
    • Chèn mô-đun với sudo insmod hello.ko
    • Tìm Hello World :)trong đầu ra củadmesg
    • Hủy bỏ mô-đun với sudo rmmod hello
    • Tìm Goodbye, world.int đầu ra củadmesg
  • Cài đặt, khi mô-đun của bạn hoạt động, sudo make modules_installsẽ cài đặt mô-đun nơi nó thuộc về, vì vậy modprobesẽ hoạt động.

1
hoạt động rất tốt đối với các nhân được cài đặt bằng gói 'raspberrypi-kernel'. Trái ngược với mô tả do 'pandalion98' đưa ra đề cập đến các hạt nhân được cài đặt bằng 'rpi-update'. Cả hai phương pháp đều loại trừ lẫn nhau phải không?
Sparkie

1
Tôi nghĩ rằng đây là một câu trả lời hợp lệ vì OP (Edward) không bao giờ nói về rpi-update, rpi-updateđã được đề xuất trong câu trả lời của pandalion98
pim

@sparkie Tại thời điểm đăng bài, kernel vẫn chưa được tích hợp vào aptkho lưu trữ của Raspbian , nếu tôi không nhầm. Cập nhật kernel có nghĩa là chạy rpi-updatetập lệnh của Hexxeh . Ngày nay, cập nhật raspberrypi-kernelhoặc chạy rpi-updatelàm khá nhiều điều tương tự.
PNDA

Về phần raspberrypi-kernel-headers, nó thường cài đặt các tiêu đề kernel không khớp, từ kinh nghiệm (các tiêu đề có xu hướng là phiên bản mới hơn so với kernel), do đó tôi chọn "hướng dẫn sử dụng".
PNDA

dường như có một số khác biệt giữa 'raspberrypi-kernel' và 'rpi-update': kết quả là '4.9.66+' khác trong '4.9.59+' tại thời điểm này. Vì vậy, tôi nghĩ rằng chúng ta vẫn phải xử lý cả hai quy trình xây dựng một cách riêng biệt
sparkie

2

trong getKernel.shtập tin thêm

sudo modprobe configs

trước

zcat /proc/config.gz >.config

(hiện tại không có hình ảnh rpi /proc/config.gz mặc định)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.