Skip to content

feat(ostool): 支持 ELF/BIN FIT 生成 - #196

Open
MRNIU wants to merge 10 commits into
drivercraft:mainfrom
MRNIU:feat/elf-bin-fit
Open

MRNIU wants to merge 10 commits into
drivercraft:mainfrom
MRNIU:feat/elf-bin-fit

Conversation

@MRNIU

@MRNIU MRNIU commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

支持生成包含 ELF 或 BIN 的 FIT 镜像;选择 BIN 时自动转换,无需手工处理。

  • 可选择 Linux 或 ELF OS,指定设备树和输出路径。
  • ELF OS 模式需要显式指定安全的加载地址,入口指向 ELF 文件头;目标 U-Boot 需启用 CONFIG_BOOTM_ELF。
  • BIN 地址支持自动获取或显式指定;地址映射不明确时要求显式填写,支持 LoongArch Linux 镜像头入口换算。
  • 现有 U-Boot 默认生成行为保持兼容。

本 PR 提供内部生成能力,暂未新增命令或用户配置入口;入口由 PR 3 接入。

依赖 #193,仅包含其上的 FIT 增量。

MRNIU and others added 7 commits September 22, 2026 15:23
新增默认关闭的 artifacts.analysis 配置,复用 Rust 工具链 LLVM 和现有
artifact registry 生成反汇编、ELF 信息与符号列表。通过 object 解析架构、
入口、PT_LOAD 与可选 __executable_start,显式请求失败时返回具体错误。

分离原始 ELF 和运行时副本,避免 .elf 输入原地覆盖;添加 BIN 时保留
符号来源与调试产物登记,新构建则清理旧登记。完整 BuildConfig 接入
构建与运行入口,保留 Cargo 选择、hooks 和 Custom runner 配置读取顺序。
同步中英文 README 与公开 API 编译用例。

验证:devbox 原生格式化、workspace clippy/build/test 全部通过;
ostool all-targets/all-features clippy -D warnings 通过。新增实际 LLVM
产物、ELF metadata、状态更新和 CLI hook 回归测试。
x86_64 CI 命令已尝试,本地因缺少交叉 sysroot/libudev 与 C 编译器阻塞。

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Niu Zhihong <zhihong@nzhnb.com>
复用 tempfile 管理分析产物的临时文件和替换,移除手工暂存路径及重复的
runtime 来源状态。将完整配置运行入口收窄为 cargo_run_with_config,
Custom CLI 继续在构建完成后读取 runner 配置,并同步中英文说明。

删除重复成功/路径/默认配置断言和 ELF32 大端专项夹具,合并状态更新与
runner hooks 测试;保留 ELF 元数据、错误处理、strip 来源和构建兼容覆盖。

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Niu Zhihong <zhihong@nzhnb.com>
删除 metadata 层重复的非法 ELF 验证,保留分析入口的失败回归。
将 Custom build-only 状态断言并入重建测试,删除配置通用序列化
往返及可由其他检查推出的断言。简化无符号 ELF 与 PT_NOTE 夹具,
保留多段地址区分、符号定义状态和原始 ELF 来源验证。

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Niu Zhihong <zhihong@nzhnb.com>
移除独立构建与 CLI 分析验收文件、手工 ELF 测试夹具和假工具测试。
完整场景保留为本地验收,仓库仅新增短配置解析测试,并在已有
runtime/build 用例中验证源 ELF 不被覆写及旧分析登记失效。

移除只用于测试注入的 resolver 包装,直接调用既有 LLVM 定位函数。
产物生成、metadata 解析及错误处理行为保持一致。

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Niu Zhihong <zhihong@nzhnb.com>
新增 crate 内部 FIT format、OS、load/entry、FDT 与输出配置,继续复用
fitimage builder 与既有 runtime BIN 转换。原始 ELF 提供符号和入口,
runtime ELF 提供实际 payload;拒绝来源布局不一致和无效加载数据。

显式地址优先,auto load 优先采用 __executable_start;缺失符号时,
ELF 要求 PT_LOAD 的物理地址减文件偏移具有共同基址,BIN 按实际
file-backed allocated section 的 LMA 推导。合法零地址保留,歧义和
溢出明确报错。小幅补充既有 ELF metadata 的 section 信息,不新增解析器。

默认 U-Boot Linux FIT、LoongArch header 及 unsupported architecture
行为保持兼容。新配置输出原子替换以保护输入硬链接,空 BIN 明确失败。
用户入口留待后续接入,不增加 CLI、公开 Rust API 或配置文件字段。

新增真实 FIT 属性和提取字节检查、地址/来源/错误路径及配置往返测试。
devbox 原生 fmt、workspace clippy/build/test(630 项)以及 ostool
all-targets/all-features Clippy -D warnings 通过,FIT 聚焦 26 项通过。
x86_64 CI 三条命令已尝试,受容器交叉 C 编译器和 libudev sysroot 缺失阻塞。

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Niu Zhihong <zhihong@nzhnb.com>
保留 ELF/BIN 自动加载地址区别和配置往返两项短测试,
移除独立 FIT 集成测试文件、手写 ELF 和外部工具夹具。
生成逻辑保持不变,完整场景保留为本地验收。

devbox 格式检查、cargo test -p ostool 和严格 Clippy 通过。

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Niu Zhihong <zhihong@nzhnb.com>
合入 upstream/main,保留 FIT 所需的 ELF section 元数据及现有解析行为。

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Niu Zhihong <zhihong@nzhnb.com>

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查结论

本 PR 新增 crate-private FitConfig 与 ELF 元数据解析,支持生成 ELF/BIN FIT、自动或显式设置 load/entry、可选 FDT 和输出路径;旧的 Linux U-Boot FIT 生成路径仍保留,且 PR 明确暂不新增 CLI 或用户配置入口。变更主要影响后续 boot-prepare 调用方,不改变当前默认 U-Boot 流程。

验证与上下文

  • GitHub check check (stable, x86_64-unknown-linux-gnu) 在目标 head f2bcdaaa73422520483acd8ba3b8fc1f80f91a41 上成功。
  • git diff --check origin/main...HEAD 通过,HEAD 与审查目标一致。
  • 本地 cargo fmt --check、cargo clippy --manifest-path ostool/Cargo.toml --all-features -- -D warnings 和 cargo test --manifest-path ostool/Cargo.toml --all-features 均因审查环境没有 cargo(退出码 127)未能运行;这不是 PR 代码导致的失败。
  • 当前 PR 没有既有 review、review comment 或 issue comment 需要处理。相近的 PR #193 是本 PR 声明的依赖,相关的 FIT/boot 边界重构 PR #123 仅作为实现模式参考。

需要修复的问题

  1. 配置化 BIN 路径没有复用 LoongArch Linux 镜像头部的入口地址换算,见行内评论。对于带 MZ 头的原始 LoongArch Linux BIN,FIT entry 必须按镜像头部相对偏移计算。
  2. BIN 自动 entry 直接使用 ELF e_entry,但 BIN load base 按 PT_LOAD.p_paddr/section LMA 推导;VMA 与 LMA 不同的合法 ELF 会被加载到一个地址却跳到另一个地址,见行内评论。

这两项都会导致生成的 FIT 在目标设备上无法正确启动。当前新增测试覆盖了地址解析的简单合成数据和旧生成路径,但没有覆盖 configured BIN/LoongArch 或 VMA/LMA 不同的 ELF;实际 U-Boot/硬件启动也未在本次环境验证。

Powered by gpt-5.6-luna

Comment thread ostool/src/boot/fit.rs Outdated
output_path: Some(temporary.path().to_path_buf()),
},
kernel_data,
entry,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里把配置解析出的 entry 直接传给 write_fit_image,绕过了旧路径 generate_fit_image 中针对 LoongArch Linux 镜像头部调用的 resolve_kernel_entry_addr。对带 MZ 头的原始 LoongArch Linux BIN,FIT entry 应为 kernel_load_addr + (image_entry - image_load);自动配置当前会保留 ELF entry,可能导致设备跳到错误地址。请对自动 BIN/Linux entry 复用该换算,同时保留显式 entry。

Comment thread ostool/src/boot/fit_config.rs Outdated
};
let entry = match self.entry {
FitAddress::Explicit(address) => address,
FitAddress::Auto => metadata.entry,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当 format=Bin 且 entry=Auto 时,这里直接返回 ELF 的 e_entry(虚拟地址);但同一配置的 BIN load base 是按 section LMA/PT_LOAD.p_paddr 推导的。对于 VMA 与 LMA 不同的合法 ELF,FIT 会把 BIN 加载到物理地址却跳到虚拟地址。请通过匹配的 PT_LOAD 将 entry 映射到 raw BIN 的 LMA 偏移,并补充 VMA/LMA 不同的测试。

@ZR233 ZR233 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当前 PR 只增加 crate 内部的 FIT 配置和生成入口;.build.toml、.uboot.toml 以及既有 U-Boot runner 的配置解析与调用点均未改动,旧配置仍走原来的 Linux FIT 生成路径。CI 通过证明了现有检查通过,但新增的 generate_configured_fit 尚未被用户入口调用,不能据此认定 ELF/BIN 新路径已经可启动。

请先修复下面两处地址语义问题,并增加从真实 ELF 生成 FIT、检查 FIT 属性与 payload 的回归验证。当前已有审查指出 LoongArch 及 BIN entry 的问题;这里的两处是额外发现。

后续接入用户配置时,建议在父配置使用可选字段,以“未填写继续走旧 generate_fit_image、显式填写才使用新生成路径”为语义。不要仅凭 FitConfig 的字段默认值切换旧流程:Auto 地址和空 FDT 可能覆盖旧的 kernel_load_addr、dtb_file。若字段放入 .uboot.toml,还需同步 UbootConfigWire 的反序列化;若板卡流程也要使用,需同步 .board.toml 到 UbootConfig 的映射。

Comment thread ostool/src/boot/fit_config.rs Outdated
};
let entry = match self.entry {
FitAddress::Explicit(address) => address,
FitAddress::Auto => metadata.entry,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] 对 os = "elf"、format = "elf",这里的 metadata.entry 是 ELF 可执行入口,但 U-Boot 的 bootm ELF 分支会将 FIT entry 作为 bootelf() 的输入地址,而 bootelf() 需要的是内存中 ELF 文件头地址。FIT payload 加载在 load,两者通常不同,因此镜像生成成功后仍无法由该分支启动。请按 ELF 文件头所在地址设置或校验 FIT entry,并用实际 ELF/FIT 验证。os = "elf" 还依赖目标 U-Boot 启用 CONFIG_BOOTM_ELF;当前允许它与默认 format = "bin" 组合,也应拒绝或定义可启动的语义。参见 https://github.com/u-boot/u-boot/blob/master/boot/bootm_os.c#L372-L393 和 https://github.com/u-boot/u-boot/blob/master/cmd/elf.c#L24-L32。

