我已经读了很多关于如何在Raspberry Pi上编译内核模块的知识,但是我仍然不太清楚为什么它不能工作。我已经能够构建模块,但是当我尝试对结果进行报告时,它将报告Invalid module format。这是我遵循的过程。首先,以insmod下的root用户身份执行以下shell脚本:

getKernel.sh

#! /usr/bin/bash
FIRMWARE_HASH=$(zgrep "* firmware as of" /usr/share/doc/raspberrypi-bootloader/changelog.Debian.gz | head -1 | awk '{ print  }')
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

我写的其余部分用于自动完成该过程。一旦所有这些都成功运行,我就会获得与运行中的内核完全匹配的源,要匹配的配置以及一个符号链接。从github位置进行了一些重定向(显然现在是https://raw.githubusercontent.com/),但是没有实际错误。

然后我成为默认的/root用户,并位于名为pi的目录中我有一个非常简单的玩具模块的源代码:

hello.c

 /home/pi/projects/lkm 


最后,我使用此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:无效的模块格式


可能相关的详细信息

我正在Raspberry Pi2上使用最新版本的Raspbian #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);

$ 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和相关博客文章blog.chris007.de/…

#1 楼

首先,请确保使用正确的内核头文件。我假设您的内核标头和源代码比您正在运行的内核更新得多。

尝试执行apt-get update && apt-get upgrade,然后重新安装模块。如果问题仍然存在,请三遍检查您的内核标头是否与当前内核匹配,再次重新编译,然后尝试安装。


注意:我正在使用Jessie。

更新:
以root用户身份运行它们。

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

# Update the kernel!
rpi-update


您可能需要重新启动。之后,继续使用下面的命令,仍然使用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


如果rpi-source抛出GCC错误(有关版本不匹配的信息),则可以因为您当前的GCC版本更高。运行rpi-source --skip-gcc而不是rpi-source

,然后继续执行您的Hello World示例。创建文件夹,然后将其插入。然后,创建文件。

mkdir hello
cd hello



文件:

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(区分大小写?)

obj-m := hello.o



现在您已经有了文件,可以继续运行常规文件了。 Hello World构建命令:

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


您现在应该检查cd。最后一行应打印以红色突出显示的dmesg

,恭喜。您刚刚制作并安装了内核模块。

现在使用Hello World :)删除它。 rmmod hello现在应该以红色突出显示dmesg

来源:1 2 3

评论


当您说“检查您的内核标头是否与当前内核匹配”时,您是什么意思呢?

–爱德华
16年1月2日,下午1:54

@Edward已更新。

–PNDA
16年1月2日在8:16

@Edward请注意,这是您好世界的示例。我构建了您的模块,但我意识到它是相同的。唯一的区别是您的代码没有红色突出显示。

–PNDA
16 Jan 2'在8:47



@Edward在您的情况下,我认为按照说明进行操作,直到rpi-source部分足够为止。您可以尝试从那时开始构建自己的产品。

–PNDA
16年1月2日在8:51

#2 楼

这里有一个更简单的版本,已在jessie和Stretch上进行了测试。

sudo apt-get install raspberrypi-kernel-headers

,然后在放置文件时:

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

示例

创建hello目录,进入并创建以下文件
hello.cMakefile

我建议您以普通用户而非root用户,只有insmodrmmodmake modules_install命令需要root权限,并且必要的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. int dmesg的输出




安装, e如果您的模块正在运行,则sudo make modules_install将在其所属的模块中进行安装,因此modprobe将会运行。


评论


对于通过“ raspberrypi-kernel”软件包安装的内核,效果很好。与“ pandalion98”发布的描述相反,它是指通过“ rpi-update”安装的内核。两种方法互斥吧?

–sparkie
17年12月6日在9:38



我认为这是一个有效的答案,因为OP(Edward)从未谈论过rpi-update,在pandalion98的答案中建议使用rpi-update

– Pim
17年12月6日在9:44

@sparkie在发布时,如果我没有记错的话,内核仍未集成到Raspbian的apt仓库中。更新内核意味着运行Hexxeh的rpi-update脚本。如今,更新raspberrypi-kernel或运行rpi-update几乎是一回事。

–PNDA
2017年12月7日在2:22



至于raspberrypi-kernel-headers,它通常会根据经验安装不匹配的内核头文件(这些头文件往往是比内核更新的版本),因此,为什么选择“手动”。

–PNDA
17年7月7日在2:25

“ raspberrypi-kernel”和“ rpi-update”之间似乎有些区别:此刻一个结果为“ 4.9.66+”,另一个结果为“ 4.9.59+”。所以我认为我们仍然必须分别处理这两个构建过程

–sparkie
17-12-7在6:43



#3 楼

getKernel.sh文件中添加

sudo modprobe configs


之前

zcat /proc/config.gz >.config


(现在在默认的rpi映像/ proc / config中。 gz不存在)