树莓派(Raspberry Pi 4 Model B)编译64位内核Kernel(64位系统)

树莓派系统默认安装的是ARM32位的系统,可是从树莓派3开始是支持ARM64位系统的,官方既然不给64位系统, 那只好咱们本身来编译了。linux

网上其实有不少树莓派3B的编译64位内核,我都试了一遍,所有启动不了,也不是说写得不对,只不过好像不适用于我,搞了我三四天,很愁人;因此我下面的步骤也不保证每一个人均可以成功,由于每一个人的状况都不同,形成的问题也不同,因此出现问题只能靠本身百度或者Google了。git

并且有不少笔记只是把内核编译为64位,可是文件系统仍是官方的32位,并不能称为真正的64位系统,因此我后面也把根文件系统也构建为64位的了。github

笔记在记载的时候不免有遗漏的,若是有哪一个步骤不太对,欢迎留言,及时修改。bootstrap

若是不想这么麻烦,想直接使用64位的系统,能够下载已经开源的64位系统:Debian-Pi-Aarch64,这个是第三方的,不是树莓派官方提供的。ubuntu

编译环境

经过vm虚拟机安装的虚拟环境Linux,如何安装网上一搜就有了,按照步骤安装便可。vim

编译机:Ubuntu 18.04-desktop-amd64bash

想要编译64位的内核,只能在64位的机器上来编译。架构

交叉编译器

经过交叉编译器生成64位的内核(Kernel)app

定义:交叉编译器(英语:Cross compiler)是指一个在某个系统平台下能够产生另外一个系统平台的可执行文件的编译器async

这句话个人理解形象一点解释就是:

  • Ubuntu 18.04-amd64:定制服装加工工厂(某个系统平台)

  • 交叉编译器:制做衣服的机器(编译器)

  • linux源码(kernel):服装材料(可执行文件的源码)

  • 树莓派4B:人(另外一个平台)

有了以上,如今我要给人作一件衣服,那么我须要找一个专门给人作衣服的工厂,把服装材料给工厂后,制做衣服的机器作出来的衣服,人就能够穿了。

每一个人理解的都不同,只要记住上面专业的定义就行了,本身怎么理解按本身的来就能够了。

编译内核(kernel)

就如上面定义的同样,那四样咱们都须要先获取到才能够制做;Ubuntu确定先要安装好;树莓派固然也要准备好。

能够用普通用户,尽可能不要用root用户来执行,等须要用到root用户时,再切换到root用户来执行

编译内核前准备

  • 获取交叉编译器并配置

Linaro Toolchain

下载上面连接中的 gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu.tar.xz,有可能更新了,日期和版本会变化。 或者用命令下载

$ sudo wget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu.tar.xz
复制代码

建立一个工做目录,后续的操做都在工做目录中操做

$ mkdir ~/build && cd ~/build
$ sudo apt-get install lrzsz
# 把下载好的文件上传并解压
$ rz
$ sudo tar -xvf  gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu.tar.xz -C /usr/src/
$ cd /usr/src/ && sudo mv gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu aarch64-linux-gnu
$ sudo vi /etc/profile
or
$ sudo vi ~/.bashrc
# 末尾添加如下内容
export ARCH_HOME=/usr/src/aarch64-linux-gnu
export PATH=$PATH:$ARCH_HOME/bin
$ source /etc/profile
or
$ source ~/.bashrc
复制代码

Note:若是是在普通用户下,还须要切换到root下再配置一遍,普通用户也须要配置

  • 获取Raspberry Kernel源码

raspberry如今默认的就是4.19版本,不过更高的版本也是有的,看本身下载哪一个更改一下版本就能够了,Raspberry官方的github下载超级慢,我是把Raspberry Linux迁移到了国内码云上,这样下载起来就很快了;有区别的就是官方更新,不会更新到个人码云的仓库上,想要最新的代码,能够先把官方的fork到本身的github,再迁移到本身的码云,把连接更换成本身的就能够了,下面的命令选择一个下载就能够了

$ cd ~/build
$ sudo apt-get install git
# 官方的github地址
$ git clone --depth=1 --branch rpi-4.19.y https://github.com/raspberrypi/linux
# 码云的地址
$ git clone --depth=1 --branch rpi-4.19.y https://gitee.com/nzwxl/linux
复制代码
  • 安装编译环境所需的依赖
$ sudo apt-get install git bison flex libssl-dev zip libncurses-dev make
复制代码

libncurses-dev依赖是支持后面menuconfig的

内核(kernel)编译开始

