香橙派Zero 3 U-Boot编译实战:BL31与Crust固件疑难解析

当你在深夜的调试中看到串口终端突然跳出两遍U-Boot启动日志时,那种既兴奋又困惑的感觉,相信每个嵌入式开发者都深有体会。香橙派Zero 3作为全志H618平台的代表,其U-Boot编译过程中BL31和Crust固件的集成堪称"新人杀手"。本文将从实际故障现象出发,带你穿透表象理解底层机制,避开那些让开发者抓狂的典型陷阱。

1. 编译环境配置的隐形陷阱

交叉编译工具链的选择往往是最初的绊脚石。许多开发者会忽略全志H618芯片的双重特性——它既是Cortex-A53架构的64位处理器,又需要32位工具链处理AR100协处理器上的Crust固件。

1.1 工具链版本冲突

推荐使用以下组合:

# AArch64主处理器工具链
gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu
# AR100协处理器工具链
or1k-linux-musl-cross

常见错误症状包括:

  • BL31编译时报 illegal instruction
  • Crust固件链接阶段出现 unrecognized relocation 警告
  • U-Boot启动时卡在 Starting SCP... 阶段

注意:切勿使用Ubuntu仓库中的默认交叉编译器,其缺少全志平台特定的指令集支持。

1.2 环境变量污染

.bashrc 中残留的旧版工具链路径会导致微妙的编译错误。建议创建隔离的编译环境:

mkdir -p ~/orangepi_build && cd ~/orangepi_build
cat > env_setup.sh <<'EOF'
export PATH="/opt/toolchains/aarch64-gcc/bin:/opt/toolchains/or1k-gcc/bin:$PATH"
export CROSS_COMPILE_AARCH64=aarch64-none-linux-gnu-
export CROSS_COMPILE_AR100=or1k-linux-musl-
EOF
source env_setup.sh

验证环境是否正确的快速方法:

aarch64-none-linux-gnu-gcc --version | grep 11.2
or1k-linux-musl-gcc --version | grep musl

2. BL31固件的配置玄机

全志H618与H616的关系就像孪生兄弟——硬件设计相似但存在关键差异。官方文档对此语焉不详,导致开发者常陷入平台选择的困境。

2.1 平台选择困境

arm-trusted-firmware/plat/allwinner 目录下,你会看到多个相似平台:

sun50i_h6/      # 原始H6平台
sun50i_h616/    # H616专用
sun50i_h618/    # 官方未提供

实际测试表明不同选项的表现差异:

PLAT参数 启动成功率 内存初始化 CPU频率识别
sun50i_h6 60% 不稳定 错误显示1.5GHz
sun50i_h616 95% 稳定 正确显示1.8GHz
sun50i_a64 无法启动 - -

最佳实践

make PLAT=sun50i_h616 DEBUG=1 bl31

2.2 调试符号的副作用

DEBUG=1参数在开发阶段很有用,但会产生两个隐患:

  1. 生成的BL31.bin体积过大(约800KB),可能超出引导区预留空间
  2. 串口输出过多调试信息干扰正常启动日志

建议发布版本移除DEBUG参数:

make PLAT=sun50i_h616 bl31

3. Crust固件的电源管理迷局

