รวบรวมโมดูลเคอร์เนลที่โหลดได้โดยไม่มีการคอมไพล์เคอร์เนลใหม่


20

ฉันได้อ่านค่อนข้างน้อยเกี่ยวกับวิธีการรวบรวมโมดูลเคอร์เนลใน (และ) Raspberry Pi แต่ฉันยังคงไม่สามารถคิดออกว่าทำไมมันไม่ทำงาน ฉันสามารถสร้างโมดูลได้ แต่จะรายงานInvalid module formatเมื่อฉันลองinsmodผลลัพธ์ นี่คือกระบวนการที่ฉันติดตาม ครั้งแรกในฐานะ root ภายใต้/rootฉันดำเนินการเชลล์สคริปต์ต่อไปนี้:

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 

บรรทัดสองสามบรรทัดแรกมาจากhttp://lostindetails.com/blog/post/Compiling-a-kernel-module-for-the-raspberry-pi-2

ส่วนที่เหลือฉันเขียนเพื่อทำให้กระบวนการมากขึ้นโดยอัตโนมัติ เมื่อทั้งหมดนั้นทำงานได้สำเร็จฉันมีแหล่งที่มาที่ตรงกับเคอร์เนลที่กำลังทำงานการกำหนดค่าเพื่อจับคู่และ symlink มีการเปลี่ยนเส้นทางจากที่ตั้งเว็บ Github (เห็นได้ชัดว่าตอนนี้เป็นhttps://raw.githubusercontent.com/ ) แต่ไม่มีข้อผิดพลาดจริง

จากนั้นฉันก็กลายเป็นpiผู้ใช้เริ่มต้นและในไดเรกทอรีชื่อ/home/pi/projects/lkmฉันมีรหัสแหล่งที่มาสำหรับโมดูลของเล่นที่ง่ายมาก:

สวัสดีซี

#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 นี้

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

ในที่สุดฉันพยายามโหลดโมดูล:

sudo insmod hello.ko

อย่างไรก็ตามผลลัพธ์น่าผิดหวัง:

insmod: ข้อผิดพลาด: ไม่สามารถแทรกโมดูล hello.ko: รูปแบบโมดูลไม่ถูกต้อง

อาจมีรายละเอียดที่เกี่ยวข้อง

ฉันใช้jessieRaspbian รุ่นล่าสุดในปัจจุบันบน 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) 

น่าเสียดายที่ฉันไม่แน่ใจว่าจะแก้ไขปัญหานี้เพิ่มเติมหรือแก้ไขได้อย่างไร เบาะแสใด ๆ


ฉันรวบรวมสิ่งที่ค้นพบและประสบการณ์ทั้งหมดของฉันให้เป็นสคริปต์ดูgithub.com/x29a/kernel/blob/master/rpi/prepare.shและ blogpost blog.chris007.de/
x29a

คำตอบ:


23

ก่อนอื่นตรวจสอบให้แน่ใจว่าคุณใช้ส่วนหัวเคอร์เนลที่เหมาะสม ฉันสมมติว่าส่วนหัวเคอร์เนลและซอร์สโค้ดของคุณมีการปรับปรุงมากกว่าเคอร์เนลที่คุณใช้งานอยู่

ลองทำapt-get update && apt-get upgradeแล้วติดตั้งโมดูลอีกครั้ง หากปัญหายังคงมีอยู่ให้ตรวจสอบสามครั้งว่าส่วนหัวเคอร์เนลของคุณตรงกับเคอร์เนลปัจจุบันให้คอมไพล์อีกครั้งจากนั้นลองติดตั้ง


หมายเหตุ: ฉันใช้เจสซี่

ปรับปรุง: เรียกใช้เหล่านี้เป็นราก

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

# Update the kernel!
rpi-update

คุณอาจต้องรีบูต หลังจากนั้นดำเนินการตามคำสั่งด้านล่างโดยใช้บัญชีรูท

# 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

ถ้าrpi-sourceโยนข้อผิดพลาด GCC (สิ่งที่เกี่ยวกับการไม่ตรงกันรุ่น) ก็ไม่เป็นไรตราบใดที่รุ่น GCC ปัจจุบันของคุณสูง เรียกใช้rpi-source --skip-gccแทนrpi-source

จากนั้นดำเนินการกับตัวอย่าง Hello World ของคุณ สร้างโฟลเดอร์และcdเข้าไป จากนั้นสร้างไฟล์

mkdir hello
cd hello

ไฟล์:

สวัสดีซี

#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 (ต้องตรงตามตัวพิมพ์ใหญ่ - เล็ก)

obj-m := hello.o

ตอนนี้คุณมีไฟล์แล้วคุณสามารถไปข้างหน้าและเรียกใช้คำสั่งการสร้าง Hello World ปกติ:

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

dmesgตอนนี้คุณควรตรวจสอบ บรรทัดสุดท้ายควรพิมพ์ที่Hello World :)เน้นด้วยสีแดง