# 若是源码文件不叫linux,能够mv 改为linux或者你想要的的名字
$ cd linux
# 在编译以前能够先进行清除命令,以保证清洁的环境,若是在编译的环节出错或者操做失误,能够运行此命令从新开始。
$ make distclean
# 编译.config,ARCH要配置成arm64,若是不配置则默认为开发机的x86了,CROSS_COMPILE指定编译器
# bcm2711_defconfig在 arch/arm64/configs/bcm2711_defconfig,它会本身根据Makefile本身去找这个文件
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig
# 在当前的.config基础上开始裁剪内核,若是没有要裁剪的按ESC两次退出便可,主要是我也没太了解,等我了解了再记
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
# 开始编译内核, 参数-j5的意思是 使用多处理器同时编译内核,数字最大为:cpu的核数 × 1.5,可自行修改
$ make -j5 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
复制代码

中间不报错的话,大概会在1个小时左右,会在目录 arch/arm64/boot 中生成 Image 二进制内核文件;若是制做的是32为内核,会在 arch/arm/boot 生成zImage 二进制内核;同时会在linux目录中生成最原始的内核文件vmlimux。

vmlinunx:最原始的linux内核文件。

zImage: 通过压缩和去掉调试信息的可加载二进制内核文件。

Image:没有通过压缩的可加载二进制内核文件。

有关更多关于内核文件可Google。

安装kernel modules

这个modules在后面的根文件系统(rootfs)中用的到,先安装到 ~/build 工做目录中,记得把 [user] 替换为本身的用户名

$ cd ~/build/linux
# 切换到root用户下
$ su
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=/home/[user]/build/ modules_install
$ su [user]
复制代码

树梅派boot文件

由于树莓派官方的 bootloader 是不开源的,可是提供了可使用的boot目录下全部的东西,一样的我由于网速的缘由下载太慢,迁移到了码云上。

$ cd ~/build
$ git clone --depth=1 https://github.com/raspberrypi/firmware/
or
$ git clone --depth=1 https://gitee.com/nzwxl/firmware/
# firmware/boot 下就是须要的文件了
$ ls firmware/boot
复制代码

制做ARM64架构的rootfs

如何制做ARM64的rootfs我在另外一篇笔记中记录了,到此步骤能够继续按照那篇笔记顺序操做,等rootfs制做完,回到此笔记与下一个步骤衔接

kernel、uboot、rootfs打包进镜像

制做镜像文件

  • 建立一个大小为 1000M 的根文件系统映像文件,而后对映像文件分区

经烧录后显示,1000M的话已经使用了90%,因此要是有许多要作的事情,或者上传一些东西的话,最好建立个比较大一点的映像文件

$ cd ~/build
$ fallocate -l 1000M rootfs.img
# 分区
$ fdisk rootfs.img
    a.输入o。这将清除映像文件上的任何分区。
    b.键入p以列出分区。应该没有分区。
    c.键入n,而后p为primary,1表示驱动器上的第一个分区,按ENTER接受默认的第一个扇区,而后为最后一个扇区键入+ 100M。
    d.键入t,而后c将第一个分区设置为键入W95 FAT32(LBA)。
    e.键入n,而后p表示主驱动器,2表示驱动器上的第二个分区,而后按两次ENTER键接受默认的第一个和最后一个扇区。
    f.写入分区表并键入w退出。
# 可经过命令查看设置好的分区
$ fdisk -l rootfs.img
复制代码
  • 使用kpartx挂载镜像到loopX

在linux中,若是映像文件(.img)含有分区表的话,使用mount是挂在不上的;可使用kpartx挂载; X是你显示的数字,Y也是数字,每一个人不必定相同,第一个 loopXpY 是上面分区后的第一个分区,第二个就是第二个分区

$ sudo apt-get install kpartx
$ sudo kpartx -av rootfs.img
add map loopXpY (254:0): 0 204800 linear 7:0 2048
add map loopXpY (254:1): 0 407552 linear 7:0 206848
# 这两个设备能够在 /dev/mapper/ 目录中看到
$ ls /dev/mapper/
复制代码
  • 格式化分区并指定分区LABEL名字
$ sudo mkfs.vfat -n BOOT /dev/mapper/loop5p1
$ sudo mkfs.ext4 -F -L -O "^has_journal" ROOTFS /dev/mapper/loop5p2
# 第一个命令中的-n 参数就是指定LABEL,能够经过 man mkfs.vfat 查看参数详情
# 第二个命令的 -F 是强制的意思(理解的不对能够纠正我),-L 指定LABEL 一样能够经过man mkfs.ext4 查看参数详情
复制代码
  • 建立挂载点并挂载