Comment thread ostool/src/boot/fit_config.rs Outdated
FitAddress::Explicit(address) => address,
FitAddress::Auto => match metadata.executable_start {
// The linker-provided origin describes the selected project's image base.
Some(address) => address,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] __executable_start 是 ELF 符号的虚拟地址;由 llvm-objcopy -O binary 生成的 BIN 则按实际可加载 section 的物理加载地址排列。若 ELF 的 VMA 与 LMA 不同,这里会绕过下面的 bin_load_base(),把虚拟地址写进 FIT load,导致 BIN 装载到错误地址。请对 BIN 优先按 section 的 LMA 推导;只有证实符号与该地址一致时才采用符号,无法确定时要求显式 load。建议用 VMA ≠ LMA 的 ELF 回归这一分支。

保留配置化 FIT 生成入口,以及 main 的 ramdisk、Rockchip 兼容和设备树旧 initrd 清理逻辑。适配共享 FIT builder 与现有测试调用,不改变地址解析规则。

验证:ARM64 devbox 格式检查、ostool Clippy、构建及库、CLI、集成和文档测试通过。严格 all-targets Clippy 受 main 已有 axloader 测试模块位置问题阻断;未运行 x86_64 CI matrix。

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Niu Zhihong <zhihong@nzhnb.com>

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查结论

REQUEST_CHANGES。本 PR 在 base 之上新增 crate-private FitConfig(ostool/src/boot/fit_config.rs)、给 ElfMetadata 增加 load_sections、新增 generate_configured_fit,并把 FIT 写文件拆成 write_fit_image,使后续入口能按 ELF 元数据推导 load/entry 并生成 ELF 或 BIN payload 的 FIT;旧的 generate_fit_image(U-Boot Linux 路径)行为未变。

影响面

  • 旧路径未变:generate_fit_image 仍是 os = "linux",仍对 LoongArch 调 resolve_kernel_entry_addr,ostool/src/run/uboot.rs:1327 的调用点未改。
  • 新增的 generate_configured_fit 与 fit_config 模块本 PR 内仍是 #[allow(dead_code)],没有调用方,所以本 PR 不改变任何现有用户可见行为;真正受影响的是“FIT load/entry/os 如何被 U-Boot 解释”这一契约语义,即下面三个行内问题。

验证

  • CI:head f33dbd5386f42759e79aff110ebb541bf9250be3 的 check (stable, x86_64-unknown-linux-gnu) 为 success(2026-10-09 完成),因此 fmt/clippy/build/test 在该 head 上是通过的。
  • 本地:git diff --check origin/main...HEAD 通过,HEAD 与审查目标一致。本审查环境没有 cargo(which cargo 未找到,退出码 127),未能本地复跑 cargo fmt --check、clippy、cargo test;这不是本 PR 导致的失败,但也意味着新增地址推导只由 CI 中的合成单测覆盖。未做任何硬件/U-Boot 实机启动验证。

需要修复(阻塞)

  1. F-001:os = "elf" 的 FIT entry 语义不成立(fit_config.rs:24,行内)。
  2. F-002:BIN 的 load 优先采用 __executable_start(VMA)(fit_config.rs:83,行内)。
  3. F-003:BIN 的 entry 直接采用 e_entry,与 LMA 推导的 load 不在同一地址空间(fit_config.rs:92,行内)。

上一轮 review 的处理情况

两条既有 review 均为 CHANGES_REQUESTED(提交于 f2bcdaa),其行内评论经 GitHub 迁移后仍锚定当前 head,当前 head 既未修复也未回复(f2bcdaa、f33dbd5 两个提交都只是与 main 的合并冲突同步):

  • mai-team-app[bot]:LoongArch 入口换算被绕过(fit.rs:164);BIN Auto entry 用 e_entry(fit_config.rs:92)。第二条技术成立,保留为 F-003;第一条按 F-004 记为 advisory,需要作者确认派生 BIN 是否仍带历史 MZ 头。
  • ZR233:[P1] bootelf 需要 ELF 头地址而不是 e_entry,以及 os = "elf" 与 format = "bin" 组合问题;[P2] __executable_start 是 VMA 却用于 BIN load。两条我都按 U-Boot 源码复核后确认成立(do_bootm_elf() → bootelf(bmi->images->ep, ...),images->ep 来自 FIT entry;boot/image.c 的 uimage_os[] 中 {IH_OS_ELF, "elf"} 被 #ifdef CONFIG_CMD_ELF 包裹),分别保留为 F-001 与 F-002。唯一需要修正的是“os = "elf" 不被 U-Boot 支持”的部分:IH_OS_ELF/"elf" 确实存在,但依赖目标 U-Boot 开启 CONFIG_CMD_ELF,并且必须给出正确的 entry。
  • ZR233 的 review body 还要求补真实 ELF 的回归验证,当前仍未提供(见下)。

遗留风险与测试缺口

  • F-004(advisory):配置化路径没有复用 resolve_kernel_entry_addr,两条路径对“以 MZ 开头的二进制 payload”的 entry 语义可能不一致;请确认派生 BIN 是否仍带该头部,否则应复用同一换算或说明原因。
  • F-005(advisory):新增路径没有调用方也没有端到端测试;fit_config.rs 的合成夹具恰好把 executable_start 设为 None、把 entry 设为按 LMA 推导出的值,正好绕开了 F-002/F-003 的分支。建议在接线 PR 前补“真实 ELF → 生成 FIT → 断言 kernel 的 os/load/entry 与 payload”的测试,并明确 format/os 的合法组合矩阵。
  • 复核后未发现问题的地方:NamedTempFile + persist 的输出替换、输出与输入同路径/符号链接的保护、validate_elf_load_data 的溢出与截断检查、section_lma() 与 objcopy/BFD 的 LMA 规则一致性、toml/json 往返测试(CI 覆盖)、以及旧路径的兼容性。

相近工作

本 PR 声明依赖 #193;相关既有改动为 FIT 边界重构 #122/#123(其中已说明 os = "elf" 应作为独立功能处理)与 FIT 修复 #194/#201/#207。未发现与本 PR 重复的开放 PR。

Powered by deepseek-flash

pub(crate) enum FitOs {
#[default]
Linux,
Elf,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FitOs::Elf 目前只是把 os = "elf" 写进 FIT,但 entry 语义不匹配:U-Boot 的 IH_OS_ELF 分支(2024 年合入的 bootm ELF 支持)执行 bootelf(bmi->images->ep, ...),images->ep 取自 FIT 的 entry 属性,而 bootelf() 需要的是“内存中 ELF 文件头所在地址”(也就是 FIT load 的落点;entry 省略时 bootm 才会用 load)。FitAddress::Auto 现在返回 ELF 的 e_entry,所以 os = "elf" + format = "elf" 生成的镜像会拿入口代码当 ELF 头解析而失败。

另外 os = "elf" 仍可与默认的 format = "bin" 组合,此时 payload 是裸 BIN,bootelf() 必然失败;"elf" 这个 os 字符串也只在目标 U-Boot 编译了 CONFIG_CMD_ELF 时才在 uimage_os[] 中注册,否则 FIT 校验阶段就会报未知 OS。

建议:os = Elf 时让 entry 等于 ELF 在内存中的落点(与 load 一致),或干脆不写 entry 属性让 bootm 使用 load 地址;拒绝 os = Elf 与 format = Bin 的组合;对 CONFIG_CMD_ELF 依赖做校验或文档说明;补一条真实 ELF 生成 FIT 并断言属性/payload 的测试。

Comment thread ostool/src/boot/fit_config.rs Outdated
FitAddress::Explicit(address) => address,
FitAddress::Auto => match metadata.executable_start {
// The linker-provided origin describes the selected project's image base.
Some(address) => address,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

format = Bin 时这条分支会绕过下面的 bin_load_base():__executable_start 是链接器符号的虚拟地址(VMA),而 objcopy -O binary 生成的裸 BIN 是按各可加载 section 的 LMA 依次排列的。对 VMA ≠ LMA 的合法 ELF(例如内核 VMA 在 0xffff…、LMA 在物理区间),这里会把 FIT load 写成虚拟地址,BIN 被装载到错误位置;而 bin_load_base() 的推导(p_paddr + file_delta)与 BFD/objcopy 的 lma = vaddr + (p_paddr - p_vaddr) 一致,本来是正确的。

建议 BIN 分支不要直接采用该符号:要么一律使用 bin_load_base(),要么仅在符号值与 LMA 推导结果一致时采用,否则报错要求显式 load。现有夹具 auto_load_distinguishes_elf_container_and_bin_payload 把 executable_start 设为 None,正好跳过了这条分支,建议补一个 VMA ≠ LMA 且符号存在的用例。

Comment thread ostool/src/boot/fit_config.rs Outdated
};
let entry = match self.entry {
FitAddress::Explicit(address) => address,
FitAddress::Auto => metadata.entry,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

entry = Auto 直接返回 ELF 的 e_entry(VMA),但同一配置在 format = Bin 下的 load 是按 PT_LOAD p_paddr/section LMA 推导的物理地址。U-Boot 用 FIT load 落盘 payload、再用 entry 跳转(images->ep 来自 entry 属性),两者不在同一地址空间时就会出现“加载到物理地址、跳到虚拟地址”,镜像生成成功但无法启动。

建议 Bin 下把 e_entry 通过匹配的 PT_LOAD 映射到与 load 相同的地址空间(例如 load + (e_entry - lowest_lma)),无法唯一映射时明确报错要求显式 entry,并补 VMA ≠ LMA 的回归测试(当前夹具的 entry 恰好等于按 LMA 推导出的值,因此测不出该问题)。

ELF OS 仅接受 ELF payload,并要求显式提供安全暂存地址;自动入口使用文件头地址,拒绝不一致的显式入口。LoongArch Linux BIN 自动入口复用已有镜像头换算。

BIN 自动地址核对实际 payload LMA;符号冲突、入口映射不明或加载位置变化时要求显式覆盖。保留合法零地址和现有默认生成流程,不增加用户配置入口。

验证:ARM64 devbox 格式、Clippy、构建及 ostool 测试通过。真实 ELF/FIT 本地验收检查 payload 完整字节、OS、架构和地址。未运行 x86_64 CI matrix 或硬件启动。

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Niu Zhihong <zhihong@nzhnb.com>

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查结论

REQUEST_CHANGES。本 head 修掉了上一轮的三个阻塞项中的两个半,地址语义整体比 f33dbd5 明显更严谨;但 FitFormat::Elf 的自动 load 仍沿用“优先取 VMA 符号”的旧写法,与本次刚在 BIN 分支建立的规则自相矛盾,会在 VMA≠LMA 或首个 PT_LOAD 偏移非零时生成放错位置的 ELF payload,属于同一类会“生成成功但启动不了”的问题,建议一并收敛。

本 PR 做了什么、影响面

  • 新增 crate-private FitConfig/FitAddress/FitFormat/FitOs(ostool/src/boot/fit_config.rs)与 ElfMetadata.load_sections,新增内部入口 generate_configured_fit,并把写 FIT 的部分拆成 write_fit_image;write_fit_image 接受 os,因此旧路径 generate_fit_image 依然固定写 os = "linux"。
  • 影响面:generate_configured_fit 与 fit_config 模块在本 PR 内仍是 #[allow(dead_code)](ostool/src/boot/mod.rs),用户入口、.uboot.toml/.board.toml 解析和 ostool/src/run/uboot.rs:1327 的调用点都未改,所以本 PR 不改变现有用户可见行为;真正被固定下来的是“FIT 的 load/entry 如何按 ELF 元数据推导”这一契约,供 PR 3 接入时依赖。旧路径行为等价(仅 build_default_fit_config → build_fit_config 加参、测试同步更新)。

上一轮 review 的处理情况

  • mai-team-app[bot](F-001):os = "elf" 的 entry 语义 → 已修。resolve_entry 现在对 FitOs::Elf 返回 load,并拒绝与 load 不一致的显式 entry;同时 resolve_load 拒绝 os = elf + format = bin。与 U-Boot do_bootm_elf() → bootelf() 需要“内存中 ELF 头地址”的语义一致。
  • mai-team-app[bot](F-002):BIN load 优先用 __executable_start(VMA) → 已修。现在先用 bin_load_base()(按 section LMA 推导),符号只在与该基址一致时被接受,冲突则报错要求显式 load。
  • mai-team-app[bot](F-003):BIN entry 直接用 e_entry(VMA) → 已修。bin_entry() 现在要求 load == bin_load_base(),且 entry 必须落在某个 LMA==VMA 的 file-backed section 内,否则要求显式 entry。
  • mai-team-app[bot](F-004,advisory):LoongArch 入口换算被绕过 → 已修。generate_configured_fit 对 LoongArch64 + BIN + os = linux + payload 带 MZ 头且 entry = auto 时复用 resolve_kernel_entry_addr,与旧路径同一公式。
  • ZR233 的两条(bootelf 需要 ELF 头地址、__executable_start 是 VMA)都已按上面两点修复;其 review body 里“补真实 ELF 生成 FIT 的回归验证”仍未落地(见下 F-103)。

验证

  • CI:head 8076e5d40c1e32c148c5c2b6d4daad73896f683d 的 check (stable, x86_64-unknown-linux-gnu) 为 success(2026-10-09T07:06:45Z 完成,check run 113708984995),因此该 head 的 cargo fmt/clippy/build/test 在 CI 环境是通过的;未发现与本 PR 相关的失败 CI。
  • 本地:git rev-parse HEAD = 8076e5d…、git rev-parse origin/main = 787943d…,工作区干净,与审查目标一致;git diff --check origin/main...HEAD 通过。本审查环境没有 cargo(/bin/sh: 1: cargo: not found,退出码 127),cargo fmt --check、cargo clippy --manifest-path ostool/Cargo.toml --all-features -- -D warnings、cargo test --manifest-path ostool/Cargo.toml --all-features 均未能运行,这不是本 PR 导致的失败。未做任何 U-Boot/硬件启动验证,以下地址语义判断基于 U-Boot bootm(FIT load 为 payload 落点、entry 为跳转地址)与 objcopy -O binary 的 LMA 布局规则。

需要修复(阻塞)

  1. F-101(ostool/src/boot/fit_config.rs:101-104,行内):FitFormat::Elf + FitAddress::Auto 仍优先采用 VMA 符号 __executable_start,只在符号缺失时退回 elf_load_base()(= p_paddr - p_offset)。ELF payload 的 load 必须是“文件首字节地址”,而符号是 VMA;与本次 BIN 分支刚建立的规则不一致。详见行内评论。

遗留风险与建议(均非阻塞)

  • F-102(advisory):LoongArch 的 entry 换算在 ostool/src/boot/fit.rs:145-153 由调用方完成,FitConfig::resolve_entry() 的返回值会被按 payload 字节静默覆盖,“Auto entry”的解析不再有唯一入口;建议收敛到一个函数,避免后续接入时两处不一致。
  • F-103(advisory):仍无“真实 ELF → 生成 FIT → 断言 os/load/entry/payload”的端到端回归;现有夹具把 executable_start 设为 None(ostool/src/boot/fit_config.rs:291),恰好跳过 F-101 所在分支。
  • F-104(advisory):write_fit_image 从参数取 kernel_entry_addr、却从 input.kernel_load_addr 取 load,并忽略 input.kernel_entry_addr;建议统一来源或加断言。
  • F-105(advisory):新写出路径用 NamedTempFile + persist,会把 image.fit 权限固定为 0600(旧 fs::write 路径遵循 umask);请确认下游(TFTP/ostool-server/其它用户)是否需要可读权限。
  • 复核后未发现问题的地方:os = elf/format = bin 组合拒绝、validate_elf_load_data 的截断与溢出检查、输出与输入同路径/符号链接的保护(含 rename 不破坏硬链接的说明)、bin_load_base/section_lma 与 objcopy LMA 规则的一致性、toml/json 往返测试、以及旧 U-Boot Linux 路径的兼容性。

相近工作

本 PR 声明依赖 #193;相关既有工作为 FIT 边界重构 #122/#123、FIT 修复 #194/#201/#207。未发现与本 PR 重复的开放 PR。

Powered by gpt-5.6-luna

Powered by deepseek-flash

Comment thread ostool/src/boot/fit_config.rs Outdated
}
Ok(base)
}
FitAddress::Auto => match metadata.executable_start {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

F-101(阻塞):format = Elf 的自动 load 仍优先取 VMA 符号,和刚在 BIN 分支建立的规则相矛盾。

同一函数上方 89-100 行已经确认了原则:payload 的 load 必须按实际落盘布局推导,__executable_start 只在与该基址一致时才接受,否则报错要求显式 load。但这个分支反过来:先信符号(Some(address) => Ok(address)),只有符号缺失时才用 elf_load_base()。

为什么这里会出错:FIT 的 load 是 U-Boot 放置 payload 字节的地址;对 format = Elf 而言 payload 是整个 ELF 文件,所以 load 必须是“文件第 0 字节的地址”,也就是 elf_container_base() 计算的 p_paddr - p_offset。__executable_start 是符号地址(VMA),只在“最低 PT_LOAD 的 p_offset == 0 且 p_paddr == p_vaddr”时才恰好等于该基址。一旦:

  • 第一个 file-backed PT_LOAD 的 p_offset != 0(头/只读段与首个可执行段分离的布局),文件被放到 p_offset 偏移错误的位置,section 落在 LMA + p_offset 而不是 LMA;
  • p_paddr != p_vaddr(内核常见的高半区 VMA + 物理 LMA),load 会被写成不可加载的 VMA,而同一路径的 entry 仍是 metadata.entry(同文件 110-124 行 FitAddress::Auto => Ok(metadata.entry)),于是“装载位置与跳转地址不在同一地址空间”。

这正是本 head 的 8076e5d 在 BIN 分支上承认并修掉的问题类型(提交信息:符号冲突、加载位置变化时要求显式覆盖),ELF 分支漏了;而 format = Elf 是本 PR 标题里的主要能力之一(os 默认为 Linux,FitAddress::Auto 默认启用),所以这条分支会被默认走到。现有单测夹具把 executable_start 设为 None(本文件 291 行),因此该分支没有被覆盖。

建议按与 BIN 相同的规则处理:

FitAddress::Auto => {
    let base = elf_load_base(metadata)?;
    if metadata
        .executable_start
        .is_some_and(|address| address != base)
    {
        bail!("cannot derive ELF FIT load address: __executable_start differs from the ELF container base; set load explicitly");
    }
    Ok(base)
}

(若希望 format = Elf 与 os = Elf 一样“暂存地址必须显式”,直接 bail! 也可以;但不要让 VMA 符号在无声的情况下决定 load。)并补一个 p_paddr != p_vaddr 且 executable_start 存在的用例,覆盖这条分支。

ELF/Linux 自动加载地址校验完整文件的装载基址;符号地址冲突、入口映射不明或加载位置变化时要求显式覆盖,避免生成不可可靠启动的 FIT。

FIT 输出保留已有文件权限,新文件遵循 umask。最终入口统一由 FitInput 传递,保持默认 Linux 与 LoongArch 镜像头处理兼容。

验证:ARM64 devbox 格式、Clippy、构建及 ostool 测试通过。真实 ELF/BIN FIT 内容、地址、LoongArch 入口、文件权限与原子替换的本地验收通过。未运行 x86_64 CI matrix 或硬件启动。

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Niu Zhihong <zhihong@nzhnb.com>

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查结论

COMMENT(未发现阻塞问题):在 head e7b566e 上未发现阻塞性缺陷——没有 fmt/clippy/test 失败,也没有安全、数据丢失、panic、竞态或行为回退类问题。上一轮唯一的阻塞项(format = "elf" 的 Auto load 仍优先采用 VMA 符号 __executable_start,见 c926f0c0 的 F-101)已在本 head 修复,且比建议更完整:符号只在与 ELF 容器基址一致时才被接受,同时 FitAddress::Auto 的 entry 统一改走 direct_entry(),会校验“entry 落在 LMA==VMA 的 file-backed section 内”。下面 4 条均为 advisory,可作为合并前或接线 PR 中的跟进项。

本 PR 做了什么

  • 新增 ostool/src/boot/fit_config.rs:crate-private FitConfig/FitFormat/FitOs/FitAddress/FitFdt,以及地址推导 resolve_load()/resolve_entry() 与 bin_load_base()/elf_load_base()/section_lma()。
  • ostool/src/artifact/elf_metadata.rs:新增 LoadSection 与 load_sections(SHF_ALLOC、非 SHT_NOBITS、file_range() 存在且 size≠0)。
  • ostool/src/boot/fit.rs:新增内部入口 generate_configured_fit() 与 validate_elf_load_data();写文件部分抽成 write_fit_image(..., os);旧 generate_fit_image() 仍固定 os = "linux"、仍对 LoongArch 镜像头调用 resolve_kernel_entry_addr(),最终 entry 统一经 FitInput.kernel_entry_addr 传递。
  • ostool/src/boot/mod.rs:注册 fit_config 模块并标注 #[allow(dead_code)](用户入口由后续 PR 接入)。

影响面

  • 旧路径等价:build_default_fit_config → build_fit_config(..., FitOs::Linux) 只是加参数;ostool/src/run/uboot.rs:1327 的调用点、.uboot.toml/.board.toml 解析与用户可见行为均未改。
  • 本 PR 内 generate_configured_fit 与 fit_config 没有调用方,改动完全内部化;真正被固定下来的是“FIT load/entry 如何由 ELF 元数据推导”这一契约,供下一个接线 PR 依赖。
  • 复核后未发现问题的部分:os = "elf" 必须 format = "elf" 且 entry 必须等于 load(与 U-Boot do_bootm_elf() → bootelf() 需要内存中 ELF 头地址一致);os = "elf" 的 Auto load 明确拒绝并要求显式 staging 地址;BIN/ELF 两种 payload 的 load 都以实际落盘布局为准,符号地址冲突时要求显式指定;validate_elf_load_data() 的文件范围/溢出检查;输出用 NamedTempFile + persist 原子替换,hard link 输入不会被截断(相对旧 fs::write 是改进),输入别名检查覆盖 source/runtime ELF 与 FDT;Builder::permissions(0o666) 在 unix 上受 umask 收窄(tempfile 文档:permissions & !umask),新建输出与 fs::write 语义一致、已有输出保留原权限;生产路径无 unwrap()/expect()/unsafe;BIN 派生使用独立 tempdir(),成功/失败路径都会清理。

验证

  • CI:head e7b566e 的 check (stable, x86_64-unknown-linux-gnu) 为 success(check run 113718682003,2026-10-09T07:37:57Z 完成),该工作流包含 cargo fmt --all -- --check、cargo clippy、cargo build、cargo test。未发现与本 PR 相关的失败 CI。
  • 本地:git rev-parse HEAD = e7b566e…、git rev-parse origin/main = 787943d…,工作区干净,git diff --check origin/main...HEAD 通过。本审查环境没有 cargo(which cargo 未找到,退出码 127),cargo fmt --check / cargo clippy --all-features -- -D warnings / cargo test --all-features 未能本地复跑;这不是本 PR 导致的失败。
  • 未做 U-Boot/硬件实机启动验证。

上一轮 review 的处理情况

  • 3f79b038(F-001/F-002/F-003)与 ZR233 的 [P1]/[P2]:均已修复——os = "elf" 的 entry 语义、BIN load 按 section LMA 推导、BIN entry 与 load 落在同一地址空间。
  • c926f0c0(F-101,阻塞):已修复(elf_load_base() 优先,符号不一致则报错要求显式 load)。
  • c926f0c0 的 F-104(write_fit_image 的 entry 参数与 input.kernel_entry_addr 来源不一致)与 F-105(NamedTempFile 把输出固定为 0600):本 head 一并修掉。
  • ZR233 的 review body 仍要求“真实 ELF → 生成 FIT → 断言属性/payload”的回归验证,本 head 未提供(见 F-201;提交信息已记录人工验收,按 /project/repo/AGENTS.md“通过测试或记录过的手动验证覆盖”有人工依据,故不作为阻塞)。

遗留风险与测试缺口(均非阻塞,对应行内评论)

  1. F-201(无端到端回归,body-only):generate_configured_fit/fit_config 在本 PR 内无调用方,覆盖仅靠合成 ElfMetadata 夹具与 build_fit_config 单测;建议在接线 PR 前补“真实 ELF(CI 已装 llvm-objcopy/cargo-binutils)→ 生成 FIT → 断言 os/load/entry 与 payload”的用例,至少覆盖 format=bin / format=elf / os=elf 三个分支。
  2. F-202(entry 策略两处解析,fit.rs:146-155):LoongArch 镜像头换算内联在生成入口,FitConfig::resolve_entry() 在该分支不被调用,也跳过 Bin 的落点校验。
  3. F-203(ELF 容器 Auto load 偏严,fit_config.rs:101-112):elf_load_base() 要求所有 file-backed PT_LOAD 共享同一 p_paddr - p_offset,否则要求显式 load(fail-closed,但带 gap 的真实内核 ELF 基本无法用 Auto)。
  4. F-204(fit_config.rs:144-161):format = "elf" + 默认 os = "linux" 下只校验 entry 所在 section 的 LMA==VMA,其余 section 的 VMA≠LMA 不会被拒绝。

相近工作

本 PR 声明依赖 #193;相关既有改动为 FIT 边界重构 #122/#123(其结论已声明“os = "elf" 应作为独立功能处理”)、boot readiness #129、以及 FIT 修复 #194/#201/#207。未发现与本 PR 重复的开放 PR。

Powered by deepseek-flash

Comment thread ostool/src/boot/fit.rs
}
// The Linux image header takes precedence over metadata-only inference.
// These branches are exclusive: an explicit entry never reads the header.
let entry = if config.entry == FitAddress::Auto

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(F-202,advisory,非阻塞)LoongArch 镜像头(MZ)的 entry 换算内联在这里,导致 FitConfig::resolve_entry() 在这个分支完全不被调用,FitAddress::Auto 出现两个解析点:调用方必须记得这段特判,未来接线方若直接调用 resolve_entry() 会得到不同结果;该分支同时绕过了 resolve_entry() 对 Bin 的“entry 必须落在 LMA==VMA 的 file-backed section 内”校验(fit_config.rs:134-168)。建议把 payload 相关换算收敛进 FitConfig(例如 resolve_entry_with_payload(&metadata, load, &kernel_data),或让 resolve_entry 接收 payload 并在内部处理 MZ 头),使地址策略只有一个所有者。

Ok(base)
}
FitAddress::Auto => {
let base = elf_load_base(metadata)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(F-203,advisory,非阻塞)elf_load_base() 要求所有 file-backed PT_LOAD 段共享同一个 p_paddr - p_offset(fit_config.rs:170-184),任一不一致就 bail! 要求显式 load。对 format = "elf"(payload 是整份 ELF 文件、按 LMA 落盘)这是保守且正确的安全条件,但真实内核 ELF(段 LMA 与文件偏移不等距推进、带 gap 的 vmlinux)几乎都会走到该拒绝分支,使 format = "elf" + FitAddress::Auto(默认值)的可用面比 PR 描述窄。失败是 fail-closed、不会写出错误地址,因此不作为阻塞项;建议要么在文档/错误信息中明确该限制,要么放宽为“取 p_paddr - p_offset 最小值并校验其余段按 LMA 等距”,并为带 gap 的布局补一个用例。

"section virtual range",
)?
{
if section_lma(section, &metadata.load_segments)? != section.virtual_address {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(F-204,advisory,非阻塞)direct_entry() 只校验包含 e_entry 的那个 section 是否 LMA == VMA,不校验 payload 其余 file-backed section。对 format = "elf" + 默认 os = "linux",payload 是整份 ELF 文件、按 LMA 逐段落盘;若只有 entry 所在段恒等映射、别的段 VMA≠LMA,生成会成功,但段内绝对地址引用指向 VMA、字节却落在 LMA,属于“生成成功但启动不对”。os = "elf" 才是为非恒等映射内核准备的模式(bootelf() 按 program header 自行装载,并要求显式 staging 地址)。建议要么在该组合下要求所有 file-backed section 均 LMA == VMA(否则报错要求显式 load/entry),要么在注释与文档中明确 format = "elf" 的 flatten 契约并引导使用 os = "elf"。

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants