【树莓派】Linux内核编译
树莓派的Linux内核编译有两种方法: 一种是在树莓派上直接编译,另一种是利用交叉编译的方法。一般我们都推荐采用交叉编译的方式进行编译,这是因为通常交叉编译Pi内核的速度比Pi本身编译快得多(性能因素)。下面就讲下如下利用这两种方式来编译Pi内核。
第一种方法:Pi本地编译
前提条件
准备一张16G以上TF卡(需要事先进行扩容和增加SWap分区操作,可参考公众号里文章)。
如果上述没有该条件,可以利用NFS挂载方式,将源码目录挂载到主机上,利用主机的空间来存储代码,但会影响到编译速度。 比如我将虚拟机的nfs目录挂载到Pi的/mnt目录下,并在该目录下存储代码,如下:
pi@raspberrypi:~ $ mount | grep mnt
192.168.1.133:/nfs/ on /mnt type nfs (rw,relatime,vers=3,rsize=524288,wsize=524288,namlen=255,hard,nolock,proto=tcp,port=2049,timeo=70,retrans=3,sec=sys,local_lock=all,addr=192.168.1.133)
pi@raspberrypi:~ $ ls /mnt/
linux
pi@raspberrypi:~ $
编译前准备
首先,配置好树莓派的网络(用推荐用有线网络,否则下载会非常慢)和树莓派的源(推荐使用阿里源,将"raspbian.raspberrypi.org”替换为“mirrors.aliyun.com/raspbian"字段),正常souces.list前后替换后差异内容大致如下:
安装git和树莓派内核编译所需的依赖库,如下所示:
$ sudo apt install git bc bison flex libssl-dev make
下载内核源码
利用git获取当前git仓库默认Pi的内核源码,如下所示:
$ git clone --depth=1 https://github.com/raspberrypi/linux
当然,你也可以选择下载自己所需的内核源码版本,如需要下载4.14.y,可利用branch参数下载,如下:
$ git clone --depth=1 https://github.com/raspberrypi/linux --branch rpi-4.14.y
配置内核
根据当前你使用的Raspberry Pi的实际型号,通过运行以下具体命令进行准备默认配置:
如果是Raspberry Pi 2, Pi 3, Pi 3+系列,默认配置如下:
pi@raspberrypi:/mnt $ cd linux
pi@raspberrypi:/mnt/linux $ KERNEL=kernel7
pi@raspberrypi:/mnt/linux $ make bcm2709_defconfig
Raspberry Pi 4的默认配置如下:
pi@raspberrypi:/mnt $ cd linux
pi@raspberrypi:/mnt/linux $ KERNEL=kernel7l
pi@raspberrypi:/mnt/linux $ make bcm2711_defconfig
Raspberry Pi 1、Pi Zero、Pi Zero W系列的默认采用配置如下:
pi@raspberrypi:/mnt $ cd linux
pi@raspberrypi:/mnt/linux $ KERNEL=kernel
pi@raspberrypi:/mnt/linux $ make bcmrpi_defconfig
如果需要额外对内核进行配置,则可以利用如下命令实现:
pi@raspberrypi:/mnt/linux $ make menuconfig
编译和安装
最后进行编译安装内核、驱动模块、设备树配置操作,这个过程会比较漫长,需要耐心等待,命令如下:
pi@raspberrypi:/mnt/linux $ make -j4 zImage modules dtbs
pi@raspberrypi:/mnt/linux $ sudo make modules_install
pi@raspberrypi:/mnt/linux $ sudo cp arch/arm/boot/dts/*.dtb /boot/
pi@raspberrypi:/mnt/linux $ sudo cp arch/arm/boot/dts/overlays/*.dtb* /boot/overlays/
pi@raspberrypi:/mnt/linux $ sudo cp arch/arm/boot/dts/overlays/README /boot/overlays/
pi@raspberrypi:/mnt/linux $ sudo cp arch/arm/boot/zImage /boot/$KERNEL.img
pi@raspberrypi:/mnt/linux $ sudo reboot -f
第二、交叉编译内核
首先,需要准备一台Linux交叉编译主机,比如Ubuntu 18.04(可以安装实体机或者VMware或VirtualBox里)。
编译前准备
首先在交叉编译Linux主机上安装所需的依赖和交叉编译工具,如下:
sudo apt install git bc bison flex libssl-dev make libc6-dev libncurses5-dev
如果Pi安装的是32的内核,则安装32位的交叉编译工具链:
(注:通过在Pi里运行“file /sbin/busybox” 或其他可执行程序可查看当前内核是32位还是64位的。如果是32位的,会显示如下32-bit 字段,否则为64位的)
$ sudo apt install crossbuild-essential-armhf
否则,如果Pi使用的是64的内核,则安装64位的交叉编译工具链:
$ sudo apt install crossbuild-essential-arm64
获取源码
利用git获取当前git仓库默认Pi的内核源码,如下所示:
$ git clone --depth=1 https://github.com/raspberrypi/linux
当然,你也可以选择下载自己所需的内核源码版本,如需要下载4.14.y,可利用branch参数下载,如下:
$ git clone --depth=1 https://github.com/raspberrypi/linux --branch rpi-4.14.y
配置内核
针对32位系统:
如果是Pi 2, Pi 3, Pi 3+, 和3系列树莓派,运行如下命令:
linux@ubuntu:~$ cd linux
linux@ubuntu:~/linux$ KERNEL=kernel7
linux@ubuntu:~/linux$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
如果是Raspberry Pi 4,运行如下命令:
linux@ubuntu:~$ cd linux
linux@ubuntu:~/linux$ KERNEL=kernel7l
linux@ubuntu:~/linux$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2711_defconfig
如果是Pi 1, Pi Zero, Pi Zero W,运行如下命令:
linux@ubuntu:~$ cd linux
linux@ubuntu:~/linux$ KERNEL=kernel
linux@ubuntu:~/linux$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcmrpi_defconfig
针对64位系统:
如果是Pi 2, Pi 3, Pi 3+, 和3系列树莓派,运行如下命令:
linux@ubuntu:~$ cd linux
linux@ubuntu:~/linux$ KERNEL=kernel8
linux@ubuntu:~/linux$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcmrpi3_defconfig
如果是Raspberry Pi 4,运行如下命令:
linux@ubuntu:~$ cd linux
linux@ubuntu:~/linux$ KERNEL=kernel8
linux@ubuntu:~/linux$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig
编译内核
针对32位内核
运行如下命令:
make -j4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs
针对64位内核
运行如下命令:
make -j4 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image modules dtbs
内核安装到TF卡
将TF卡接到Linux交叉编译主机上(如果是VMwar虚拟机,则需要将"设置->硬件->USB控制机->USB兼容性(C)”调成“USB 1.1”)
运行lsblk命令查看识别到的TF卡设备节点,如下:
linux@ubuntu:~/linux$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 20G 0 disk
└─sda1 8:1 0 20G 0 part /
sdb 8:16 1 14.6G 0 disk
├─sdb1 8:17 1 256M 0 part /media/linux/boot
└─sdb2 8:18 1 3.3G 0 part /media/linux/rootfs
正常TF卡设备会自动挂载到/media/${当前用户目录}/下的boot和rootfs目录下,如果没有自动挂载,则根据识别到实际TF卡的设备节点,将设备挂载到主机上,如下:
sudo mkdir /media/linux/rootfs -p
sudo mkdir /media/linux/boot -p
sudo mount /dev/sdb1 /media/linux/boot
sudo mount /dev/sdb2 /media/linux/rootfs
然后将内核模块安装到SD中:
针对32位内核
运行如下命令:
sudo env PATH=$PATH make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=/media/linux/rootfs modules_install
针对64位内核
运行如下命令:
sudo env PATH=$PATH make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=/media/linux/rootfs modules_install
备份旧内核
最后备份原理SD卡中的旧内核, 并将新内核和设备树配置文件到SD卡中:
针对32位内核
运行如下命令:
sudo cp /media/linux/boot/$KERNEL.img /media/linux/boot/$KERNEL-backup.img
sudo cp arch/arm/boot/zImage /media/linux/boot/$KERNEL.img
sudo cp arch/arm/boot/dts/*.dtb /media/linux/boot
sudo cp arch/arm/boot/dts/overlays/*.dtb* /media/linux/boot/overlays/
sudo cp arch/arm/boot/dts/overlays/README /media/linux/boot/overlays/
sudo umount /media/linux/boot
sudo umount /media/linux/rootfs
针对64位内核
运行如下命令:
sudo cp /media/linux/boot/$KERNEL.img /media/linux/boot/$KERNEL-backup.img
sudo cp arch/arm64/boot/Image /media/linux/boot/$KERNEL.img
sudo cp arch/arm64/boot/dts/broadcom/*.dtb /media/linux/boot/
sudo cp arch/arm64/boot/dts/overlays/*.dtb* /media/linux/boot/overlays/
sudo cp arch/arm64/boot/dts/overlays/README /media/linux/boot/overlays/
sudo umount /media/linux/boot/
sudo umount /media/linux/rootfs
当然,你也可以不备份旧的内核,而是通过重命令编译出来的内核名称,如将编译出来的img改为kernel-new.img,然后修改config.txt的配置文件种的kernel字段,如下:
kernel=kernel-new.img
这么做的好处是保证原有的内核不被破坏,如果新的内核无法启动,只需要将config.txt的kernel字段改回来即可。
最后,将TF卡插回Pi上,然后启动Pi即可。