剥离armbian的patch并为ASUS Tinkerboard 2构建Archlinux镜像
目录
这可能是某种执念。成功了,但最后还是觉得完成后也没什么用。跑点什么好呢?
学习Armbian的设计,获取编译必要信息🔗
一开始没有方向。原以为从启动脚本开始看就好了,但发现Armbian的Bash脚本用了很多高级编程方法,没法轻松追溯各个部分。于是选择从开发板配置开始看。来看看armbian-build/config/boards/tinkerboard-2.csc
。
# Rockchip RK3399 hexa core 2GB SoC GBe eMMC USB3 WiFi/BT
BOARD_NAME="Tinker Board 2"
BOARDFAMILY="rockchip64"
BOARD_MAINTAINER=""
BOOTCONFIG="tinker-2-rk3399_defconfig"
KERNEL_TARGET="current,edge"
KERNEL_TEST_TARGET="current,edge"
FULL_DESKTOP="yes"
BOOT_LOGO="desktop"
BOOT_FDT_FILE="rockchip/rk3399-tinker-2.dtb"
SERIALCON="ttyS2"
BOOT_SCENARIO="spl-blobs" # 'blobless' also works; but some RAM issues found; see rk33/rk3399_ddr_800MHz_v1.27.bin in rockchip64_common.inc
BOARD_FIRMWARE_INSTALL="-full" # Install full firmware, for rtl8822ce firmware and others
BOOTBRANCH="tag:v2021.07" # v2021.07 ...
BOOTPATCHDIR='legacy/u-boot-tinkerboard2' # ... with _only_ the patches we need for TB2, not the default rockchip64
DDR_BLOB="rk33/rk3399_ddr_800MHz_v1.27.bin" # Different blob for TB2
全局搜索上面的变量名称,可以发现下面一些文件很有意思
armbian-build/config/sources/families/include/rockchip64_common.inc
- rockchip64平台的配置脚本
armbian-build/extensions/rkbin-tools.sh
- rkbin的编译工具
armbian-build/config/sources/common.conf
- 部分代码定义了内核补丁的默认行为
列一些有用的代码块
CPUMIN=
)
CPUMAX=
BOOT_SCENARIO=""
DDR_BLOB=""
MINILOADER_BLOB=""
BL31_BLOB=""
;;
UBOOT_TARGET_MAP="BL31= / spl/u-boot-spl.bin u-boot.dtb u-boot.itb;;idbloader.img u-boot.itb"
ATFSOURCE=''
ATF_COMPILE='no'
;;
}
# If KERNELPATCHDIR is unset, set it to "archive/${KERNELPATCHDIR}-${KERNEL_MAJOR_MINOR}" # @TODO: no, use LINUXFAMILY directly
if ; then
KERNELPATCHDIR="archive/ -" # previously was KERNELPATCHDIR="$LINUXFAMILY-$BRANCH"
fi
看了下Linux的编译操作分散在 kernel*.sh
中。Armbian的默认做法是给主线内核打补丁,使其兼容目标平台。用户也可以使用变量配置实际内核的来源和分支。
编译u-boot🔗
看tinkerboard2相关commit说,因为一些内存初始化问题,用RK官方提供的blob会更好,这里就不用编译ATF。复用了一些Armbian的变量、抠了一些代码出来用,参考流程如下:
RKBIN_DIR=
DDR_BLOB=rk33/rk3399_ddr_800MHz_v1.27.bin
BL31_BLOB=rk33/rk3399_bl31_v1.35.elf
BOOT_SOC_MKIMAGE=rk3399
# configure u-boot
# apply patches in armbian-build/patch/u-boot/legacy/u-boot-tinkerboard2
# use custom version control version, here's empty, so no -dirty will be appended
# emm?
# u-boot done configuring
# build u-boot
UBOOT_CFLAGS_ARRAY=(
"-fdiagnostics-color=always" # color messages
"-Wno-error=maybe-uninitialized"
"-Wno-error=misleading-indentation" # patches have mismatching indentation
"-Wno-error=attributes" # for very old-uboots
"-Wno-error=address-of-packed-member" # for very old-uboots
"-Wno-error=array-parameter" # very old uboots, apply when gcc version >= 11
)
UBOOT_TARGET_MAP="BL31= / spl/u-boot-spl.bin u-boot.dtb u-boot.itb;;idbloader.img u-boot.itb"
target_make=
# target_patchdir=$(cut -d';' -f2 <<< "${UBOOT_TARGET_MAP}")
target_files=
# post process
SPL_BIN_PATH=" /"
# Installation? TBW
编译linux🔗
大差不大。有一点注意,Armbian按natural sort排序依序应用patch(这个和python的sorted
、ls -v
一致)。看源码说,部分情况下还需要拆分mailbox形式的patch,不过我没遇到过。
参考准备流程如下:
# apply patches in armbian-build/patch/kernel/archive/rockchip64-6.6
# order matters, use natural sort(-v)
for; do
done
# overwrite devicetrees
[ ||
# auto patch Makefile. some kernel version may need extra '-y'
for; do
if ! ; then
fi
done
# no "-dirty", hahaha
# patch done
配置然后编译内核。在第一遍还没有config用的时候就这样吧。
# here we need linux-rockchip64-current.config from
# armbian-build/config/kernel/linux-rockchip64-current.config
# at the time of writing, this is the one for kernel 6.6.* used by armbian
然后按正常流程来编译内核,不再详叙。打包就参考linux-aarch64
,略。不过Armbian默认配置带的驱动还真多啊。
准备rootfs🔗
跳过!这段不写!研究下pacstrap吧~
存储器分区🔗
使用单分区配置(只有rootfs一个分区,不含EFI之类)。根据瑞芯微wiki,boot分区应从32768扇区开始,不过实际可以单单把rootfs放在这里。大概是u-boot实现了从ext4加载的功能,暂不深究。
之后把rootfs释放进去,把u-boot要用的脚本、kernel image、initrd之类的丢进/boot
就好。
安装bootloader🔗
根据瑞芯微的wiki,把idbloader.img
、u-boot.itb
写到对应位置。BTW扇区大小512字节。
按习惯我会直接用u-boot加载initramfs、kernel、config。但是实际测试竟然不能启动? 接串口看了看日志,说是initrd格式错误。 看起来所用u-boot不支持直接加载initramfs(类似rootfs只是文件打包),需要改成initrd(一个虚拟block设备,需要挂载)。可以使用下面的指令进行转换:
说起来是不是应该有种方法让kernel自己加载initramfs?不太了解。
下面的脚本是mkinitcpio的post hook,这样能每次自动生成initrd:
#!/usr/bin/env bash
kernel=
initramfs=
unified_image=
initrd_name="uInitrd"
if ; then
initrd_name=" -fallback"
fi
initramfs_path=
启动脚本的部分我把dietpi用的搬了过来,稍微改了改。毕竟u-boot用的都是armbian版。
boot.cmd
:
# DO NOT EDIT THIS FILE
#
# Please edit /boot/bootEnv.txt to set supported parameters
# This file is adapted from dietpi's work.
#
# If you must, edit /boot/boot.cmd and recompile /boot/boot.scr with:
# mkimage -C none -A arm64 -T script -d /boot/boot.cmd /boot/boot.scr
# Default environment
# Load addresses
# Load environment file
if ; then
fi
# Define kernel command-line arguments
# Add bootargs for Docker
if ; then ; fi
# Load kernel, initramfs and device tree
# Apply DT overlays
if ; then
for; do
if ; then
||
fi
done
for; do
if ; then
||
fi
done
if ; then
else
if ; then
fi
if ; then
if ; then
fi
fi
fi
fi
# Boot
bootEnv.txt
:
rootdev=UUID=CHANGE_ME
rootfstype=ext4
# The init system logs to the console defined last.
consoleargs=console=ttyS2,1500000 console=tty1
usbstoragequirks=
extraargs=net.ifnames=0
docker_optimizations=off
overlay_path=rockchip
overlay_prefix=rockchip
overlays=
user_overlays=
一些问题🔗
不知道为啥,用 armbian 的内核 HDMI 就会抖,例如字体纵向边缘有波纹抖动,但是在dietpi上没这个问题。已测试不是设备树的问题。在dietpi的相关资料里也没翻到他们怎么编译内核的。
Update:意外发现,好像是我显示器HDMI接口不太灵……
所以armbian/build是什么?🔗
看起来这是一套代码复用率很高的打包框架。不过有些地方的设计还挺令我头疼的。简单说,我第一次用时对整个流程都不是很了解,不透明,而且那时候不懂使用地区镜像,网速慢死,劝退劝退。
它通过平台/开发板配置文件指定各个流程用到的关键配置,包括源码来源、内核版本、u-boot配置、各种乱七八糟的东西。编译不同版本的u-boot和linux的流程大差不大,armbian就把它们整合起来了。中间有一些编译期间的quirks,这个没办法单独列出来。整体上就是下载源码、打补丁、交互模式时的手动配置、编译、转移/打包编译成果。
好像在这篇文里提Arch有点多余?🔗
看起来是这样。毕竟打包和安装rootfs的部分都省略了。