为Raspberry Pi 2编译内核模块

2015-04-21更新:原始的rpi-source项目已经由PeterOGB 接手维护,所以无须再用我下文中提到的我改过的rpi-source脚本,直接用原始的就可以了。其它文中提到的背景知识都仍然有效。

即把第一个命令改为:
$ wget https://raw.githubusercontent.com/notro/rpi-source/master/rpi-source
&& chmod a+x rpi-source

2015-07-29更新:Raspbian的内核版本已经升级到4.x,rpi-source还不能正确处理,需要进行以下额外的工作:

1. rpi-source需要获取的/proc/config.gz默认不存在了,需要额外加载模块来实现:

$ sudo modprobe configs

2. rpi-source在4.x内核下无法正确检测gcc版本,运行rpi-source时请加–skip-gcc选项。


 

在Linux下使用“360随身WiFi 2”》一文的留言区中,曾经有人问过,为什么编译出来的模块insmod/modprobe时报“Exec format error”,我不假思索的回复,请他检查编译模块时用的内核头文件与实际运行的内核是否完全匹配。这个答案倒也不算错,不过其实并没有解决问题,因为遇到的这个问题的人一般都已经用了“正确”的方式去编译他的模块,就算再重新做几遍,还是会遇到一样的问题。

最近我给Raspberry Pi 2编译内核模块时,遇到了一样的问题,花了很多时间才真正解决,在这里总结一下。以下描述的方法和内容,对Raspberry Pi (A/A+/B/B+)和Raspberry Pi 2都适用。

准备编译模块需要的内核树的方法(适用于Raspbian):

1. 下载我改过的rpi-source脚本
$ wget https://raw.githubusercontent.com/lifanxi/rpi-source/master/rpi-source
&& chmod a+x rpi-source

2. 运行rpi-source
$ ./rpi-source

3. 好了,可以进入模块源代码的目录进行模块编译了。

疑难排解:

1. rpi-source报gcc版本不一致

截止2015-03-12,Raspbian最新的内核是用gcc 4.8编译的(可以查看/proc/version确认),而Raspbian中自带的gcc是4.6的,需要升级到4.8。因为4.8的gcc已经backport了,所以可以直接sudo apt-get install gcc-4.8 g++-4.8,然后用update-alternatives设置优先级即可[1]。

2. 如果用rpi-source –skip-gcc忽略gcc版本检查,并强行用4.6的gcc会编译模块怎么样?

我的试验结果是模块可以编译,但在加载模块时会造成kernel oops,然后再用insmod/modprobe/rmmod/lsmod等命令时会挂住,只能重启解决。如果你编的模块是会自动加载的,重启前先把它删掉,不然启动时就会挂住。

3. rpi-source无法正常下载内核代码或Modules.symvers文件

有可能是你的内核版本太老,rpi-source只支持Raspberry Pi 3.10.37以上的内核。对于Raspberry Pi 2,它只支持3.18.6以上的内核。解决办法是先运行sudo rpi-update更新内核和固件,更新后请重启系统,然后再重新运行rpi-source。

4. 编译模块时报找不到arch/armv6l或arch/armv7l目录

尝试在make命令前加ARCH=arm参数,或尝试把/lib/modules/`uname -r`/build/arch中的arm软链为armv6l或armv7l后再编译。

背景知识:

1. Raspbian的内核包

不要按照使用Debian的习惯去找什么linux-image、linux-source之类的包,Raspbian的内核包是raspberrypi-bootloader,里面包含了内核、模块和一些启动文件,但没有Mo