0%

OrangePi-3B 折腾笔记—— 构建 Kernel

OrangePi-3B 系列笔记:

编译环境

  • 主板: OrangePi-3b
  • 芯片: RK3566
  • 环境: Debian(12-x86_64) + Docker(Debian:12)

内容说明

U-Boot 搞到差不多了,现在转战 Kernel

U-Boot 类似,OrangePi-3BKernel 供应商正经的也有三家:

  • OrangePi
    板子供应商,有最贴合板子的适配,拿来即用,版本有 5.106.1 可选;
  • Rockchip
    芯片供应商,有比较贴合芯片的适配,但没有板子相关的适配,版本只有 5.10,是 OrangePi5.10 Kernel 的上游。
  • Mainline
    主线内核,瑞芯微会不定时向主线合入对芯片的适配代码。支持度一般,但版本不受限制。

三种开源 Kernel 构建类似,但 RockchipOrangePi 提供了构建脚本,以下内容以主线 Kernel 为主。

构建

OrangePi

克隆代码

cd ~/projects/
git clone https://github.com/orangepi-xunlong/linux-orangepi.git -b orange-pi-5.10-rk35xx kernel_orangepi

启动容器

docker run -ti --rm --privileged -v ~/projects/:/projects/ linux-build bash -l
  1. 关于镜像 linux-build 的内容请参考之前的笔记,其中已经安装构建所需要的软件包。

启动编译

cd /projects/kernel_orangepi/

# 清除缓存[可选]
rm -rf out
make ARCH=arm64 clean
make ARCH=arm64 mrproper
make ARCH=arm64 distclean

# 构建镜像
./make.sh CROSS_COMPILE=aarch64-linux-gnu- orangepi-3b-rk3566
  1. 使用 make.sh 可以快捷编译,也支持使用 make 命令编译;make.sh 能够生成 ATF 镜像。

构建产物

  • vmlinux
    Linux 内核编译出来的原始的内核文件,未做压缩处理的 elf 格式;
  • boot.img
    编译脚本 ATF 处理过的内核镜像,需要配合 OrangePiU-Boot 启动;
  • arch/arm64/boot/Image
    使用 objcopy 处理 vmlinux 后生成的二进制内核映像;
  • arch/arm64/boot/Image.lz4
    使用 lz4 压缩 Image 后生成的压缩文件(不带自解压头),ARMU-Boot 默认支持这种格式并且 U-Boot 负责解压内核;
  • arch/arm64/boot/dts/rockchip/rk3566-orangepi-3b.dtb
    设备树文件;

Rockchip

克隆代码

cd ~/projects/
git clone https://github.com/rockchip-linux/kernel.git -b develop-5.10 kernel_rockchip

启动容器

docker run -ti --rm --privileged -v ~/projects/:/projects/ linux-build bash -l
  1. 关于镜像 linux-build 的内容请参考之前的笔记,其中已经安装构建所需要的软件包。

启动编译

cd /projects/kernel_rockchip/

# 清除缓存[可选]
rm -rf out
make ARCH=arm64 clean
make ARCH=arm64 mrproper
make ARCH=arm64 distclean

# 构建镜像
./make.sh CROSS_COMPILE=aarch64-linux-gnu- orangepi-3b-rk3566
  1. 使用 make.sh 可以快捷编译,也支持使用 make 命令编译;make.sh 能够生成 ATF 镜像。
  2. RockchipKernel 源码中没有包含 OrangePi-3B 的设备树和配置,需要从 OrangePiKernel 中移植。

构建产物

  • vmlinux
    Linux 内核编译出来的原始的内核文件,未做压缩处理的 elf 格式;
  • boot.img
    编译脚本 ATF 处理过的内核镜像,需要配合 OrangePiU-Boot 启动;
  • arch/arm64/boot/Image
    使用 objcopy 处理 vmlinux 后生成的二进制内核映像;
  • arch/arm64/boot/Image.lz4
    使用 lz4 压缩 Image 后生成的压缩文件(不带自解压头),ARMU-Boot 默认支持这种格式并且 U-Boot 负责解压内核;
  • arch/arm64/boot/dts/rockchip/rk3566-orangepi-3b.dtb
    设备树文件;

Mainline

克隆代码

cd ~/projects/
git clone https://github.com/torvalds/linux.git -b linux-rolling-stable kernel
  1. 使用滚动的稳定版本分支;

启动容器

docker run -ti --rm --privileged -v ~/projects/:/projects/ linux-build bash -l
  1. 关于镜像 linux-build 的内容请参考之前的笔记,其中已经安装构建所需要的软件包。

设备树

板子的设备树拷贝的大名鼎鼎 Armbian 的源文件:

cd /projects/kernel/

# 下载设备树文件
DTS_URL=https://raw.githubusercontent.com/armbian/build/main/patch/kernel/archive/rockchip64-6.8/dt/rk3566-orangepi-3b.dts
wget ${DTS_URL} -O arch/arm64/boot/dts/rockchip/rk3566-orangepi-3b.dts

https://github.com/armbian/build/blob/main/patch/kernel/archive/rockchip64-6.8/dt/rk3566-orangepi-3b.dts

实测适配 EMMC 模块不太稳定,在此基础上做了一点调整:

diff --git a/arch/arm64/boot/dts/rockchip/rk3566-orangepi-3b.dts b/arch/arm64/boot/dts/rockchip/rk3566-orangepi-3b.dts
index ac4822641039..d2183ba0eee3 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-orangepi-3b.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-orangepi-3b.dts
@@ -724,11 +724,13 @@ &saradc {
 };
 
 &sdhci {
-       bus-width = <8>;
-       max-frequency = <200000000>;
+       max-frequency = <150000000>;
+       bus-width = <8>;
+       cap-mmc-highspeed;
+       cap-sd-highspeed;
        non-removable;
        pinctrl-names = "default";
-       pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd>;
+       pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd &emmc_datastrobe>;
        status = "okay";
 };
  1. 将频率从 200MHz 降到 150MHz

配置文件

我这没有抄作业,新建了一个基础的配置文件,命名为 arch/arm64/configs/orangepi-3b.config,用于修改 defconfig 配置:

#
# General setup
#
CONFIG_LOCALVERSION_AUTO=y
CONFIG_LOCALVERSION="-orangepi-3b"

#
# Platform selection
#
# CONFIG_ARCH_ACTIONS is not set
# CONFIG_ARCH_SUNXI is not set
# CONFIG_ARCH_ALPINE is not set
# CONFIG_ARCH_APPLE is not set
# CONFIG_ARCH_BCM is not set
# CONFIG_ARCH_BCM2835 is not set
# CONFIG_ARCH_BCMBCA is not set
# CONFIG_ARCH_BCM_IPROC is not set
# CONFIG_ARCH_BERLIN is not set
# CONFIG_ARCH_BRCMSTB is not set
# CONFIG_ARCH_EXYNOS is not set
# CONFIG_ARCH_K3 is not set
# CONFIG_ARCH_LAYERSCAPE is not set
# CONFIG_ARCH_LG1K is not set
# CONFIG_ARCH_HISI is not set
# CONFIG_ARCH_KEEMBAY is not set
# CONFIG_ARCH_MEDIATEK is not set
# CONFIG_ARCH_MESON is not set
# CONFIG_ARCH_MVEBU is not set
# CONFIG_ARCH_NXP is not set
# CONFIG_ARCH_MXC is not set
# CONFIG_ARCH_NPCM is not set
# CONFIG_ARCH_QCOM is not set
# CONFIG_ARCH_RENESAS is not set
CONFIG_ARCH_ROCKCHIP=y
# CONFIG_ARCH_S32 is not set
# CONFIG_ARCH_SEATTLE is not set
# CONFIG_ARCH_INTEL_SOCFPGA is not set
# CONFIG_ARCH_SYNQUACER is not set
# CONFIG_ARCH_TEGRA is not set
# CONFIG_ARCH_TESLA_FSD is not set
# CONFIG_ARCH_SPRD is not set
# CONFIG_ARCH_THUNDER is not set
# CONFIG_ARCH_THUNDER2 is not set
# CONFIG_ARCH_UNIPHIER is not set
# CONFIG_ARCH_VEXPRESS is not set
# CONFIG_ARCH_VISCONTI is not set
# CONFIG_ARCH_XGENE is not set
# CONFIG_ARCH_ZYNQMP is not set

#
# Soc drivers
#
# CONFIG_ROCKCHIP_PX30 is not set
# CONFIG_ROCKCHIP_RK3036 is not set
# CONFIG_ROCKCHIP_RK3066 is not set
# CONFIG_ROCKCHIP_RK3128 is not set
# CONFIG_ROCKCHIP_RK3188 is not set
# CONFIG_ROCKCHIP_RK322X is not set
# CONFIG_ROCKCHIP_RK3288 is not set
# CONFIG_ROCKCHIP_RK3308 is not set
# CONFIG_ROCKCHIP_RK3328 is not set
# CONFIG_ROCKCHIP_RK3368 is not set
# CONFIG_ROCKCHIP_RK3399 is not set
CONFIG_ROCKCHIP_RK3568=y
# CONFIG_ROCKCHIP_RK3588 is not set
# CONFIG_ROCKCHIP_RV1108 is not set
# CONFIG_ROCKCHIP_RV1126 is not set

