一、编译前的准备工作
在编译内核之前首先要把编译环境搭建起来,vim、gcc等工具最好都更新一下,最重要的是,要满足以下三个条件:
1. 要有交叉编译工具链;
2. 有Linux内核;
3. 有编译所需要的插件。
1.安装编译工具
交叉编译工具链在我的上一条博客有介绍:交叉编译工具链的安装。
2.准备Linux内核
Linux内核的下载请到:github.com/raspberrypi/linux下载,但是下载之前请查看以下自己树莓派的内核版本,使用:
uname -r
我的是5.4版本,所以在github选择rpi-5.4.y,大家应该根据自己树莓派的内核版本下载相应的版本:
众所周知,github的下载速度都很感人,如果大家的树莓派内核也是5.4的话,可以下载我的资源:rpi-5.4.y
下载完之后,放到Ubuntu虚拟机上解压即可。
3.内核配置(生成.congfig)
在一个Linux内核当中,很多架构的工程代码,比如有适用于树莓派的arm,虚拟机的x86,powerPC等,编译器会通过一个配置文件 .conifg 指导makfile 把有用的文件组织起来,才能生成我们适合树莓派的内核程序。
树莓派1的工程是bcmrpi_defconfig;
树莓派2、3、4的工程是bcm2709_defconfig。
更多工程可在linux-5.4.y目录下,使用:
find . -name *_defconfig
来查看所有工程。
配置 .config 有三种方式:
(1) 复制厂家给的 .config ;
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7l make bcm2711_defconfig
树莓派3用:
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make bcm2709_defconfig
如果大家是第一次的话,可能会遇到这种情况,这时候安装两个插件就行了:
sudo apt-get install bison
sudo apt-get install flex
因为我之前就已编译过了,所以直接输出了 .config
(2) 自己使用 make menuconfig来一项项配置,但是都是基于厂家的config来配置(初级的程序员基本不会);
(3) 完全自己来配置树莓派Linux 的内核。
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7l make menuconfig
4.安装编译环境
编译也需要一些插件,以提供Makefile使用,
sudo apt-get install bc
sudo apt-get install libncurses5-dev libncursesw5-dev
sudo apt-get install zlib1g:i386
sudo apt-get install libc6-i386 lib32stdc++6 lib32gcc1 lib32ncurses5-dev
sudo apt-get install python2
环境安装好之后,应该可以实现以下界面:
二、编译内核(生成zImag)
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7l make -j4 zImage modules dtbs
指令内容 | 解释 |
---|---|
ARCH=arm | 指定编译的是arm架构,编译其他架构时,在“=”后面修改 |
CROCSS_COMPILE | 指定编译工具,arm-linux-gnueabihf- 位arm 的交叉编译工具链 |
KERNEL | 指定芯片方案,kernel7是树莓派的 |
-j4 | 为目标平台的资源,为核心数量,4代表4核 |
zImage | 生成内核的名字 |
modules | 驱动模块的名字 |
dtbs | 其他必要的文件 |
编译错误会有提示,我这里是因为缺少了一个库,安装一下libssl-dev:
sudo apt-get install libssl-dev
再次编译:
正常的编译过程会比较久,这时候电脑卡一点是正常的。编译成功后,会有vmlinux文件,失败就没有。
三、打包内核(生成kernel.img)
如果编译的是rpi-5.2y之前(包括5.2)的版本,则使用:
./scripts/mkknlimg arch/arm/boot/zImage ./kernel_new.img
来打包生成img内核,
而rpi-5.3y以及之后的Linux内核源码则使用工具中的:imagetool-uncompressd.py 来打包:
./tools-master/mkimage/imagetool-uncompressd.py ....arch/arm/boot/zImage ./kernel_new.img
四、替换树莓派内核
内核编译完成并且打包之后,可以替换掉树莓派原有的内核,但是不会对上层文件有影响,起到一个更新的作用。
1.挂载树莓派SD 卡
把树莓派的SD卡通过读卡器插入电脑,并连接到虚拟机上,输入命令:dmesg 可查看低层设备,看到有类似以下设备,曾明SD已经成功连接虚拟机。
树莓派的sd卡有两个分区:
一个 fat分区(上图中的sdb1),是boot相关的内容,kernel的img文件就放在这个分区里;
一个是 ext4分区(上图中的sdb2),也就是系统的根目录分区。
然后在当前目录创建两个文件夹:fat 和 ext4,名字可以随便起,只要记得住就行。
然后分别使用:
sudo mount /dev/sdb1 fat
sudo mount /dev/sdb2 ext4
把SD卡的 sdb1 和 sdb2 两个分区挂载到 fat 和 ext4文件夹中。
2.安装驱动modules
去到Linux内核的目录下,因为操作的是 ext4 分区,因此需要管理员权限:
cd linux-pi-5.4.y
//执行下面指令
sudo ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make INSTALL_MOD_PATH=/home/seahi/ext4 modules_install
完成这看起来很牛逼的过程之后,modules就安装完毕了。
3.复制kernel.img文件到 fat 分区
kernel.img在SD卡中的名字为:kernel7.img,这是树莓派指定的名字,不能更改,所以复制的时候要把kernel7.img复制成kernel7l.img。个人建议,在复制之前先把原有的kernel7.img 拷贝一份,防止无法启动。另外说一下各个 .img 内核的区别:
内核名称 | 说明 |
---|---|
kernel.img | 树莓派1代默认启动的内核名称 |
kernel7.img | 树莓派2、3代默认启动的内核名称 |
kernel7l.img | 树莓派4代的默认启动的内核名称 |
kernel8.img | 树莓派64位的内核名称,目前只有3代和4代支持64位,可在config.txt 加入 arm_64bit=1 来使用64位架构 |
找到kernel.img所在目录,使用命令,4B的默认启动内核是kernel7l.img,我把默认img替换了:
sudo cp arch/arm/boot/zImage /home/seahi/fat/$KERNEL.img
如果不想替换,可以另起一个名字:
sudo cp arch/arm/boot/zImage /home/seahi/fat/kernel-mykernel.img
并在内存卡中的 /boot 分区中config.txt 文件中添加:
kernel=kernel-mykernel.img
路径根据自己的 fat文件夹路径,最好检查一下新的kernel7.img 是否和我们的kernel.img是一样的,使用 “md5sum +文件名命令” 查看:
两个的.img的文件校验码都是一样的,证明我们复制成功了。但是现在还没有完成,还需要复制三个文件到 fat
4.复制其他相关文件
在文件源码根目录下,分别执行:
cp arch/arm/boot/dts/*.dtb fat的路径/
cp arch/arm/boot/dts/overlays/.*dtb* fat的路径/overlays/
cp arch/arm/boot/dts/overlays/README fat的路径/overlays/
耐心等待复制完成。完成之后,就可以断开SD卡的连接,然后安全退出,把SD卡插入树莓派等待启动了,登录名和密码都是之前的,不会改变。因为之后需要编译驱动,所以需要一个编译好的内核。成功的替换内核版本的内核,应该有所改变,我的从5.4.79变成了5.4.83: