- 嵌入式
- 构建工具
- 操作系统
【免费下载链接】build
The official build framework for the Armbian Linux distribution. This repository contains the complete toolchain and scripts required to compile custom OS images from source, including kernel configuration, U-Boot handling, and board-specific tweaks for various ARM and ARM64 single-board computers.
导读
本文深入解析 Armbian 官方构建框架中为 Radxa 厂商 U-Bootnext-dev-v2024.10分支定制的补丁集(目录 patch/u-boot/legacy/u-boot-radxa-rk35xx-v2024.10)。该补丁集集中解决了 Rock 4D(RK3576)等板卡在启动阶段遇到的 GPT 分区表校验崩溃、UFS/SCSI 查询数据错位、4096 字节原生扇区几何失真、多块读取尾块清零等底层问题。读完本文,你将理解这些补丁背后的 DMA 缓存一致性、GPT 探测流程与 SCSI 命令构造原理,并掌握它们在 Armbian 板卡配置与构建流程中的挂载方式。
一、补丁集的定位:为next-dev-v2024.10分支而设
目录内的 README.md 开宗明义地指出:本补丁集只面向 Radxa 的next-dev-v2024.10分支,不适用于更早的next-dev-v2024.03分支——后者仍被 mixtile-blade3 和 Mekotronics rk3588 系列板卡锁定使用,因为 2024.10+ 会破坏它们的 stable-MAC 补丁。
这套"一个 U-Boot 分支配套一个补丁目录"的策略,在 Armbian 构建框架中通过BOOTPATCHDIR变量落实。查看 config/sources/families/rk35xx.conf 可以看到:
BOOTSOURCE='https://github.com/radxa/u-boot.git' BOOTBRANCH='branch:next-dev-v2024.10' # Always use same version as rk3588, they share a patch dir BOOTPATCHDIR="legacy/u-boot-radxa-rk35xx legacy/u-boot-radxa-rk35xx-v2024.10" # v2024.10 dir: patches that need the newer Radxa branch (not 2024.03 boards)注释说得非常直白:BOOTPATCHDIR同时列出基础补丁目录legacy/u-boot-radxa-rk35xx和增量补丁目录legacy/u-boot-radxa-rk35xx-v2024.10,后者专门存放依赖新版 Radxa 分支的补丁,2024.03 的板卡只使用基础目录。同样的配置也出现在 rockchip-rk3588.conf、seeed-rk3588.conf 与 seeed-rk3576.conf 中,因为它们共享同一套 Radxa U-Boot 源码与补丁目录。
在构建链路上,BOOTPATCHDIR的值会被 lib/functions/compilation/uboot-patching.sh 以PATCH_DIRS_TO_APPLY=${BOOTPATCHDIR}的形式传入 Python 补丁脚本 lib/tools/patching.py,由其对radxa/u-boot克隆目录依次应用目录中的全部.patch文件,并记录补丁哈希用于产物版本追踪(见 artifact-uboot.sh)。
二、GPT 补丁:对齐 mainline 探测逻辑,修复 Rock 4D 启动崩溃
问题背景:RKIMG 路径的 GPT 校验/修复在每次part_init()时触发
fix-part-efi-gpt-crash-on-unformatted-storage.patch 的提交信息描述了一个严重的启动故障:下游 Rockchip U-Boot 在开启CONFIG_RKIMG_BOOTLOADER后,会在part_test_efi()内于每一次part_init()(包括 SCSI/UFS/MTD 扫描)时运行 RKIMG 的 GPT 校验与修复逻辑;而 mainline U-Boot 只检查保护性 MBR(protective MBR)。这条额外的代码路径会在某些介质上通过gpt_entry_modify()的下溢(underflow)造成堆破坏(heap corruption),并在有效 GPT 被用于启动之前就中止引导。
修复一:PTE 数组的"不可能几何"预检
补丁在part_efi.c分配 GPT 分区表项(PTE)之前新增一道防线:一旦读取到垃圾头部(garbage header),立即拒绝:
if (le32_to_cpu(gpt_h->num_partition_entries) == 0 || le32_to_cpu(gpt_h->num_partition_entries) > 512 || le32_to_cpu(gpt_h->sizeof_partition_entry) != sizeof(gpt_entry)) { printf("GPT: invalid partition entry geometry: entries=%u size=%u\n", le32_to_cpu(gpt_h->num_partition_entries), le32_to_cpu(gpt_h->sizeof_partition_entry)); return -1; }关键点在于上限取512而不是 Radxa 默认的CONFIG GPT_ENTRY_NUMBERS(该值为 64)——因为 Armbian 镜像和 mainline U-Boot 普遍使用128 项 GPT,若按 64 硬性限制会误杀合法磁盘。补丁注释明确说明这一取舍:"Do not use GPT_ENTRY_NUMBERS (often 64 on Radxa) — Armbian images commonly ship 128-entry GPTs like mainline."同时保留CONFIG_SPL_SYS_MALLOC_SIMPLE所需的 PTE 复用捷径,避免耗尽 SPL 的malloc_simple内存池。
修复二:gpt_entry_modify()的空项下溢
原代码循环for (i = 0; i < gpt_head->num_partition_entries; i++)且未转换字节序(应使用le32_to_cpu),若第一项就无效则i == 0,随后访问gpt_pte[i - 1]即为越界写,这正是堆破坏的来源。补丁将其改为:
for (i = 0; i < le32_to_cpu(gpt_head->num_partition_entries); i++) { if (!is_pte_valid(&gpt_pte[i])) break; } /* No valid entries: do not index gpt_pte[i - 1] (heap corruption). */ if (i == 0) return;修复三:删除part_test_efi()中的 RKIMG 校验/修复块
补丁用大段删除把CONFIG_RKIMG_BOOTLOADER下的"每次扫描即校验并修复主/备份 GPT"逻辑整体移除,回归 mainline 语义:part_test_efi()只负责确认保护性 MBR,真正的 GPT 校验推迟到分区实际被使用的part_get_info_efi()阶段。这既消除了崩溃点,也避免了对未格式化(unformatted)存储介质做无谓的修复写入。
三、UFS/SCSI 补丁之一:PRDT DMA 目标缓冲对齐(tempbuff)
fix-scsi-ufs-dma-aligned-tempbuff.patch 修复了 Rock 4D UFS 的 INQUIRY/CAPACITY 数据"移位 2 字节"的诡异现象:厂商字符串SAMSUNG显示成MSUNG、产品名缺首字符、类型字段异常、块大小离谱(如 268456769)。
根因:drivers/scsi/scsi.c使用了一个未对齐的 BSS 缓冲区tempbuff(地址以...5e结尾,addr%4==2)作为 UFSHCI PRDT 的 DMA 目标。PRDT 要求双字(dword)对齐的地址,于是控制器比软件解析指针提前写了两个字节。mainline U-Boot 早已改用DEFINE_CACHE_ALIGN_BUFFER声明该缓冲,补丁照搬之:
static unsigned char tempbuff[512]; /* temporary data buffer */ // 改为: DEFINE_CACHE_ALIGN_BUFFER(u8, tempbuff, 512); /* temporary data buffer */同时把pccb->pdata = (unsigned char *)&tempbuff;改为pccb->pdata = tempbuff;(DEFINE_CACHE_ALIGN_BUFFER返回的是数组名,取址反而引入偏移)。
四、UFS/SCSI 补丁之二:保留 4096 原生几何,对齐 mainline 语义
fix-scsi-ufs-native-4096-geometry.patch 针对下游把 UFS 4096 字节设备强制转成 512e 逻辑块、并把 LUN 塞进 SCSI CDB 的做法。在 Rock 4D 上,这会导致 INQUIRY/CAPACITY 损坏(厂商名乱码、块大小荒谬),进而使 GPT 校验报出my_lba incorrect——因为分区 I/O 与 mainline 能正常引导的 4096 原生 GPT 不再匹配。
补丁逐点对齐 mainline 行为:
- CDB 中不再编码 LUN:
pccb->cmd[1] = pccb->lun << 5全部改为pccb->cmd[1] = 0(READ16/READ10/WRITE10/INQUIRY/TST_U_RDY/RD_CAPAC10),因为 UFS 的 LUN 由 UPIU(UTP 协议信息单元)承载,无需塞进命令块; - READ CAPACITY 的 last LBA 按含入处理:
*capacity += 1;(mainline 语义,防止容量少算一块); - 512e 换算仅在真正发生重映射时启用:
rawsectsz由block_dev->rawblksz / 512改为条件式(block_dev->blksz == 512 && block_dev->rawblksz == 4096) ? 8 : 1; - 设备探测不再改写几何:删除
if (bdesc->rawblksz == 4096)下把blksz改为 512、rawlba++、lba = rawlba * 8的整个 512e 模拟分支,改为直接bdesc->log2blksz = bd.log2blksz;保留原生 4096 几何。
五、UFS/SCSI 补丁之三:DMA 缓存一致性(多块读取尾块清零)
fix-ufs-dma-cache-coherency-like-mainline.patch 是问题最深的一处。Radxa 的prepare_prdt_table()在每次传输开始前都 invalidatepccb->pdata的缓存。在 RK3576 上,这会打开一个窗口:CPU 的推测性填充(speculative fill)会重新装载陈旧缓存行,而 UFS 控制器同时在向 DRAM 写入。单块 READ 往往"碰巧正确",多块 READ 则表现为"返回 OK 但尾块全零"(补丁提交信息给出了实测对照:scsi read LBA0 count=2与LBA1 count=1结果不一致)。
mainline 的ufs-uclass.c在 DMA 前并不 invalidate 数据缓冲,而是在ufshcd_send_command之前 flush、之后 invalidate。补丁照此重写:
- 新增
ufshcd_cache_flush()/ufshcd_cache_invalidate()两个辅助函数,缓存区间统一按[aligned_start, aligned_end)计算(start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1),end_addr = ALIGN(addr + size, ARCH_DMA_MINALIGN)),替代原先aaddr + ALIGN(size, ...)的错误区间数学; ufshcd_cache_flush_and_invalidate()只保留给 UTRD/UCD 描述符使用,且改为分别调用上述两个新函数;prepare_prdt_table()中不再触碰pccb->pdata的缓存,仅在ufs_send_scsi_cmd()中按 mainline 顺序执行:
if (pccb->datalen) ufshcd_cache_flush(pccb->pdata, pccb->datalen); if (ufshcd_send_command(hba, TASK_TAG) == -ETIMEDOUT && retry_count) { retry_count--; goto retry; } if (pccb->datalen) ufshcd_cache_invalidate(pccb->pdata, pccb->datalen);补丁末尾注明:这一改动取代了此前针对原生 4K UFS 的单块 SCSI I/O 权宜之计(即上一节提到的 512e 重映射模拟),真正从缓存一致性层面根治问题。
六、Rock 4D SPI 配置补丁:128 项 GPT 分区表
rock-4d-spi-efi-partition-entries-128.patch 是一处 defconfig 修正:Radxa 默认CONFIG_EFI_PARTITION_ENTRIES_NUMBERS=64,而 Armbian 镜像与 mainline U-Boot 使用 128 项 GPT。因此将 Rock 4D SPI 启动场景(configs/rock-4d-spi-rk3576_defconfig)的配置提升到 128:
-CONFIG_EFI_PARTITION_ENTRIES_NUMBERS=64 +CONFIG_EFI_PARTITION_ENTRIES_NUMBERS=128这与第二节 GPT 补丁中"拒绝以 64 作为 PTE 上限"的思路一脉相承:两者共同保证 Armbian 的 128 项 GPT 在 Radxa 厂商 U-Boot 的 SPL 与完整 U-Boot 两个阶段都能被正确识别。
七、补丁的实际挂载板卡与构建应用
目标板卡:Radxa Rock 4D
受惠最直接的是 config/boards/radxa-rock-4d.conf,其 SPI 启动配置明确使用rock-4d-spi-rk3576_defconfig、BOOT_SCENARIO="spl-blobs"、BOOT_SUPPORT_SPI="yes",并依赖厂商 ATF 与 DDR blob 组装启动镜像。由于rk35xx家族共享BOOTPATCHDIR,所有基于 Radxanext-dev-v2024.10分支的 rk35xx/rk3588 板卡(含 seeed 系列)在构建时都会应用这套补丁。
构建流程中的挂载点
在 Armbian 构建框架中,U-Boot 补丁应用发生在 lib/functions/compilation/uboot.sh 组织的编译阶段:克隆BOOTSOURCE指定的 Radxa 仓库、检出BOOTBRANCH分支后,由uboot_main_patching_python()(见 uboot-patching.sh)将BOOTPATCHDIR展开为目录列表,交给 patching.py 逐一应用,最终产物(含 U-Boot 镜像与 SPL)供后续镜像写入使用。该流程还支持USERPATCHES_PATH用户补丁叠加,便于在官方补丁之上做本地定制。
八、总结
这套 v2024.10 补丁集体现了"对齐 mainline、消除下游副作用"的清晰思路:
| 补丁文件 | 解决的问题 | 核心手段 |
|---|---|---|
| fix-part-efi-gpt-crash-on-unformatted-storage.patch | 未格式化介质上 GPT 校验/修复导致堆破坏、启动中止 | PTE 几何预检、gpt_entry_modify空项防护、删除part_test_efi内的 RKIMG 校验/修复 |
| fix-scsi-ufs-dma-aligned-tempbuff.patch | UFS 查询数据偏移 2 字节、厂商名/块大小乱码 | 用DEFINE_CACHE_ALIGN_BUFFER对齐 PRDT DMA 目标 |
| fix-scsi-ufs-native-4096-geometry.patch | 4096 原生设备被强行 512e 重映射导致 GPT 校验失败 | 保留原生几何、CDB 不编 LUN、容量含入 |
| fix-ufs-dma-cache-coherency-like-mainline.patch | 多块 UFS 读取尾块清零 | DMA 前 flush / 后 invalidate,修正缓存区间数学 |
| rock-4d-spi-efi-partition-entries-128.patch | SPI 场景 GPT 分区项上限 64 与 Armbian 128 项不符 | defconfig 提升至 128 |
对想深入验证的读者,建议在本地 Armbian 构建环境中运行./compile.sh BOARD=radxa-rock-4d BRANCH=vendor,观察日志中Using U-Boot patch dir:输出的目录列表,即可确认这套补丁集被实际纳入;随后可在 U-Boot 命令行执行part list与scsi info验证 GPT 与 UFS 几何输出是否符合预期。
- 嵌入式
- 构建工具
- 操作系统
【免费下载链接】build
The official build framework for the Armbian Linux distribution. This repository contains the complete toolchain and scripts required to compile custom OS images from source, including kernel configuration, U-Boot handling, and board-specific tweaks for various ARM and ARM64 single-board computers.
相关推荐
Zephyr 在 Radxa ROCK 3B(Rockchip RK3568)上的移植、构建与 U-Boot 运行指南
Zephyr 在 Radxa ROCK 3B(Rockchip RK3568)上的移植、构建与 U Boot 运行指南 Radxa ROCK 3B 是一款基于
操作系统嵌入式RTOS物联网Vinext 1.0.0-beta.6 补丁全解析:App Router、缓存与构建系统的 20 项修复
Vinext 1.0.0 beta.6 补丁全解析:App Router、缓存与构建系统的 20 项修复 本指南基于 vinext 仓库中的 v1.0.0 be
后端Web框架SSRamlogic-s9xxx-armbian启动故障修复:u-boot配置与引导修复教程
amlogic s9xxx armbian启动故障修复:u boot配置与引导修复教程 引言:启动故障的痛点与解决方案 你是否曾遇到Amlogic盒子刷入Arm
嵌入式开发工具构建工具操作系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考