Crust作为全志特有的电源管理固件,其配置复杂度往往被低估。当系统出现以下症状时,很可能就是Crust在作祟:

  • 无法正常关机(卡在 reboot: Power down
  • 重启变成关机
  • 系统唤醒后外设失效

3.1 配置文件选择策略

crust/configs 目录下,与H618最接近的配置是:

orangepi_3_defconfig     # H6方案
orangepi_zero3_defconfig # 官方提供但存在缺陷

实测发现直接使用 orangepi_3_defconfig 反而更稳定。关键修改点:

# 修改crust/configs/orangepi_3_defconfig
-CONFIG_PSYCHO_CPU_VOLT=1100
+CONFIG_PSYCHO_CPU_VOLT=1200  # H618需要更高电压

3.2 编译时的线程陷阱

虽然多线程编译(make -j)能加快速度,但Crust编译系统对并行处理支持不佳。建议:

make orangepi_3_defconfig
make -j2 scp  # 限制在2个线程以内

常见编译错误及解决方案:

  • 错误1 or1k-linux-musl-ld: cannot find -lgloss 解决方法:在Makefile中添加 LDFLAGS += -nostdlib

  • 错误2 undefined reference to __stack_chk_guard' 解决方法:禁用栈保护 CFLAGS += -fno-stack-protector`

4. U-Boot集成时的典型故障

当BL31和Crust都编译成功后,集成到U-Boot阶段仍然可能遇到各种"灵异现象"。以下是几个最令人抓狂的案例:

4.1 双重启动之谜

串口输出中出现两遍U-Boot日志,通常表现为:

U-Boot SPL 2023.04
Trying to boot from MMC1
U-Boot SPL 2023.04
Trying to boot from MMC1

根本原因在于:

  1. SPL没有正确识别BL31加载状态
  2. 设备树中 /chosen 节点冲突

解决方案分三步:

# 1. 修改include/configs/sunxi-common.h
-#define CONFIG_SPL_BOARD_LOAD_IMAGE
+#undef CONFIG_SPL_BOARD_LOAD_IMAGE

# 2. 更新设备树
&pmu {
    status = "okay";
};

# 3. 重新编译时确保清除旧配置
make mrproper

4.2 环境变量传递失效

BL31参数无法正确传递给内核的表现:

  • 内核启动时卡在 Starting kernel ...
  • 系统无法识别内存容量
  • CPU频率显示异常

关键检查点:

  1. 确认BL31路径导出为绝对路径

    export BL31=$(pwd)/arm-trusted-firmware/build/sun50i_h616/debug/bl31.bin
    
  2. 验证U-Boot的 bootm 命令是否包含 bl31_phys_addr 参数

    setenv bootargs 'earlyprintk console=ttyS0,115200 bl31_phys_addr=0x44000000'
    
  3. 检查 .config 中的关键选项:

    CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT=y
    CONFIG_ARMV8_PSCI=y
    

4.3 电源管理异常

当出现以下情况时,需要检查Crust集成:

  • 按电源键无响应
  • 系统无法唤醒
  • 重启后外设初始化失败

调试步骤:

  1. 确认SCP路径导出正确

    export SCP=$(pwd)/crust/build/scp/scp.bin
    
  2. 在U-Boot中测试电源管理功能:

    # 测试关机
    pmic shutdown
    # 测试重启
    pmic reboot
    
  3. 必要时可临时禁用Crust:

    export SCP=/dev/null
    

5. 烧录与调试实战技巧

当所有组件编译通过后,最后的烧录阶段仍然暗藏杀机。以下是从数十次失败中总结的宝贵经验。

5.1 TF卡分区布局陷阱

官方推荐的 dd 命令存在隐患:

sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdb bs=1024 seek=8

更安全的方案是:

  1. 先擦除前1MB:

    sudo dd if=/dev/zero of=/dev/sdb bs=1k count=1024
    
  2. 精确写入SPL:

    sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdb bs=512 seek=16 conv=fsync
    

分区表建议采用以下结构:

/dev/sdb1 - 200M FAT32 (boot)
/dev/sdb2 - 剩余空间 EXT4 (rootfs)

5.2 串口调试进阶技巧

当系统无法启动时,可以尝试:

  1. 在U-Boot中手动加载BL31:

    load mmc 0:1 0x44000000 bl31.bin
    dcache flush
    go 0x44000000
    
  2. 检查内存映射:

    md 0x44000000 0x100  # 查看BL31头部
    md 0x40000000 0x100  # 检查SCP区域
    
  3. 关键地址列表:

    BL31加载地址:0x44000000
    SCP加载地址:0x40000000
    U-Boot入口:0x4a000000
    

5.3 性能优化参数

include/configs/sunxi-common.h 中添加:

#define CONFIG_SYS_BOOTM_LEN (32 << 20)  // 增加内核加载空间
#define CONFIG_SYS_MALLOC_LEN (32 << 20) // 扩大内存池

对于H618特有的设置:

#define CONFIG_SUNXI_DRAM_H618
#define CONFIG_MACH_TYPE 0x00001000

在香橙派Zero 3的调试过程中,最令我难忘的是发现BL31版本与Crust的微妙交互问题——当使用DEBUG版本的BL31时,Crust的电源管理会间歇性失效。这个教训让我明白,嵌入式开发中有时"少即是多",精简的发布版本反而能带来更稳定的表现。

更多推荐