ถ้าคุณทำขอแสดงความยินดี คุณเพิ่งสร้างและติดตั้งโมดูลเคอร์เนล

rmmod helloตอนนี้เอามันออกไปใช้ dmesgควรพิมพ์Goodbye World!ไฮไลต์ด้วยสีแดง

แหล่งที่มา: 1 2 3


เมื่อคุณพูดว่า "ตรวจสอบว่าส่วนหัวเคอร์เนลของคุณตรงกับเคอร์เนลปัจจุบัน" คุณหมายถึงว่าฉันควรทำอย่างไร
Edward

@ ปรับปรุงแล้ว
PNDA

@Edward โปรดทราบว่านี่เป็นตัวอย่างสวัสดีโลก ฉันสร้างโมดูลของคุณ แต่ฉันรู้ว่ามันเหมือนกัน ข้อแตกต่างคือรหัสของคุณไม่มีไฮไลต์สีแดง
PNDA

@Edward ในกรณีของคุณฉันคิดว่าทำตามคำแนะนำจนถึงrpi-sourceส่วนที่เพียงพอ คุณสามารถลองสร้างของคุณเองจากจุดนั้น
PNDA

5

มีรุ่นที่ง่ายมากที่นี่การทดสอบเกี่ยวกับเจสซีและยืด

sudo apt-get install raspberrypi-kernel-headers

แล้วเมื่อไฟล์ของคุณอยู่ในสถานที่:

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

ตัวอย่าง

สร้างhelloไดเรกทอรีไปภายในและสร้างไฟล์ต่อไปนี้: และhello.cMakefile

ผมขอแนะนำให้ทำงานเป็นผู้ใช้ปกติของคุณไม่รากเท่านั้นinsmod, rmmodและmake modules_installคำสั่งที่ต้องใช้สิทธิ์รากและความจำเป็นที่sudoจะปรากฏในคำสั่งดังต่อไปนี้


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

Makefile (เปลี่ยนแล้ว)

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)   

การใช้

  • สร้าง: make(ในไดเรกทอรีเดียวกับ Makefile)
  • ทดสอบ
    • ใส่โมดูลด้วย sudo insmod hello.ko
    • ค้นหาHello World :)ในผลลัพธ์ของdmesg
    • ลบโมดูลด้วย sudo rmmod hello
    • ค้นหาGoodbye, world.ผลลัพธ์ของ intdmesg
  • ติดตั้งเมื่อโมดูลของคุณทำงานsudo make modules_installจะติดตั้งโมดูลที่เป็นของมันดังนั้นmodprobeจะทำงาน

1
ทำงานได้ดีมากสำหรับเมล็ดที่ติดตั้งโดยใช้แพคเกจ 'raspberrypi-kernel' ตรงกันข้ามกับคำอธิบายที่ออกโดย 'pandalion98' หมายถึงเมล็ดที่ติดตั้งโดยใช้ 'rpi-update' ทั้งสองวิธีต่างก็มีสิทธิพิเศษร่วมกันใช่ไหม?
sparkie

1
ผมคิดว่านี่เป็นคำตอบที่ถูกต้องตั้งแต่ OP (เอ็ดเวิร์ด) ไม่เคยพูดคุยเกี่ยวกับrpi-update, rpi-updateได้รับการแนะนำใน pandalion98 ของคำตอบ
PIM

@sparkie ในขณะที่ทำการโพสต์เคอร์เนลยังคงไม่ถูกรวมเข้ากับที่aptเก็บของ Raspbian ถ้าฉันไม่เข้าใจผิด การอัพเดตเคอร์เนลหมายถึงการรันrpi-updateสคริปต์ของ Hexxeh ทุกวันนี้การอัพเดทraspberrypi-kernelหรือการทำงานก็rpi-updateทำแบบเดียวกัน
PNDA

สำหรับraspberrypi-kernel-headersมันมักจะติดตั้งส่วนหัวเคอร์เนลไม่ตรงกันจากประสบการณ์ (ส่วนหัวมีแนวโน้มที่จะเป็นรุ่นใหม่กว่าเคอร์เนล) ดังนั้นทำไมฉันเลือกที่จะ "ไปด้วยตนเอง"
PNDA

ดูเหมือนจะมีความแตกต่างระหว่าง 'raspberrypi-kernel' และ 'rpi-update': ผลลัพธ์หนึ่งใน '4.9.66+' และอื่น ๆ ใน '4.9.59+' ในขณะนี้ ดังนั้นฉันคิดว่าเรายังต้องจัดการขั้นตอนการสร้างทั้งสองแยกต่างหาก
sparkie

2

ในการgetKernel.shเพิ่มไฟล์

sudo modprobe configs

ก่อน

zcat /proc/config.gz >.config

(ตอนนี้อยู่ในภาพ rpi เริ่มต้น /proc/config.gz ไม่มีอยู่)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.