OrangePi-3B 系列笔记:
- OrangePi-3B 折腾笔记 —— 认识开发板
- OrangePi-3B 折腾笔记 —— 准备构建环境
- OrangePi-3B 折腾笔记 —— 构建 U-Boot
- OrangePi-3B 折腾笔记 —— 构建 Kernel
- OrangePi-3B 折腾笔记 —— 点亮 LCD 屏幕
- OrangePi-3B 折腾笔记 —— 移植 WiFi & BT 驱动
- OrangePi-3B 折腾笔记 —— 构建文件系统镜像
温馨提示:
- OrangePi-3B 硬件版本 V1.1.1 的板子出现过有线网卡“无故”失灵的故障, 所以在进行操作前请确认开发板工作良好(修复这个问题需要更换 RK3566 芯片).
https://www.bilibili.com/read/cv33224126- 香橙派目前已经推出了硬件版本为 V2.1 的 OrangePi-3B, 有线网卡供应商更换为 RTL. 本系列文章没有针对 V2.1 的板子做过适配, 请根据实际情况操作(同时强烈谴责此种不负责任的行为, 如考虑购买此型号板子商用, 建议换个型号避坑).
- 本系列文章最后更新时间: 2024年11月02日.
编译环境
- 主板: OrangePi-3b_V1.1.1
- 芯片: RK3566
- 环境: Debian:12_x86_64(Docker)
启动流程
通俗理解
要研究 U-Boot
,就不得不学习一下芯片是如何启动的。
玩过单片机的朋友都知道,单片机中基本是一个芯片内置了 CPU
、MEM
、FLASH
,单片机的内置引导程序能够直接让 CPU
调用 MEM
和 FLASH
,用户只需要将程序写入 FLASH
就能开始运行。
但是类似 RK3566
这一类芯片则不同,它们更像是PC的CPU,芯片内除了 CPU
之外只有一些额外的控制器,不能给芯片本身下载程序;需要搭配外设才能运行,最主要的有 DRAM
和 eMMC
下挂的各种存储设备;比如 OrangePi-3b
则是外挂了一个 DDR4
内存,存储则是支持 SDCard
、eMMC
、NVME
等设备,使用的使用用户程序则是存放在这些存储设备中。
和单片机相比,RK3566
运行指令存在于外扩的各种存储设备中,这些设备不是 XIP
设备,访问它们需要经过 eMMC
控制器,并且将其指令复制到 DRAM
中再运行;同时外扩的 DRAM
规格也各不相同,芯片难以在内嵌固件中初始化这些设备;现代芯片还需要支持芯片级的加密支持,这些任务组合在一起很难由片内固件和 SRAM
来完成(也有可能是兼容之前的方案故意为之,毕竟之前由于工艺和成本的原因,很难在片内集成大容量的 FLASH
和 SRAM
)。
XIP:eXecute In Place,即芯片内执行,指应用程序可以直接在
FLASH
闪存内运行,不必再把代码读到系统DRAM
中。FLASH
内执行是指NOR FLASH
不需要初始化,可以直接读取FLASH
中的指令。
因此,目前主流的方案基本都是采用二段式加载方式启动 U-Boot
:
1. BootROM
2. Pre-Loader
3. U-Boot
4. Kernel
5. ...
这里的二段式启动指的是芯片固件 BootROM
不会直接加载 U-Boot
,而是存在一个 Pre-Loader
。
通常 Pre-Loader
又细分为 TPL/SPL (Tiny Program Loader/Secondary Program Loader)
, 分别用来初始化 DRAM
和加载 U-Boot
。
相应的启动过程如下:
- BootROM
这是内嵌在芯片的固件,芯片出厂时已经固化,它在芯片上电时首先被执行;它的任务主要是寻找并执行存储设备设备中的TPL
(通常是FLASH
,但也能从eMMC
下面的存储设备中加载,换句话说BootROM
也能初始化eMMC
);这个阶段芯片使用片内自带SRAM
作为内存运行,SRAM
速度极快但成本极高,容量普遍只有几百KB
;同时也反映了为什么会分为两次加载,因为此时没有初始化DRAM
, 只有几百KB
大小的SRAM
, 没法完整加载U-Boot
程序; - Pre-Loader
Pre-Loader
由BootROM
从存储设备中加载至SRAM
执行,其中TPL
负责初始化DRAM
,然后跳到SPL
继续执行(过程中会跳回BootROM
),并寻找储存设备中合适的U-Boot
并拷贝到DRAM
, 最后执行DRAM
中的U-Boot
; - U-Boot
U-Boot
被SPL
复制到内存并开始执行,它首先完成一次自身重定位,然后就是加载设备树并驱动更多的外设,最后就是加载并执行Kernel
和RootFS
了;另外支持TEE
的设备在这个阶段还会完成TEE
环境的初始化; - Kernel
Kernel
可以看做是操作系统的入口了;
流程示意图如下:
BootROM --> TPL --> BootROM(Back) --> SPL--> U-Boot --> Kernel --> ...
由于 TPL/SPL
通常的表现为一个 Pre-Loader
产物/模块,所以可以简化一下流程:
BootROM --> Pre-Loader --> U-Boot --> Kernel --> ...
ARM Trusted Firmware (TF-A/ATF)
RK3566
是一颗基于 ARMv8
的芯片,它还需要支持 ARM Trusted Firmware (TF-A/ATF)
;启动过程按照 ATF
功能划分为:
Boot stage | Exception level | Description |
---|---|---|
BL1 | EL3 | Boot ROM firmwareNOTE:BL1 is embedded in hardware (Boot ROM + PBL commands) |
BL2 | EL3 | Platform initialization firmware |
BL31 | EL3 | Resident runtime firmware |
BL32 | EL1S | [Optional] Trusted operating system. For example, OP-TEE |
BL33 | EL2 | Normal world bootloader. For example, U-Boot, UEFI |
它们直接的启动关系如图:
- Boot ROM (BL1)
- 当
CPU
从重置中释放出来时,硬件执行PBL
命令,将用于平台初始化的BL2
二进制文件复制到SRAM
,然后通过PBI
命令跳转到BL2
处执行。 - 在成功执行
PBI
命令后,Boot ROM
将控制传递给EL3
的BL2
映像。
- 当
- BL2
BL2
初始化DRAM
,配置TZASC
。BL2
在验证BL31
、BL32
和BL33
镜像后加载到DDR内存中。- 完成组件镜像验证后,
BL2
将执行控制权传递给名为BL31
的EL3
运行时固件映像。
- BL31
- 在
EL3
处设置异常向量表。 - 配置安全相关设置(
TZPC
)。 - 为引导加载程序和操作系统提供服务,例如控制核心电源状态和使其他核心退出重置。
- [可选]如果存在
BL32
镜像,则将执行控制权传递给可信操作系统(OP-TEE
)镜像BL32
。
- 在
- BL32
- [可选]初始化后,
BL32
将控制权返回给BL31
。
- [可选]初始化后,
- BL31
- 将执行控制传递给引导加载程序
U-Boot
/UEFI
,BL33
在EL2
。
- 将执行控制传递给引导加载程序
- BL33
- 加载并启动内核和其他固件映像(如果有的话)。
ARMv7
和 ARMv8
启动存在明显差异:
瑞芯微的实现
瑞芯微采用的方案和上述基本一致,以下是瑞芯微的说明文档:
+--------+----------------+----------+-------------+---------+
| Boot | Terminology #1 | Actual | Rockchip | Image |
| stage | | program | Image | Location|
| number | | name | Name | (sector)|
+--------+----------------+----------+-------------+---------+
| 1 | Primary | ROM code | BootRom | |
| | Program | | | |
| | Loader | | | |
| | | | | |
| 2 | Secondary | U-Boot |idbloader.img| 0x40 | pre-loader
| | Program | TPL/SPL | | |
| | Loader (SPL) | | | |
| | | | | |
| 3 | - | U-Boot | u-boot.itb | 0x4000 | including u-boot and atf
| | | | uboot.img | | only used with miniloader
| | | | | |
| | | ATF/TEE | trust.img | 0x6000 | only used with miniloader
| | | | | |
| 4 | - | kernel | boot.img | 0x8000 |
| | | | | |
| 5 | - | rootfs | rootfs.img | 0x40000 |
+--------+----------------+----------+-------------+---------+
瑞芯微根据 Pre-Loader(idbloader.img)
的开源与否规划了两种启动路线:
- MiniLoader:
瑞芯微对TPL/SPL
方案闭源的实现,效果和分工与TPL/SPL
类似:ddr.bin
负责初始化DRAM
,miniloader
是一个类似U-Boot
的引导程序;不同的是miniloader
需要一个独立的分区来存储TEE
的程序; - U-Boot(TPL/SPL):
U-Boot
是一个通用引导程序,其中有TPL/SPL
的开源实现;瑞芯微开源的U-Boot
是基于公版U-Boot
修改而来;
构建
OrangePi-3B
支持的正经官方 U-Boot
有三个:
- 香橙派
板子供应商,根据上游瑞芯微U-Boot
的修改版,对板子有良好的适配; - 瑞芯微
芯片供应商,使用Mainline
的2017.x
版本改写的U-Boot
,增加了对rk3566
芯片的深度支持。 - Mainline
主线U-Boot
,瑞芯微会不定时向主线合入对芯片的适配代码。支持度一般,但版本不受限制。
瑞芯微提供的 MiniLoader
不是成品镜像需要手动构建,但过程比较简单。
另外三种开源 U-Boot
构建类似,瑞芯微
和 香橙派
提供了构建脚本,以下内容以主线 U-Boot
为主。
瑞芯微 MiniLoader(MiniLoaderAll.bin + trust.img)
瑞芯微 MiniLoader
是一个包含 TPL
、SPL
、ATF
和 TEE
的组件包,全套都是闭源的。用它们来引导 U-Boot
可以获得原厂性能。
其他的 U-Boot
编译时也会或多或少引用这个库下面的闭源二进制镜像。
克隆代码
cd ~/projects/
git clone https://github.com/rockchip-linux/rkbin.git -b master
启动容器
docker run -ti --rm --privileged -v ~/projects/:/projects/ build-linux bash -l
- 关于镜像
build-linux
的内容请参考之前的笔记,其中已经安装构建所需要的软件包。
合成闭源的 Pre-Loader
Pre-Loader
也叫做 MiniLoaderAll.bin
。
cd /projects/rkbin/
./tools/boot_merger ./RKBOOT/RK3566MINIALL.ini
合成闭源的 trust.img
cd /projects/rkbin/
./tools/trust_merger ./RKTRUST/RK3568TRUST.ini
生成产物
rk356x_spl_loader_v1.xx.xxx.bin
Loader
镜像, 即MiniLoaderAll.bin
,烧录到Loader
或idbloader
分区使用。trust.img
搭配MiniLoaderAll.bin
使用的可信执行环境固件镜像, 烧录到trust
分区使用。
香橙派 U-Boot
克隆代码
cd ~/projects/
git clone https://github.com/rockchip-linux/rkbin.git -b master
git clone https://github.com/orangepi-xunlong/u-boot-orangepi.git -b v2017.09-rk3588 u-boot_orangepi
香橙派的
U-Boot
是基于的瑞芯微U-Boot
改进而来, 需要引用rkbin
的闭源镜像生成idbloader
;
启动容器
docker run -ti --rm --privileged -v ~/projects/:/projects/ build-linux bash -l
- 关于镜像
build-linux
的内容请参考之前的笔记,其中已经安装构建所需要的软件包。
启动编译
cd /projects/u-boot_orangepi/
./make.sh CROSS_COMPILE=aarch64-linux-gnu- orangepi-3b-rk3566
- 香橙派
U-Boot
基于瑞芯微开源的U-Boot
中2017.09
分支的代码,搭配的工具链版本不能太新(11.x 还能编译,切到 13.x 编译失败);
构建产物
u-boot_orangepi/rk356x_spl_loader_v1.xx.xxx.bin
Loader
镜像, 即MiniLoaderAll.bin
,烧录到Loader
或idbloader
分区使用。u-boot_orangepi/uboot.img
U-Boot
镜像,烧录到uboot
分区使用;
瑞芯微 U-Boot
克隆代码
cd ~/projects/
git clone https://github.com/rockchip-linux/rkbin.git -b master
git clone https://github.com/rockchip-linux/u-boot.git -b next-dev u-boot_rockchip
- 瑞芯微
U-Boot
需要引用rkbin
的闭源镜像生成idbloader
;
启动容器
docker run -ti --rm --privileged -v ~/projects/:/projects/ build-linux bash -l
- 关于镜像
build-linux
的内容请参考之前的笔记,其中已经安装构建所需要的软件包。
启动编译
cd /projects/u-boot_rockchip/
./make.sh CROSS_COMPILE=aarch64-linux-gnu- rk3566
- 瑞芯微的
U-Boot
基于主线2017.09
分支的代码,搭配的工具链版本不能太新(11.x 还能编译,切到 13.x 编译失败);
构建产物
u-boot_rockchip/rk356x_spl_loader_v1.xx.xxx.bin
Loader
镜像, 即MiniLoaderAll.bin
,烧录到Loader
或idbloader
分区使用。u-boot_rockchip/uboot.img
U-Boot
镜像,烧录到uboot
分区使用;
主线 U-Boot
2024-08-09
已经有人在主线提交OrangePi 3b
的适配代码, 本文的内容可能会有无法对其的情况. 请以提交记录为准.
https://source.denx.de/u-boot/u-boot/-/commit/a52099b4a2ae9e8cafc79268325249bcad308012
主线 U-Boot
默认配置构建时,需要依赖 ATF
和 OPTEE-OS
。如果忽略依赖直接按照正常方式直接编译,会报如下错误:
Image 'simple-bin' is missing external blobs and is non-functional: rockchip-tpl atf-bl31
/binman/simple-bin/mkimage/rockchip-tpl (rockchip-tpl):
An external TPL is required to initialize DRAM. Get the external TPL
binary and build with ROCKCHIP_TPL=/path/to/ddr.bin. One possible source
for the external TPL binary is https://github.com/rockchip-linux/rkbin.
/binman/simple-bin/fit/images/@atf-SEQ/atf-bl31 (atf-bl31):
See the documentation for your board. You may need to build ARM Trusted
Firmware and build with BL31=/path/to/bl31.bin
Image 'simple-bin' is missing optional external blobs but is still functional: tee-os
/binman/simple-bin/fit/images/@tee-SEQ/tee-os (tee-os):
See the documentation for your board. You may need to build Open Portable
Trusted Execution Environment (OP-TEE) and build with TEE=/path/to/tee.bin
Some images are invalid
make: *** [Makefile:1124: .binman_stamp] Error 103
- 对于
RK3566/RK3568
芯片,主线U-Boot
附带的开源组件只包含了SPL
;TPL
需要使用闭源的Rockchip-TPL
固件;BL31
即ATF(ARM Trusted Firmware)
,目前只能使用瑞芯微闭源的BL31
固件。BL32
即TEE(Trusted Execute Environment)
,基于TrustZone
技术搭建的安全执行环境;目前只能使用闭源的BL31
固件,开源版本有OPTEE-OS
,但目前不支持。ATF
是一组开源固件和引导加载程序,用于启动ARM
架构设备。它负责引导设备,初始化硬件,启动OPTEE-OS
以及其他运行时环境,如操作系统。OPTEE-OS
提供了TEE
的操作系统和运行时环境。它是一个用于构建安全应用程序和服务的软件栈。OPTEE-OS
和ATF
协同工作,用于实现设备的安全引导和可信执行环境。ATF
负责设备的初始化和引导,然后将控制权传递给OPTEE-OS
,从而确保TEE
的安全性和可信性。这两个项目是嵌入式系统中安全和可信计算的关键组件。
截止2024年1月,ATF
和 OPTEE-OS
均没有对 RK35XX
系列芯片提供支持。笔者试过强行使用现有代码,最终还是失败了!本文会贴一下这两个组件的编译方法,但如无必要无需尝试。
克隆代码
cd ~/projects/
git clone https://github.com/rockchip-linux/rkbin.git -b master
git clone https://github.com/u-boot/u-boot.git -b master
- 主线
U-Boot
需要引用rkbin
的闭源镜像生成idbloader
;
启动容器
docker run -ti --rm --privileged -v ~/projects/:/projects/ build-linux bash -l
- 关于镜像
build-linux
的内容请参考之前的笔记,其中已经安装构建所需要的软件包。
驱动有线网卡
使用 evb-rk3568
设备树不能正确驱动 orangepi-3b
的有线网卡,这里拷贝一份并修改一下:
diff --git a/arch/arm/dts/rk3568-evb.dts b/arch/arm/dts/rk3568-orangepi-3b.dts
index 674792567f..6f5e599979 100644
--- a/arch/arm/dts/rk3568-evb.dts
+++ b/arch/arm/dts/rk3568-evb.dts
@@ -206,13 +206,13 @@
assigned-clock-rates = <0>, <125000000>;
clock_in_out = "output";
phy-handle = <&rgmii_phy1>;
- phy-mode = "rgmii-id";
+ phy-mode = "rgmii";
pinctrl-names = "default";
- pinctrl-0 = <&gmac1m1_miim
- &gmac1m1_tx_bus2
- &gmac1m1_rx_bus2
- &gmac1m1_rgmii_clk
- &gmac1m1_rgmii_bus>;
+ pinctrl-0 = <&gmac1m0_miim
+ &gmac1m0_tx_bus2
+ &gmac1m0_rx_bus2
+ &gmac1m0_rgmii_clk
+ &gmac1m0_rgmii_bus>;
status = "okay";
};
@@ -525,7 +525,7 @@
reg = <0x0>;
reset-assert-us = <20000>;
reset-deassert-us = <100000>;
- reset-gpios = <&gpio2 RK_PD1 GPIO_ACTIVE_LOW>;
+ reset-gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>;
};
};
arch/arm/dts/rk3568-orangepi-3b.dts
为拷贝并修改后的设备树文件。- 板子集成的
YT8531
的物理网卡芯片,YT8531
和RTL8211
可以片对片替换。
新建 U-Boot
配置文件
上一步骤增加了 arch/arm/dts/rk3568-orangepi-3b.dts
设备树文件,接下来新建一份属于 orangepi-3b
的编译配置文件。专业名称叫“本地化”。
CONFIG_ARM=y
CONFIG_SKIP_LOWLEVEL_INIT=y
CONFIG_COUNTER_FREQUENCY=24000000
CONFIG_ARCH_ROCKCHIP=y
CONFIG_DEFAULT_DEVICE_TREE="rockchip/rk3566-orangepi-3b"
CONFIG_ROCKCHIP_RK3568=y
CONFIG_SPL_SERIAL=y
CONFIG_DEBUG_UART_BASE=0xFE660000
CONFIG_DEBUG_UART_CLOCK=24000000
CONFIG_SYS_LOAD_ADDR=0xc00800
CONFIG_DEBUG_UART=y
CONFIG_FIT=y
CONFIG_FIT_VERBOSE=y
CONFIG_SPL_FIT_SIGNATURE=y
CONFIG_SPL_LOAD_FIT=y
CONFIG_LEGACY_IMAGE_FORMAT=y
CONFIG_DEFAULT_FDT_FILE="rockchip/rk3566-orangepi-3b.dtb"
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_DISPLAY_BOARDINFO_LATE=y
CONFIG_SPL_MAX_SIZE=0x40000
CONFIG_SPL_PAD_TO=0x7f8000
# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
CONFIG_SPL_ATF=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_GPT=y
CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_PMIC=y
CONFIG_CMD_REGULATOR=y
# CONFIG_SPL_DOS_PARTITION is not set
CONFIG_SPL_OF_CONTROL=y
CONFIG_OF_LIVE=y
CONFIG_OF_SPL_REMOVE_PROPS="clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
CONFIG_SPL_DM_SEQ_ALIAS=y
CONFIG_SPL_REGMAP=y
CONFIG_SPL_SYSCON=y
CONFIG_SPL_CLK=y
CONFIG_ROCKCHIP_GPIO=y
CONFIG_SYS_I2C_ROCKCHIP=y
CONFIG_MISC=y
CONFIG_SUPPORT_EMMC_RPMB=y
CONFIG_MMC_DW=y
CONFIG_MMC_DW_ROCKCHIP=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_SDMA=y
CONFIG_MMC_SDHCI_ROCKCHIP=y
CONFIG_PHY_REALTEK=y
CONFIG_DWC_ETH_QOS=y
CONFIG_DWC_ETH_QOS_ROCKCHIP=y
CONFIG_SPL_PINCTRL=y
CONFIG_DM_PMIC=y
CONFIG_PMIC_RK8XX=y
CONFIG_REGULATOR_RK8XX=y
CONFIG_PWM_ROCKCHIP=y
CONFIG_SPL_RAM=y
CONFIG_BAUDRATE=1500000
CONFIG_DEBUG_UART_SHIFT=2
CONFIG_SYS_NS16550_MEM32=y
CONFIG_SYSRESET=y
CONFIG_ERRNO_STR=y
# 自定义功能
CONFIG_ARM64=y
CONFIG_BOOTSTD_FULL=y
CONFIG_DFU_MMC=y
CONFIG_DFU_RAM=y
CONFIG_ENV_IS_IN_MMC=y
CONFIG_LED=y
CONFIG_NVME=y
# NET
CONFIG_NET=y
CONFIG_PHY_REALTEK=y
CONFIG_DWC_ETH_QOS=y
CONFIG_DWC_ETH_QOS_ROCKCHIP=y
# USB
CONFIG_USB=y
CONFIG_USB_STORAGE=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_MANUFACTURER="Rockchip"
CONFIG_USB_GADGET_VENDOR_NUM=0x18d1
CONFIG_USB_GADGET_PRODUCT_NUM=0xd00d
CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_USB_FUNCTION_FASTBOOT=y
CONFIG_DM_USB_GADGET=y
# USB 1.1
CONFIG_USB_UHCI_HCD=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_GENERIC=y
# USB 2.0
CONFIG_USB_DWC2=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_GENERIC=y
# USB 3.0
CONFIG_USB_DWC3=y
CONFIG_USB_DWC3_GADGET=y
CONFIG_USB_DWC3_GENERIC=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
# FASTBOOT
CONFIG_ANDROID_BOOT_IMAGE=y
CONFIG_FASTBOOT=y
CONFIG_FASTBOOT_FLASH=y
CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
CONFIG_FASTBOOT_BUF_ADDR=0x00A00000
CONFIG_FASTBOOT_BUF_SIZE=0x0A000000
# 命令大全
CONFIG_CMD_2048=y
CONFIG_CMD_ABOOTIMG=y
CONFIG_CMD_ADC=y
CONFIG_CMD_ADTIMG=y
CONFIG_CMD_AES=y
CONFIG_CMD_BCB=y
CONFIG_CMD_BDINFO_EXTRA=y
CONFIG_CMD_BINOP=y
CONFIG_CMD_BOOTM=y
CONFIG_CMD_BOOTDEV=y
CONFIG_CMD_BOOTEFI_HELLO=y
CONFIG_CMD_BOOTEFI_HELLO_COMPILE=y
CONFIG_CMD_BOOTFLOW_FULL=y
CONFIG_CMD_BOOTMENU=y
CONFIG_CMD_BOOTMETH=y
CONFIG_CMD_CAT=y
CONFIG_CMD_DFU=y
CONFIG_CMD_EEPROM=y
CONFIG_CMD_ERASEENV=y
CONFIG_CMD_EROFS=y
CONFIG_CMD_ETHSW=y
CONFIG_CMD_EVENT=y
CONFIG_CMD_FLASH=y
CONFIG_CMD_FASTBOOT=y
CONFIG_CMD_LSBLK=y
CONFIG_CMD_PWM=y
CONFIG_CMD_MBR=y
CONFIG_CMD_INI=y
CONFIG_CMD_LED=y
CONFIG_CMD_MD5SUM=y
CONFIG_CMD_MEMINFO=y
CONFIG_CMD_MEM_SEARCH=y
CONFIG_CMD_MISC=y
CONFIG_CMD_NFS=y
CONFIG_CMD_NVME=y
CONFIG_CMD_PCAP=y
CONFIG_CMD_READ=y
CONFIG_CMD_SDRAM=y
CONFIG_CMD_SHA1SUM=y
CONFIG_CMD_SPI=y
CONFIG_CMD_STRINGS=y
CONFIG_CMD_TFTPPUT=y
CONFIG_CMD_TFTPSRV=y
CONFIG_CMD_USB=y
CONFIG_CMD_USB_MASS_STORAGE=y
CONFIG_CMD_WOL=y
CONFIG_CMD_WRITE=y
# 自定义启动命令
CONFIG_BOOTDELAY=0
CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS=""
CONFIG_USE_BOOTCOMMAND=y
CONFIG_BOOTCOMMAND="bootflow scan -b"
configs/orangepi-3b-rk3566_defconfig
修改自orangepi-3b-rk3566_defconfig
配置文件。2024.05
主线开启了OF_UPSTREAM
特性,大量设备树迁移到了dts/upstream/src/arm64/
路径下,不需要在arch/arm/dts/Makefile
中添加设备树的编译配置了,改变为通过CONFIG_DEFAULT_DEVICE_TREE
设置默认的设备树即可。
编译 U-Boot
cd /projects/u-boot/
# 清除缓存[可选]
rm -rf build
make O=build clean
make O=build mrproper
make O=build distclean
# 应用配置
make CROSS_COMPILE=aarch64-linux-gnu- O=build orangepi-3b-rk3566_defconfig
# 图形化配置
make CROSS_COMPILE=aarch64-linux-gnu- O=build menuconfig
# 编译
make \
CROSS_COMPILE=aarch64-linux-gnu- \
ROCKCHIP_TPL=../rkbin/bin/rk35/rk3566_ddr_1056MHz_v1.23.bin \
BL31=../rkbin/bin/rk35/rk3568_bl31_v1.44.elf \
TEE= \
O=build -j8
- 主线
U-Boot
代码可以使用最新的工具链编译。- 主线
U-Boot
没有提交RK3566
的默认配置,使用RK3568
配置代替。- 使用
make
的O=build
参数重定向的编译输出产物的目录为build
。ROCKCHIP_TPL
这个必须使用rkbin
的闭源固件。BL31
也只能使用rkbin
的闭源固件,用PX30
平台编译的BL31
固件无法启动U-Boot
。TEE(BL32)
请一定留空!之前实验的时候强行使用PX30
编译的固件../optee_os/out/arm-plat-rockchip/core/tee.elf
,虽然U-Boot
启动不报错,但引导内核动不动就卡死,足足坑我一个月的时间,各种怀疑人生!(我也试过传入瑞芯微闭源的../rkbin/bin/rk35/rk3568_bl32_v2.10.bin
,但是编译系统需要传入elf
格式的文件。最终答案就是目前没有一个BL32
能用)- 为什么怀疑内核启动不了可能是由于错误的
TEE
导致的?因为我发现官方的镜像U-Boot
启动的时候也没有TEEOS
(SPL
加载BL32
报错失败)。
编译产物
u-boot/build/idbloader.img
Pre-Loader
镜像,烧录到idbloader
分区使用;u-boot/build/u-boot.img
U-Boot
镜像,烧录到uboot
分区使用,不加载ATF
,网卡会用不了;u-boot/build/u-boot.itb
U-Boot
镜像,烧录到uboot
分区使用,各项功能正常(当然是没有TEE
的);
针对 OrangePi 3B
的改动记录
https://github.com/lx0758/u-boot/commits/orangepi-3b/
编译 ATF
& OPTEE-OS
实测 RK3566
无法使用仅做记录,如无必要无需尝试。
克隆代码
cd ~/projects/
git clone https://github.com/ARM-software/arm-trusted-firmware.git -b master
git clone https://github.com/OP-TEE/optee_os.git -b master
启动容器
docker run -ti --rm -v ~/projects/:/projects/ build-linux bash
- 关于镜像
build-linux
的内容请参考之前的笔记,其中已经安装构建所需要的软件包。
编译
# 编译 ATF
cd /projects/arm-trusted-firmware/
make clean
make realclean
make CROSS_COMPILE=aarch64-linux-gnu- PLAT=rk3568
# 编译 OPTEE-OS
cd /projects/optee_os/
rm -rf out
make clean
make \
CROSS_COMPILE32=arm-linux-gnueabi- \
CROSS_COMPILE64=aarch64-linux-gnu- \
PLATFORM=rockchip-px30 \
CFG_ARM64_core=y
ATF
目前已经适配了RK3568
的平台。OPTEE-OS
还不支持RK3568
,所以使用PX30
作为演示。
编译产物
arm-trusted-firmware/build/px30/release/bl31/bl31.elf
ATF
固件;optee_os/out/arm-plat-rockchip/core/tee.elf
&/optee_os/out/arm-plat-rockchip/core/tee.bin
OPTEE-OS
固件;
烧写镜像
烧写工具
RKDevTool
是瑞芯微在 Windows
下的芯片烧写工具,和芯片内置的 MaskROM Mode
搭配实现裸机烧写。
分区表
目前只是研究 U-Boot
,根据瑞芯微的 Wiki文档 - 启动模式 和 Wiki文档 - 分区结构 说明的扇区指导,自建了一个分区表文件,借助 RKDevTool
可以进行分区表写入。
文件 parameter.txt
内容如下:
FIRMWARE_VER: 1.0
MACHINE_MODEL: orangepi-3b
MACHINE_ID: 007
MANUFACTURER: rockchip
MAGIC: 0x5041524B
ATAG: 0x00200800
MACHINE: rk3566_r
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
TYPE: GPT
CMDLINE:mtdparts=rk29xxnand:0x00003FC0@0x00000040(idbloader),0x00004000@0x00004000(uboot),0x00002000@0x00008000(trust),0x00036000@0x0000A000(boot),-@0x00040000(rootfs:grow)
- idbloader
用于存放前级引导ddr/miniloader
或TPL/SPL
的区块 - uboot
用于存放 U-Boot 的区块 - trust
用于存放trust.img
的区块(仅miniloader
方式需要) - boot
用于存放Kernel
的分区 - rootfs
用于存放RootFS
的分区
使用 RKDevTool
写入分区表只需要使用一个地址指向 0x00000000
名为 parameter
的条目,路径指向 parameter.txt
然后执行即可。
注意文件中分区的地址和尺寸指的都是扇区,每个扇区是
512Byte
大小。
烧写配置
# | □ | 存储 | 地址 | 名字 | 路径 | … |
---|---|---|---|---|---|---|
1 | □ | 0x00000000 | Loader | MiniLoaderAll.bin | ||
2 | □ | 0x00000000 | parameter | parameter.txt | ||
3 | □ | 0x00000040 | idbloader | idbloader.img | ||
4 | □ | 0x00004000 | uboot | uboot.img/u-boot.itb | ||
5 | □ | 0x00008000 | trust | trust.img | ||
6 | □ | 0x0000A000 | boot | |||
7 | □ | 0x00040000 | rootfs |
- 注意存储位置, 老版本的
RKDevTool
没有存储
那一列,则需要先在高级功能
中切换为对应的存储器;操作之前需要先下载Loader
;- 事实上
MiniLoaderAll.bin
直接刷入idbloader
分区也是可以正常工作的;Loader
和idbloader
不能同时刷入同一个存储设备,idbloader
会被Loader
覆盖;
调试
如果需要经常调试 Kernel
或 RootFS
,可以使用 U-Boot
加载并启动 NFS
中的 Kernel
和 RootFS
# 挂载 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
U-Boot
的 NFS 协议只能支持2
,为了兼容给NFS
服务器的3
协议关了。但是Kernel
使用NFS
的默认协议是3
,这里强制指定为4
。
使用 U-Boot
加载并启动 USB
设备中的 Kernel
和 RootFS
# 挂载 U盘 为 ROOTFS
setenv bootargs "earlycon console=ttyS2,1500000n8 root=/dev/sda1 rw rootfstype=ext4 rootwait"
# 通过 U盘 加载 Kernel
usb start
load usb 0:1 0x4000000 /boot/Image.gz
load usb 0:1 0x2000000 /boot/initramfs.img
load usb 0:1 0x1000000 /boot/dts/rockchip/rk3566-orangepi-3b.dtb
booti 0x4000000 0x2000000 0x1000000;
使用 U-Boot
加载并启动 MMC
设备中的 Kernel
和 RootFS
# 挂载 MMC 为 ROOTFS
setenv bootargs "earlycon console=ttyS2,1500000n8 root=/dev/mmcblk0p1 rw rootfstype=ext4 rootwait"
# 通过 MMC 加载 Kernel
load mmc 0:1 0x4000000 /boot/Image.gz
load mmc 0:1 0x2000000 /boot/initramfs.img
load mmc 0:1 0x1000000 /boot/dts/rockchip/rk3566-orangepi-3b.dtb
booti 0x4000000 0x2000000 0x1000000