Repository navigation
Conversation
新增默认关闭的 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>
There was a problem hiding this comment.
审查结论
本 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)在目标 headf2bcdaaa73422520483acd8ba3b8fc1f80f91a41上成功。 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 仅作为实现模式参考。
需要修复的问题
- 配置化 BIN 路径没有复用 LoongArch Linux 镜像头部的入口地址换算,见行内评论。对于带
MZ头的原始 LoongArch Linux BIN,FIT entry 必须按镜像头部相对偏移计算。 - 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
| output_path: Some(temporary.path().to_path_buf()), | ||
| }, | ||
| kernel_data, | ||
| entry, |
There was a problem hiding this comment.
这里把配置解析出的 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。
| }; | ||
| let entry = match self.entry { | ||
| FitAddress::Explicit(address) => address, | ||
| FitAddress::Auto => metadata.entry, |
There was a problem hiding this comment.
当 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
left a comment
There was a problem hiding this comment.
当前 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 的映射。
| }; | ||
| let entry = match self.entry { | ||
| FitAddress::Explicit(address) => address, | ||
| FitAddress::Auto => metadata.entry, |
There was a problem hiding this comment.
[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。
| FitAddress::Explicit(address) => address, | ||
| FitAddress::Auto => match metadata.executable_start { | ||
| // The linker-provided origin describes the selected project's image base. | ||
| Some(address) => address, |
There was a problem hiding this comment.
[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>
There was a problem hiding this comment.
审查结论
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 不改变任何现有用户可见行为;真正受影响的是“FITload/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 实机启动验证。
需要修复(阻塞)
- F-001:
os = "elf"的 FITentry语义不成立(fit_config.rs:24,行内)。 - F-002:BIN 的
load优先采用__executable_start(VMA)(fit_config.rs:83,行内)。 - 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来自 FITentry;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, |
There was a problem hiding this comment.
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 的测试。
| FitAddress::Explicit(address) => address, | ||
| FitAddress::Auto => match metadata.executable_start { | ||
| // The linker-provided origin describes the selected project's image base. | ||
| Some(address) => address, |
There was a problem hiding this comment.
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 且符号存在的用例。
| }; | ||
| let entry = match self.entry { | ||
| FitAddress::Explicit(address) => address, | ||
| FitAddress::Auto => metadata.entry, |
There was a problem hiding this comment.
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>
There was a problem hiding this comment.
审查结论
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-Bootdo_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-Bootbootm(FITload为 payload 落点、entry为跳转地址)与objcopy -O binary的 LMA 布局规则。
需要修复(阻塞)
- 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
| } | ||
| Ok(base) | ||
| } | ||
| FitAddress::Auto => match metadata.executable_start { |
There was a problem hiding this comment.
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>
There was a problem hiding this comment.
审查结论
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-privateFitConfig/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没有调用方,改动完全内部化;真正被固定下来的是“FITload/entry如何由 ELF 元数据推导”这一契约,供下一个接线 PR 依赖。 - 复核后未发现问题的部分:
os = "elf"必须format = "elf"且 entry 必须等于 load(与 U-Bootdo_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 语义、BINload按 section LMA 推导、BINentry与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“通过测试或记录过的手动验证覆盖”有人工依据,故不作为阻塞)。
遗留风险与测试缺口(均非阻塞,对应行内评论)
- 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 三个分支。 - F-202(entry 策略两处解析,
fit.rs:146-155):LoongArch 镜像头换算内联在生成入口,FitConfig::resolve_entry()在该分支不被调用,也跳过 Bin 的落点校验。 - 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)。 - 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
| } | ||
| // 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 |
There was a problem hiding this comment.
(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)?; |
There was a problem hiding this comment.
(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 { |
There was a problem hiding this comment.
(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"。
支持生成包含 ELF 或 BIN 的 FIT 镜像;选择 BIN 时自动转换,无需手工处理。
本 PR 提供内部生成能力,暂未新增命令或用户配置入口;入口由 PR 3 接入。
依赖 #193,仅包含其上的 FIT 增量。