通过格式化分区后,如今咱们能够挂载loopXpY设备到文件

$ sudo mkdir {/mnt/loopXp1,/mnt/loopXp2}
$ sudo mount /dev/mapper/loop5p1 /mnt/loopXp1
$ sudo mount /dev/mapper/loop5p2 /mnt/loopXp2
复制代码

复制内核和boot所需文件

$ cd ~/build
# 复制boot所需文件
$ sudo cp -r firmware/boot/* /mnt/loopXp1/
$ sudo cp linux/arch/arm64/boot/dts/broadcom/*.dtb /mnt/loopXp1
$ sudo cp linux/arch/arm64/boot/dts/overlays/*.dtb* /mnt/loopXp1/overlays/
$ sudo cp linux/arch/arm64/boot/dts/overlays/README /mnt/loopXp1/overlays/
# 复制内核
$ sudo cp linux/arch/arm64/boot/Image /mnt/loopXp1/kernel8.img
复制代码

编写cmdline.txt和 config.txt

参考:RPi_cmdline.txt

编写cmdline.txt

# 添加内容并保存退出
$ sudo vim /mnt/loopXp1/cmdline.txt
console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rw rootwait fsck.repair=yes
复制代码
  • console=serial0,115200:串口使用哪一个设备,以及传输速率
  • console=tty1:控制台输出使用tty1设备
  • root=/dev/mmcblk0p2:将内存卡第二分区设置为根分区
  • rootfstype=ext4:根分区类型 f2fs应更换为f2fs
  • rw:可写挂载跟分区
  • rootwait:等待内核识别根分区设备后再挂载
  • sck.repair=yes:启动时自动检查修复文件系统错误

编写config.txt

# 添加内容并保存退出
$ sudo vim /mnt/loopXp1/config.txt

# 以64位读取内核
arm_64bit=1
# 想要以ARMV8的模式启动,设置此选项
arm_control=0x200
# 内核的名字
kernel=kernel8.img

# u-boot进行引导kernel时延迟几秒
boot_delay=1

# 关闭蓝牙功能
# See /boot/overlays/README for all available options
dtoverlay=disable-bt
# 开启音频snd_bcm2835
dtparam=audio=on
复制代码

同步rootfs进镜像第二分区

$ sudo apt-get install rsync
$ cd ~/build/linux-rootfs/
# 开始同步
$ sudo rsync -HPavz -q ./ /mnt/loopXp2
复制代码

rsync参数详解: rsync命令

编写fstab文件

若是想要第一分区中的boot目录在系统启动后显示文件,须要在 /etc/fstab 中添加如下内容:

$ sudo vim /mnt/loopXp2/etc/fstab
<file system>   <mount point>    <type>   <options>  <dump> <pass>
LABEL=BOOT      /boot            vfat     defaults   0      1
复制代码
  • file system: 能够是实际分区名,也能够是实际分区的卷标(Lable),卷标名上面已经规定过了
  • mount point: 是挂载点
  • type: 为此分区的文件系统类型,vfat位fat32的类型应该是
  • options: 是挂载的选项,用于设置挂载的参数,常见的有如下参数
    • defaults: rw, suid, dev, exec, auto, nouser, and async.
    • auto: 系统自动挂载,fstab默认就是这个选项
    • noauto 开机不自动挂载
    • nouser 只有超级用户能够挂载
    • ro 按只读权限挂载
    • rw 按可读可写权限挂载
    • user 任何用户均可以挂载
  • dump: 是备份设置 当其值设置为1时,将容许dump备份程序备份;设置为0时,忽略备份操做;
  • pass: 是fsck磁盘检查设置; 其值是一个顺序。当其值为0时,永远不检查;而 / 根目录分区永远都为1。其它分区从2开始,数字越小越先检查,若是两个分区的数字相同,则同时检查。

安装内核模块

由于在编译kernel时已经把modules安装到了工做目录build中了,直接复制到第二分区中就能够了,若是不放心,能够用安装modules的命令安装到第二分区下,更改下路径就能够了。

$ cd ~/build
$ sudo cp -r lib/modules/ /mnt/loopXp2/lib/
复制代码

卸载烧录IMG文件到SD卡

$ cd ~/build
$ sync
$ sudo umount /mnt/loopXp1/
$ sudo umount /mnt/loopXp2/
$ sudo kpartx -dv rootfs.img
复制代码

把 rootfs.img 下载到windowns下 烧录到SD卡中,烧录SD卡的方式可参考:

启动Raspberry后经过命令查看内核版本为64位

uname -a

参考

相关文章
相关标签/搜索