☰
Armbian 构建框架中的 Radxa rk35xx v2024.10 厂商 U-Boot 补丁集:修复 Rock 4D 的 GPT、UFS/SCSI 与 DMA 缓存问题
2026/10/2 13:33:27 网站建设 项目流程
  • 嵌入式
  • 构建工具
  • 操作系统

【免费下载链接】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.

项目地址:https://gitcode.com/GitHub_Trending/bu/build
点击查看免费下载

导读

本文深入解析 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 行为:

  1. 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 协议信息单元)承载,无需塞进命令块;
  2. READ CAPACITY 的 last LBA 按含入处理:*capacity += 1;(mainline 语义,防止容量少算一块);
  3. 512e 换算仅在真正发生重映射时启用:rawsectsz由block_dev->rawblksz / 512改为条件式(block_dev->blksz == 512 && block_dev->rawblksz == 4096) ? 8 : 1;
  4. 设备探测不再改写几何:删除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.patchUFS 查询数据偏移 2 字节、厂商名/块大小乱码用DEFINE_CACHE_ALIGN_BUFFER对齐 PRDT DMA 目标
fix-scsi-ufs-native-4096-geometry.patch4096 原生设备被强行 512e 重映射导致 GPT 校验失败保留原生几何、CDB 不编 LUN、容量含入
fix-ufs-dma-cache-coherency-like-mainline.patch多块 UFS 读取尾块清零DMA 前 flush / 后 invalidate,修正缓存区间数学
rock-4d-spi-efi-partition-entries-128.patchSPI 场景 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.

项目地址:https://gitcode.com/GitHub_Trending/bu/build
点击查看免费下载
上一篇:硬件黑客的秘密武器:kalitools安卓逆向与固件分析指南
下一篇:提升june语音识别准确率的5个实用技巧:从模型选择到环境优化

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询