网络 & NFS 配置

如果要挂载 NFSrootfs,需要启动网卡。除了要修改设备树之外重点要打开 DWMAC 的配置(让我一顿好找):

#
# Wired NIC driver
#
CONFIG_STMMAC_ETH=y
CONFIG_STMMAC_PLATFORM=y
CONFIG_DWMAC_GENERIC=y
CONFIG_DWMAC_ROCKCHIP=y

#
# Network FileSystem Support
#
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V2=y
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_NFS_SWAP=y
CONFIG_NFS_V4_1=y
CONFIG_NFS_V4_2=y
CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org"
CONFIG_NFS_V4_1_MIGRATION=y
CONFIG_NFS_V4_SECURITY_LABEL=y
CONFIG_NFS_USE_LEGACY_DNS=y
CONFIG_NFS_USE_KERNEL_DNS=y
CONFIG_NFS_DISABLE_UDP_SUPPORT=y
CONFIG_NFS_V4_2_READ_PLUS=y
CONFIG_PNFS_FILE_LAYOUT=y
CONFIG_PNFS_BLOCK=y
CONFIG_PNFS_FLEXFILE_LAYOUT=y
CONFIG_ROOT_NFS=y

启动编译

cd /projects/kernel/

# 清除缓存[可选]
rm -rf out
make ARCH=arm64 O=out clean
make ARCH=arm64 O=out mrproper
make ARCH=arm64 O=out distclean

# 应用配置
make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 O=out defconfig orangepi-3b.config
# 图形化配置
make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 O=out menuconfig

# 编译
make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 O=out -j8
# 单编内核
make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 O=out Image.gz -j8
# 单编设备树
make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 O=out dtbs -j8
# 单编模块
make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 O=out modules -j8
# 联合编译
make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 O=out Image.gz dtbs modules -j8
# 导出模块(自定义输出路径)
rm -rf out/lib/modules/
make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 O=out INSTALL_MOD_PATH=. INSTALL_MOD_STRIP=1 modules_install -j8

# 查看内核签名版本
# out/include/generated/utsrelease.h
make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 O=out kernelrelease
  1. 使用 makeO=out 参数重定向的编译输出产物的目录为 out
  2. 构建配置文件时带上交叉编译链,不然启动编译时会有编译选项需要手动确认。
  3. 细节配置可以参考 armbian-build 仓库 main 分支中的 config/kernel/linux-rockchip* 配置文件。
  4. 其中一个 cpio 依赖的问题让我迷茫好一阵: https://github.com/Frogging-Family/linux-tkg/issues/147;

编译产物

  • out/vmlinux
    Linux 内核编译出来的原始的内核文件,未做压缩处理的 elf 格式;
  • out/arch/arm64/boot/Image
    使用 objcopy 处理 vmlinux 后生成的二进制内核映像;
  • out/arch/arm64/boot/Image.gz
    使用 gzip 压缩 Image 后生成的压缩文件(不带自解压头),ARMU-Boot 默认支持这种格式并且 U-Boot 负责解压内核;
  • out/arch/arm64/boot/dts/rockchip/rk3566-orangepi-3b.dtb
    设备树文件;
  • out/lib/modules/*
    内核模块,需要整合进 rootfsinitramfs 系统功能才会完整(比如网络);

针对 OrangePi 3B 的改动记录

https://github.com/lx0758/linux/commits/orangepi-3b/

调试

在没有文件系统的情况下可以通过 U-BootNFS 协议远程加载 Kernel 测试。

# 挂载 NFS 为 ROOTFS
setenv bootargs "earlycon console=ttyS2,1500000n8 root=/dev/nfs ro nfsroot=192.168.8.13:/home/liux/projects/buildfs/rootfs/,vers=4 ip=dhcp rootwait"
# 通过 NFS 加载 Kernel
setenv ipaddr 192.168.8.21
nfs 0x4000000 192.168.8.13:/home/liux/projects/buildfs/rootfs/boot/Image.gz
nfs 0x2000000 192.168.8.13:/home/liux/projects/buildfs/rootfs/boot/initramfs.img
nfs 0x1000000 192.168.8.13:/home/liux/projects/buildfs/rootfs/boot/dts/rockchip/rk3566-orangepi-3b.dtb
booti 0x4000000 0x2000000 0x1000000
  1. U-Boot 的 NFS 协议只能支持 2,为了兼容给 NFS 服务器的 3 协议关了。但是 Kernel 使用 NFS 的默认协议是 3,这里强制指定为 4