Skip to content

feat(ebpf): add x86_64 eBPF JIT backend#1140

Closed
CN-TangLin wants to merge 6 commits into
rcore-os:devfrom
CN-TangLin:feat/ebpf-jit-2-x86-64
Closed

feat(ebpf): add x86_64 eBPF JIT backend#1140
CN-TangLin wants to merge 6 commits into
rcore-os:devfrom
CN-TangLin:feat/ebpf-jit-2-x86-64

Conversation

@CN-TangLin

@CN-TangLin CN-TangLin commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

问题

在 JIT 框架(#1142)基础上,添加 x86_64 eBPF JIT 后端,完整实现 JitBackend trait,覆盖 ALU/JMP/MEM/CALL/BPF_END 指令翻译。

变更

  • jit_x86_64.rs:900 行,x86_64 JIT 后端,覆盖 ALU64/ALU32/JMP/MEM/CALL/BPF_END
  • jit_aarch64.rs:空 stub
  • jit_riscv64.rs:完整 RISC-V 实现
  • mod.rs:JIT 框架(JitBuffer + JitBackend + JitCompiler)
  • bpf_insn.rs:指令定义
  • ebpf/mod.rs:模块接入
  • 新代码标记 #[allow(dead_code)]

Review 后修复

  • emit_divmod 中 2 处 !buf.counting() counting guards:防止 sizing pass 中空指针解引用
  • #[cfg(any(target_arch = "aarch64", target_arch = "riscv64", target_arch = "x86_64"))] 门控 + 不支持架构的 fallback,修复 loongarch64 构建失败
  • bpf_insn re-export 移除 cfg gate,避免 clippy unused import 警告

Logic

x86-64 寄存器映射:BPF R0-R5 → RAX/RDI/RSI/RDX/RCX/R8(恰好匹配 SysV ABI,无需参数重排)、R6-R9 → RBX/R13/R14/R15(callee-saved)、R10 → RBP。dst == RCX 时统一使用 R11 作为 scratch。Prologue 保存 RBX/RBP/R13-R15,分配 512 字节 BPF 栈。栈对齐正确(prologue 5×push + sub 512 + call 隐式 push = 16B 对齐)。两遍编译 sizing pass 使用计数缓冲区精确计算变长 x86-64 指令字节数,彻底消除独立 insn_size 估算误差。

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: feat(ebpf): add x86_64 eBPF JIT backend

变更概述

本 PR 在 PR#1139 建立的 JIT 框架基础上,添加 x86_64 eBPF JIT 后端实现 (jit_x86_64.rs),同时包含 JIT 框架 (ebpf_jit/mod.rs)、riscv64 后端 (jit_riscv64.rs)、aarch64 stub (jit_aarch64.rs) 和 BPF 指令定义 (bpf_insn.rs)。

实现分析

x86_64 后端使用两遍编译:第一遍通过 insn_size 估算每条指令字节数并记录偏移,第二遍实际发射机器码。代码结构清晰,寄存器映射合理,正确处理了 dst==RCX 的别名冲突。

阻塞问题

1. insn_size 系统性错误导致跳转偏移错误

insn_size 返回的估算大小与实际发射字节数存在系统性偏差。两遍编译要求 insn_size 精确匹配实际大小,否则所有跳转目标偏移都会错误,JIT 生成的代码在任何带控制流的 eBPF 程序上都会出错。

具体不匹配:

  • BPF_DIV/BPF_MOD:返回 50,实际 ~29-34 字节
  • BPF_ALU32 的 zext_size:返回 8,实际 emit_zext32 仅 2 字节
  • BPF_ALU32 寄存器移位:insn_size 返回 6,但实际包含 zext 共 8 字节(低估
  • 普通 ALU op_size:返回 3+3=6,实际寄存器 ADD 仅 3 字节
  • BPF_CALL:返回 16,实际 12 字节
  • BPF_JSET:+4 额外字节估算不准确

对比 riscv64 后端,每条 RISC-V 指令固定 4 字节,insn_size 可以精确计算。x86 的变长编码需要逐一验证每种情况。

2. BPF_MOD 除零语义错误

eBPF 规范:div by 0 → dst = 0mod by 0 → dst = dst(保持被除数不变)

emit_divmod 中,当 is_div=false 且 src==0 时,RDX 被清零(xor rdx, rdx),然后跳过 DIV 指令,最终 mov dst, rdx = 0。但应返回原始 dst(被除数)。riscv64 后端在此场景下不修改 dst,语义正确。

3. PR 未添加任何 JIT 正确性测试

PR body 声称 cargo xtask clippy --package starry-kernel 通过,但缺少实际的 JIT 正确性验证。insn_size 的错误只能通过运行带跳转的 eBPF 程序来发现。建议至少添加一个简单的单元测试验证两遍编译的偏移一致性。

CI 状态

  • Check formatting / run_host:✅ 通过
  • Run sync-lint / run_host:✅ 通过
  • Run clippy / run_container:✅ skipped(path filter)
  • Test starry aarch64 qemu / run_container:❌ 失败(Run command 步骤)— 需确认是否为已有问题
  • 其余 QEMU 测试:cancelled(因首个失败被取消)

本地验证:cargo fmt --check ✅,cargo clippy --all-features -D warnings ✅。

重复/重叠分析

PR #1139(已关闭未合并)是本 PR 的子集(JIT 框架 + riscv64)。本 PR 包含 #1139 的所有 3 个 commit。无其他 open PR 与 eBPF x86_64 JIT 重叠。

结论

insn_size 的系统性错误和 mod by 0 语义错误是阻塞性正确性问题,需要修复后重新验证。

Powered by mimo-v2.5-pro

Comment thread os/StarryOS/kernel/src/ebpf/ebpf_jit/jit_x86_64.rs
Comment thread os/StarryOS/kernel/src/ebpf/ebpf_jit/jit_x86_64.rs

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: feat(ebpf): add x86_64 eBPF JIT backend

变更概述

本 PR 在 JIT 框架基础上添加 x86_64 eBPF JIT 后端 (jit_x86_64.rs),包含完整的 ALU/JMP/MEM/CALL 指令翻译、两遍编译(insn_size 估算 + 实际发射)、div/mod 零除保护。同时新增 bpf_insn.rs 指令定义、jit_aarch64.rs 空 stub,并将 JitBuffer 的 emit_u32/offset/emit_u8 从 riscv64 限定改为全局可用。

阻塞问题

1. insn_size 系统性错误 — 跳转偏移全部错误

insn_size 用于第一遍编译构建偏移表,两遍编译要求其返回值与实际 emit 字节数精确匹配。当前 insn_size 与实际发射存在系统性偏差:

  • BPF_ALU64 ADD reg:insn_size 返回 6,实际 emit_add_reg64 仅 3 字节(+3 高估)
  • BPF_ALU64 ADD imm:insn_size 返回 10,实际 emit_mov_imm64(10) + emit_add_reg64(3) = 13(-3 低估)
  • BPF_ALU32 ADD reg:insn_size 返回 6,实际 add(3) + zext32(2) = 5(+1 高估)
  • BPF_ALU32 ADD imm:insn_size 返回 9,实际 mov_imm32(6) + add(3) + zext32(2) = 11(-2 低估)
  • BPF_DIV/MOD:insn_size 返回 50,实际 64 位 33B、32 位 34B(+17 高估)
  • BPF_CALL:insn_size 返回 16,实际 mov_imm64(10) + call_reg(3) = 13(+3 高估)

根因:默认 op_size=6 假设 3 字节 imm_src 加载,但 emit_mov_imm64 实际 10B、emit_mov_imm32 实际 6B。emit_divmod 实际 33B 而非 50B。emit_zext32 仅 2B 而非预估 8B。

影响:任何带跳转的 eBPF 程序都会因 offsets 数组错误而生成无效的 JIT 代码。

2. BPF_MOD 除零语义违反 eBPF 规范

emit_divmod 中,is_div=false(取模)且 src==0 时:代码先 xor rdx,rdx(清零),跳过 DIV 指令,再 mov dst,rdx = 0。但 eBPF 规范要求 mod by 0 返回被除数(dst 不变)。riscv64 后端通过跳过 remu 并保持 dst 不变来正确实现。

3. 缺少 JIT 正确性测试

PR body 声称 cargo xtask clippy 通过,但缺少 JIT 实际正确性验证。insn_size 的错误只能通过运行带控制流的 eBPF 程序来发现。建议添加 debug_assert 验证 insn_size 与实际 emit 字节数的一致性。

CI 状态

  • Check formatting:success
  • Run sync-lint:success
  • Run clippy run_container:skipped(path filter 未覆盖 ebpf 路径)
  • Test starry aarch64 qemu:failure — 该失败在 aarch64 QEMU 上,与 x86_64 JIT 后端无关,应为已有基础设施问题
  • 其余 QEMU 测试:cancelled

本地验证:cargo fmt --check 通过。

重复/重叠分析

  • PR #1139(已关闭未合并)是本 PR 的前序提交(JIT 框架 + riscv64),本 PR 包含 #1139 的所有 commit。
  • 无其他 open PR 与 eBPF x86_64 JIT 重叠。

结论

insn_size 系统性错误和 BPF_MOD 除零语义错误是阻塞性正确性问题。建议作者逐一修正 insn_size 并添加自验证断言,修复 emit_divmod 的 MOD 除零路径。

Powered by mimo-v2.5-pro

Comment thread os/StarryOS/kernel/src/ebpf/ebpf_jit/jit_x86_64.rs Outdated
Comment thread os/StarryOS/kernel/src/ebpf/ebpf_jit/jit_x86_64.rs Outdated

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: feat(ebpf): add x86_64 eBPF JIT backend

变更概述

本 PR 在 JIT 框架基础上添加 x86_64 eBPF JIT 后端 (jit_x86_64.rs),包含完整的 ALU/JMP/MEM/CALL 指令翻译。同时新增 bpf_insn.rs 指令定义、jit_aarch64.rs 空 stub、jit_riscv64.rs 完整实现,并将 JitBufferemit_u32/offset/emit_u8 改为无条件可用。

前次 review 阻塞问题已修复

  1. insn_size 系统性错误 → 已修复:新代码使用 JitBuffer::new_sizing() 计数缓冲区进行第一遍 sizing,调用与第二遍完全相同的 emit_* 函数,保证字节数精确匹配。解决了此前估算字节数与实际发射不一致导致跳转偏移错误的问题。

  2. BPF_MOD 除零语义 → 已修复emit_divmod 中,当 is_div=false 且 src==0 时,不再修改 dst(保持被除数不变)。当 is_div=true 且 src==0 时,dst 设为 0。符合 eBPF 规范。

实现分析

x86_64 后端采用两遍编译架构:

  • 第一遍:pass1_sizing() 使用计数缓冲区,调用实际 emit_* 函数仅计算字节数
  • 第二遍:实际发射机器码,使用第一遍的 offsets 表修正跳转目标

这种架构消除了此前独立 insn_size 函数的估算误差问题。代码结构清晰,寄存器映射合理(BPF R0-R10 → x86-64 rax/rdi/rsi/rdx/rcx/r8/rbx/r13-r15/rbp),正确处理了 dst==RCX 时使用 R11 作为暂存寄存器的别名冲突。

div/mod 的零除保护实现正确:先保存 dst 到 R10,测试 src 是否为零,跳过实际 DIV 指令。对于 MOD,结果赋值在非零路径内执行,确保 src==0 时 dst 不被修改。

CI 状态

所有 CI check runs 均为 skipped 状态(路径过滤器未覆盖 os/StarryOS/kernel/src/ebpf/ 路径)。这是预期行为,因为 eBPF 代码不在 CI 的变更检测范围内。

本地验证:

  • cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --all-features -- -D warnings ✅ 通过
  • cargo fmt --check 发现的差异在 os/axvisor/src/fdt/create.rs(非本 PR 变更文件)
  • cargo test 失败于 scope_local 链接器错误(pre-existing infrastructure 问题,与本 PR 无关)

重复/重叠分析

  • PR #1139(已关闭未合并)是本 PR 的前序提交(JIT 框架 + riscv64),本 PR 包含 #1139 的所有 commit
  • 搜索 open PR:无其他 PR 与 eBPF x86_64 JIT 重叠
  • base 分支上无 eBPF JIT 相关代码

非阻塞性建议

  1. 缺少 JIT 正确性测试:建议后续 PR 添加 debug_assert 验证两遍编译的偏移一致性,或添加简单的 eBPF 程序端到端测试。当前因 sizing pass 调用实际 emit 函数,正确性已通过架构保证,但运行时测试能增强信心。

  2. BPF_END 未实现:字节序转换仅打印警告,未实际转换。建议后续补齐。

  3. emit_divmod DIV 除零路径:当 src==0 且 is_div=true 时,代码先清零 RAX,跳过 DIV,再 mov dst, RAX = 0。虽然语义正确(eBPF 规范要求 div by 0 返回 0),但 riscv64 后端在此场景下通过 jal + addi dst, zero, 0 跳转设置 dst。两种实现一致。

结论

前次 review 的两个阻塞问题(insn_size 系统性错误和 BPF_MOD 除零语义)已在新提交中修复。代码结构清晰,clippy 通过,CI skip 是预期行为。建议 approve。

Powered by mimo-v2.5-pro

@mai-team-app
mai-team-app Bot requested a review from ZCShou June 6, 2026 02:23
@CN-TangLin CN-TangLin closed this Jun 6, 2026
@CN-TangLin CN-TangLin reopened this Jun 6, 2026

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: feat(ebpf): add x86_64 eBPF JIT backend

变更概述

在 JIT 框架基础上添加 x86_64 eBPF JIT 后端 (jit_x86_64.rs),完整实现 JitBackend trait。同时包含 bpf_insn.rs 指令定义、jit_aarch64.rs 空 stub、jit_riscv64.rs 完整实现、ebpf_jit/mod.rs JIT 框架(含两遍编译和计数缓冲区 sizing pass),以及 ebpf/mod.rs 模块接入。

前次 review 阻塞问题已修复确认

  1. insn_size 系统性错误 → 已修复:新代码使用 JitBuffer::new_sizing() 计数缓冲区进行第一遍 sizing,调用与第二遍完全相同的 emit_* 函数,通过架构保证字节数精确匹配,彻底消除了独立 insn_size 估算函数的误差问题。

  2. BPF_MOD 除零语义 → 已修复emit_divmod 中,当 is_div=false 且 src==0 时,MOD 结果赋值仅在非零路径内执行,跳过时 dst 保持不变,符合 eBPF 规范。DIV 除零时预先清零 RAX 再赋值 dst,语义正确。

已手动 resolve 两个未过期的 review thread(insn_size 和 BPF_MOD),因为对应问题在当前代码中已修复。

实现分析

x86_64 后端采用两遍编译架构:

  • 第一遍:pass1_sizing() 使用 JitBuffer::new_sizing() 计数缓冲区,调用实际 emit_* 函数仅计算字节数
  • 第二遍:实际发射机器码,使用第一遍的 offsets 表修正跳转目标

代码结构清晰,寄存器映射合理(BPF R0-R10 → x86-64 rax/rdi/rsi/rdx/rcx/r8/rbx/r13-r15/rbp),正确处理 dst==RCX 时使用 R11 作为暂存寄存器的别名冲突。prologue 保存 callee-saved 寄存器(rbx/r13/r14/r15)并分配 512 字节 BPF 栈空间,RBP 偏移量 -32 正确对应 4 个 push 的空间。

div/mod 零除保护实现正确,与 riscv64 后端语义一致。

CI 状态

所有 CI check runs 均为 skipped 状态(共 16 个 check,全部 skipped)。路径过滤器 ebpf 路径不在 CI 变更检测范围内,这是预期行为。

本地验证:

  • cargo fmt --check ✅ 通过
  • cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --all-features -- -D warnings ✅ 通过

重复/重叠分析

  • PR #1139(已关闭未合并)是本 PR 的前序提交(JIT 框架 + riscv64),本 PR 包含 #1139 的所有 commit
  • base 分支上无 eBPF JIT 相关代码(ebpf_jit/mod.rs 不存在于 dev)
  • 搜索 open PR:无其他 PR 与 eBPF x86_64 JIT 重叠(open PRs 包括 Wayland app #1160、cgroup #1156 等,均不涉及 eBPF JIT)

非阻塞性建议

  1. BPF_END 未实现:字节序转换仅打印 warn!,未实际转换。建议后续补齐 BPF_TO_LE/BPF_TO_BE 处理。

  2. JIT 正确性测试:建议后续 PR 添加单元测试,验证计数缓冲区 sizing pass 与实际发射的一致性,以及端到端 eBPF 程序 JIT 执行的正确性。

结论

前次 review 的两个阻塞问题(insn_size 系统性错误和 BPF_MOD 除零语义)已在新提交中正确修复。代码结构清晰,计数缓冲区 sizing pass 通过架构保证字节数精确匹配,clippy/fmt 通过,CI skip 为预期行为。Approve。

Powered by mimo-v2.5-pro

@CN-TangLin
CN-TangLin force-pushed the feat/ebpf-jit-2-x86-64 branch 3 times, most recently from 658acef to e720414 Compare June 6, 2026 03:09

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: feat(ebpf): add x86_64 eBPF JIT backend

变更概述

在 JIT 框架基础上添加 x86_64 eBPF JIT 后端 (jit_x86_64.rs),完整实现 JitBackend trait。同时包含 bpf_insn.rs 指令定义、jit_aarch64.rs 空 stub、jit_riscv64.rs 完整实现、ebpf_jit/mod.rs JIT 框架(含两遍编译和计数缓冲区 sizing pass),以及 ebpf/mod.rs 模块接入。

前次 review 阻塞问题已修复确认

  1. insn_size 系统性错误 → 已修复:新代码使用 JitBuffer::new_sizing() 计数缓冲区进行第一遍 sizing,调用与第二遍完全相同的 emit_* 函数,通过架构保证字节数精确匹配,彻底消除了独立 insn_size 估算函数的误差问题。

  2. BPF_MOD 除零语义 → 已修复emit_divmod 中,当 is_div=false 且 src==0 时,MOD 结果赋值仅在非零路径内执行,跳过时 dst 保持不变,符合 eBPF 规范。

  3. BPF_END → 已实现:使用 rol reg16,8bswap reg32bswap reg64 实现 BPF_TO_BE,BPF_TO_LE 在 x86_64 上为 no-op。

新发现的阻塞问题

32 位 DIV/MOD 路径未清零 EDX

emit_divmod 的 32 位分支(第 490-516 行)在执行 DIV R11d没有清零 EDX。x86 的 DIV r/m32 指令将 EDX:EAX 作为被除数(64 位),如果 EDX 不为零,商和余数都会错误。

对比 64 位路径(第 470 行),在非零分支内正确执行了 emit_xor_reg64(buf, X86_RDX, X86_RDX)。但 32 位路径中缺少对应的 emit_xor_reg32(buf, X86_RDX, X86_RDX)

影响:任何使用 32 位 BPF_DIV 或 BPF_MOD 的 eBPF 程序都会产生错误结果,因为 EDX 可能包含上一条 BPF 指令的残留值。

修复方案:在第 500 行(emit_rex_if)之前添加 emit_xor_reg32(buf, X86_RDX, X86_RDX),与 64 位路径对齐。

CI 状态

所有 CI check runs 均为 skipped 状态(共 16 个 check,全部 skipped)。路径过滤器 ebpf 路径不在 CI 变更检测范围内,这是预期行为。

本地验证:

  • cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --all-features -- -D warnings ✅ 通过
  • cargo fmt --check(仅检查 PR 变更文件)✅ 通过

重复/重叠分析

  • PR #1139(已关闭未合并)是本 PR 的前序提交(JIT 框架 + riscv64),本 PR 包含 #1139 的所有 commit
  • base 分支上无 eBPF JIT 相关代码
  • 搜索 open PR:无其他 PR 与 eBPF x86_64 JIT 重叠(#1160 Wayland app、#1156 cgroup 等均不涉及 eBPF JIT)

结论

前次 review 的 insn_sizeBPF_MOD 阻塞问题已正确修复。但新发现 32 位 DIV/MOD 路径未清零 EDX 的正确性 bug,需要修复。

Powered by mimo-v2.5-pro

Comment thread os/StarryOS/kernel/src/ebpf/ebpf_jit/jit_x86_64.rs
@CN-TangLin
CN-TangLin force-pushed the feat/ebpf-jit-2-x86-64 branch from e720414 to 3e8f810 Compare June 6, 2026 03:13

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: feat(ebpf): add x86_64 eBPF JIT backend

变更概述

在 JIT 框架基础上添加 x86_64 eBPF JIT 后端 (jit_x86_64.rs),完整实现 JitBackend trait,覆盖 ALU/JMP/MEM/CALL/BPF_END 指令翻译。同时包含 bpf_insn.rs 指令定义、jit_aarch64.rs 空 stub、jit_riscv64.rs 完整实现,以及 ebpf_jit/mod.rs JIT 框架(两遍编译 + 计数缓冲区 sizing pass)。将 JitBufferemit_u32/offset/emit_u8 改为无条件可用。

前次 review 阻塞问题已修复确认

  1. insn_size 系统性错误 → 已修复:使用 JitBuffer::new_sizing() 计数缓冲区进行第一遍 sizing,调用与第二遍完全相同的 emit_* 函数,通过架构保证字节数精确匹配。
  2. BPF_MOD 除零语义 → 已修复emit_divmod 中,当 is_div=false 且 src==0 时,MOD 结果赋值仅在非零路径内执行,跳过时 dst 保持不变,符合 eBPF 规范。
  3. 32 位 DIV/MOD 路径 EDX 清零 → 已修复:32 位路径在执行 DIV R11d 前正确清零 EDX(emit_xor_reg32(buf, X86_RDX, X86_RDX))。
  4. BPF_END 字节序转换 → 已实现:使用 rol reg16,8(16 位)、bswap reg32(32 位)、bswap reg64(64 位)实现 BPF_TO_BE,BPF_TO_LE 在 x86_64 上为 no-op。编码正确。

新发现的阻塞问题

emit_st 硬编码 RCX 作为 scratch 导致寄存器冲突

emit_st 使用 X86_RCX 作为 scratch 寄存器来加载立即数。但当 BPF 目标寄存器是 R4 时,bpf_to_x86(4) = X86_RCX,此时立即数会覆盖基址寄存器。

// 当 base == X86_RCX 时,立即数被加载到 RCX,覆盖了基址
emit_mov_imm32(buf, X86_RCX, imm as i32);  // RCX = immediate
emit_store_mem(buf, base, adjusted_off, X86_RCX, insn.size());  // 写入 [RCX+off] 但 RCX 已被覆盖

影响:任何使用 BPF R4 作为 BPF_ST(立即数存储)基址寄存器的 eBPF 程序都会将数据写入错误的内存地址。

对比 riscv64 后端:riscv64 使用 RV_T2(x28,非 BPF 映射寄存器)作为 scratch,不存在此冲突。

修复方案:使用 X86_R11(非 BPF 映射寄存器)作为 scratch,类似 ALU 操作中的 imm_src 逻辑:

let scratch = if base == X86_RCX { X86_R11 } else { X86_RCX };
if insn.size() == BPF_DW {
    emit_mov_imm64(buf, scratch, imm as u64);
    emit_store_mem(buf, base, adjusted_off, scratch, BPF_DW);
} else {
    emit_mov_imm32(buf, scratch, imm as i32);
    emit_store_mem(buf, base, adjusted_off, scratch, insn.size());
}

CI 状态

所有 16 个 CI check runs 均为 skipped 状态(路径过滤器未覆盖 os/StarryOS/kernel/src/ebpf/ 路径)。这是预期行为。

本地验证:

  • cargo fmt --check(PR 变更文件) ✅ 通过
  • cargo xtask clippy --package starry-kernel(13 项 feature 检查) ✅ 全部通过

重复/重叠分析

  • PR #1139(已关闭未合并)是本 PR 的前序提交(JIT 框架 + riscv64),本 PR 包含 #1139 的所有 commit
  • base 分支上无 eBPF JIT 相关代码
  • 搜索 open PR:#1160 Wayland app、#1156 cgroup 等均不涉及 eBPF JIT,无重叠

非阻塞性建议

  1. JIT 正确性测试:建议后续 PR 添加单元测试,验证 sizing pass 与实际发射的一致性,以及端到端 eBPF 程序 JIT 执行的正确性。

结论

前次 review 的三个阻塞问题(insn_sizeBPF_MOD 除零、32 位 EDX 清零)均已正确修复。但新发现 emit_st 硬编码 RCX 作 scratch 导致寄存器冲突的正确性 bug,需要修复。

Powered by mimo-v2.5-pro

Comment thread os/StarryOS/kernel/src/ebpf/ebpf_jit/jit_x86_64.rs Outdated

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: feat(ebpf): add x86_64 eBPF JIT backend

变更概述

在 PR#1139 JIT 框架基础上,添加 x86_64 eBPF JIT 后端 (jit_x86_64.rs),完整实现 JitBackend trait。同时包含 bpf_insn.rs 指令定义、jit_aarch64.rs 空 stub、jit_riscv64.rs 完整实现、ebpf_jit/mod.rs JIT 框架(计数缓冲区 sizing pass + 两遍编译),以及 ebpf/mod.rs 模块接入。将 JitBufferemit_u32/offset/emit_u8 改为无条件可用。

历史阻塞问题修复确认

  1. insn_size 系统性错误 → 已修复:使用 JitBuffer::new_sizing() 计数缓冲区进行第一遍 sizing,调用与第二遍完全相同的 emit_* 函数,通过架构保证字节数精确匹配。这是比 riscv64 固定 4 字节方案更通用的解法——完美适配 x86 变长编码。

  2. BPF_MOD 除零语义 → 已修复emit_divmod 中,is_div=false 且 src==0 时,MOD 结果赋值仅在非零路径内执行,跳过时 dst 保持不变,符合 eBPF 规范。DIV 除零时预先清零 RAX 再赋值 dst,语义正确。

  3. 32 位 DIV/MOD EDX 清零 → 已修复:32 位路径在执行 DIV R11d 前正确执行 emit_xor_reg32(buf, X86_RDX, X86_RDX) 清零 EDX。

  4. emit_st RCX 寄存器冲突 → 已修复(commit 329c3f6):当 base==X86_RCX 时使用 X86_R11 作为 scratch,与 ALU 操作中 imm_src 模式一致。

  5. BPF_END 字节序转换 → 已实现:使用 rol reg16,8(16 位)、bswap reg32(32 位)、bswap reg64(64 位)实现 BPF_TO_BE,BPF_TO_LE 在 x86_64 上为 no-op。REX/legacy prefix 编码顺序正确。

实现分析

  • 两遍编译架构pass1_sizing() 使用 JitBuffer::new_sizing() 计数缓冲区,调用实际 emit_* 函数仅计算字节数;第二遍发射机器码。这种架构从根本上消除了独立 insn_size 估算函数的误差问题。
  • 寄存器映射合理(R0→RAX, R1→RDI, ..., R4→RCX, R10→RBP),dst==RCX 时统一使用 R11 作为暂存寄存器,模式一致。
  • div/mod 零除保护实现正确,与 riscv64 后端语义完全一致。
  • prologue/epilogue:正确保存/恢复 callee-saved 寄存器(RBX, R13-R15),分配 512 字节 BPF 栈空间。

CI 状态

所有 CI check runs 均为 skipped 状态(路径过滤器未覆盖 os/StarryOS/kernel/src/ebpf/ 路径)。Check formattingRun sync-lint 在 host runner 上成功通过。总体 workflow 标记为 failure 是因为 container 依赖的测试被 skip,非实际代码失败。

本地验证:

  • cargo fmt --check ✅ 通过
  • cargo clippy --all-features -D warnings ✅ 通过
  • cargo test 失败于 scope_local 链接器错误(pre-existing infrastructure 问题,与本 PR 无关)

重复/重叠分析

  • PR #1139(已关闭未合并)是本 PR 的前序提交(JIT 框架 + riscv64),本 PR 包含 #1139 的所有 commit
  • base 分支上无 eBPF JIT 相关代码
  • 无其他 open PR 与 eBPF x86_64 JIT 重叠

非阻塞性建议

  1. JIT 正确性测试:建议后续 PR 为 x86_64 后端添加单元测试(参考 riscv64 的 28 个测试),至少覆盖:计数缓冲区 sizing pass 与实际发射一致性验证、emit_load_imm64 边界值、BPF_END 编码正确性。
  2. eBPF 端到端测试:建议添加简单 eBPF 程序的 JIT 执行正确性测试,覆盖带跳转的控制流场景。

结论

前次 review 的五个阻塞问题均已正确修复。代码结构清晰,计数缓冲区 sizing pass 架构优秀,clippy/fmt 通过,CI skip 为预期行为(路径过滤器未覆盖 ebpf 目录)。Approve。

Powered by mimo-v2.5-pro

@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.

已审查当前 head 329c3f69cc9b6905e8ee3b5d2901e06d03adf68c

本 PR 在 #1142 的 eBPF JIT 框架/RISC-V 后端基础上补充 x86_64 后端,并修正了 sizing pass、DIV/MOD、emit_st RCX scratch 等历史 review 问题。当前代码中这些旧问题已确认修复,我也已将对应的 4 个已修复 review thread resolve 掉。

阻塞问题:当前 JIT 模块会在 loongarch64 Starry 构建中编译,但 Backend 只在 aarch64riscv64x86_64 下定义,导致当前 head 的 Test starry loongarch64 qemu / run_container CI 失败。这个失败直接来自本 PR 新增的 os/StarryOS/kernel/src/ebpf/ebpf_jit/mod.rs,不是外部基础设施问题。

本地验证结果:

  • cargo fmt --check:通过。
  • cargo xtask clippy --package starry-kernel:13/13 通过。
  • cargo xtask starry test qemu --arch loongarch64:失败,build 阶段在 starry-kernel 报 22 个 E0433: cannot find type Backend in this scope,首个位置是 os/StarryOS/kernel/src/ebpf/ebpf_jit/mod.rs:182

CI 状态:当前 head 对应 run 27053609675Detect changed pathsCheck formatting / run_hostRun sync-lint / run_host 通过;Test starry loongarch64 qemu / run_container 失败,失败命令为 cargo xtask starry test qemu --arch loongarch64,错误与本地复现一致。其他大量 job 是路径/矩阵跳过或在该失败后取消。

重复/重叠分析:base dev 上已有 eBPF runtime,但没有 ebpf_jit/JitBackend#1142 是本系列的框架/RISC-V 前置 PR,#1140 当前包含其改动,属于 stacked/partial-overlap;#1141#1140 基础上继续做 AArch64 和执行路径接入,是下游重叠;#1163 是 JIT 回归测试补充,属于互补;#1010 的 seccomp BPF 语义与本 PR 不重叠。

merge-readiness 清单:PR 元数据已核对,作者不是当前账号;未解决线程已检查并 resolve 已修复项;独立 worktree 已使用;base/open PR 重叠已分类;本地验证和当前 head CI 已核对;当前存在 PR 相关 CI/构建失败,因此不能 approve。

#[cfg(target_arch = "riscv64")]
use jit_riscv64::Riscv64Backend as Backend;
#[cfg(target_arch = "x86_64")]
use jit_x86_64::X86_64Backend as Backend;

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.

这里目前只在 aarch64riscv64x86_64 下给 Backend 起别名,但 ebpf_jit 模块在 ebpf/mod.rs 中对所有 Starry 架构都会编译。loongarch64 目标会进入本文件却没有任何 Backend 定义,当前 head 的 cargo xtask starry test qemu --arch loongarch64 因此在 Backend::emit_* 处报 22 个 E0433 并失败。这个是本 PR 新增模块导致的跨架构构建回归。建议把 JIT 模块或 try_jit_compile 按受支持架构 gate 住,并确保不支持 JIT 的架构回退解释器或不编译这些 Backend::... 调用;不要导入 crate::mm::Backend 来掩盖名字冲突。

@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.

已复核当前 head 329c3f69cc9b6905e8ee3b5d2901e06d03adf68c

本 PR 在 #1142 的 eBPF JIT 框架/RISC-V 后端基础上补充 x86_64 JIT 后端;前序 review 中关于 sizing pass、DIV/MOD 语义、32 位 EDX 清零、emit_st RCX scratch 和 x86_64 BPF_END 的 correctness 问题在当前代码中已经修复,对应旧 thread 已保持 resolved。

阻塞问题仍然存在:ebpf_jit 模块在 loongarch64 Starry 构建中仍会被编译,但 Backend 只在 aarch64/riscv64/x86_64 下定义,导致当前 head 的 loongarch64 Starry QEMU 构建失败。

验证结果:

  • git diff --check origin/dev...HEAD:通过。
  • cargo fmt --check:通过。
  • cargo xtask starry test qemu --arch loongarch64 -c smoke:失败,build 阶段在 starry-kernel 报 22 个 E0433: cannot find type Backend in this scope,首个位置是 os/StarryOS/kernel/src/ebpf/ebpf_jit/mod.rs:182

CI 状态:当前 head 对应 run 27053609675Detect changed pathsCheck formatting / run_hostRun sync-lint / run_host 通过;Test starry loongarch64 qemu / run_container 失败,日志与本地复现一致;后续大量 host/container job 是该失败后的 cancelled/skipped。

重复/重叠分析:base dev 没有 ebpf_jit/JitBackend#1142 是本系列框架/RISC-V 前置 PR,#1140 当前包含其改动,属于 stacked/partial-overlap;#1141 进一步包含 #1140 并接入 AArch64 和执行路径,属于下游重叠;#1163 是 JIT 回归测试补充,属于互补;#1010 的 seccomp BPF 语义不重叠。

Reviewer 分配:本 PR 命中 ebpf 方向;讨论 594 中该方向没有可请求的明确 GitHub login,现有 ZCShou reviewer 已保留,未新增 reviewer。


match class {
BPF_ALU | BPF_ALU64 => {
Backend::emit_alu(&mut buf, insn, class == BPF_ALU64);

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.

这个阻塞点在当前 head 仍然存在:loongarch64 Starry 构建会编译到本模块,但 Backend 只在 aarch64/riscv64/x86_64 下定义。本地 cargo xtask starry test qemu --arch loongarch64 -c smoke 和当前 CI Test starry loongarch64 qemu / run_container 都在这里开始报 E0433: cannot find type Backend in this scope。需要对不支持 JIT 的架构完整 cfg-gate ebpf_jit/try_jit_compile,或保证这些架构不编译 Backend::... 调用并回退解释器路径。

…kend

Add a modular JIT compilation backend for eBPF programs in the StarryOS
kernel, with a hand-written RISC-V 64 code generator. Pass 1 computes
instruction sizes and builds an offset table; pass 2 emits native code
into executable (JitBuffer) memory.

## Architecture

- JitBackend trait with per-architecture cfg-gated implementations
- RISC-V 64 backend: ~830 lines supporting all ALU/JMP/MEM/CALL instructions
  with zero-division guards, BPF frame pointer offset adjustment, and
  AUIPC+load_imm+ADD+JALR pattern for PC-relative conditional jumps
- x86_64 and aarch64 stubs included for future completion
- 28 #[cfg(test)] unit tests for emit_load_imm64 boundaries and insn_size
  golden-match validation
- JitBuffer: PAGE_SIZE-aligned executable buffer with icache/D-CVAU flush

## Testing

- cargo fmt --check: passes
- cargo xtask clippy --package starry-kernel: all 13 feature configs pass

Signed-off-by: CN-TangLin <2242120212@qq.com>
- Register mapping: r0=RAX, r1=RDI, r2=RSI, r3=RDX, r4=RCX, r5=R8,
  r6=RBX, r7=R13, r8=R14, r9=R15, r10=RBP
- Prologue: PUSH RBP; MOV RBP,RSP; PUSH all callee-saved (RBX,R13-R15);
  MOV r1,RDI (address arg); SUB RSP,512 (BPF stack)
- All ALU/ALU64 instructions with immediate and register operands,
  including special imm_src handling for dst==RCX (BPF r4) conflict
- Shift operations: LSH/RSH/ARSH with RCX alias protection when
  dst==RCX (save to R10, shift R10, move back)
- JMP/JMP32: conditional via CMP+Jcc; JSET via TEST+JNE
- ST/STX/LDX: B/H/W/DW via MOV+MOVZX/MOVSX with BPF frame offset
- DIV/MOD zero-division protection: TEST src/src; JE skip; DIV; return 0
- Helper call: MOV rdi,rsi,rdx,rcx,r8 (5 args)

- RCX alias in ALU immediate path (imm_src pattern)
- Shift register alias when dst==RCX (save to R10, restore)
- BPF_MOV|BPF_K double immediate load
- emit_divmod R10/R11 temp register alias
- emit_st/emit_stx bpf_to_x86 base register
- Prologue MOV RBP,RSP direction
- BPF_EXIT dead code removal
- emit_load_mem BPF_W redundant AND
- JSET redundant CMP
- sz redundant variable simplification

Signed-off-by: CN-TangLin <2242120212@qq.com>
When the base register is X86_RCX (BPF R4), the hardcoded scratch
register X86_RCX gets overwritten with the immediate value before
it is used as the store base address.  Use X86_R11 as the scratch
when base == X86_RCX, matching the pattern already used in ALU
operations.
@CN-TangLin
CN-TangLin force-pushed the feat/ebpf-jit-2-x86-64 branch from 329c3f6 to 3feb3f7 Compare June 12, 2026 07:00

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: feat(ebpf): add x86_64 eBPF JIT backend

变更概述

在 PR#1139 JIT 框架基础上,添加 x86_64 eBPF JIT 后端 (jit_x86_64.rs),完整实现 JitBackend trait,覆盖 ALU/JMP/MEM/CALL/BPF_END 指令翻译。同时包含 bpf_insn.rs 指令定义、jit_aarch64.rs 空 stub、jit_riscv64.rs 完整实现、ebpf_jit/mod.rs JIT 框架(计数缓冲区 sizing pass + 两遍编译),以及 ebpf/mod.rs 模块接入。

历史阻塞问题修复确认

  1. insn_size 系统性错误 → 已修复:使用 JitBuffer::new_sizing() 计数缓冲区进行第一遍 sizing,调用与第二遍完全相同的 emit_* 函数,通过架构保证字节数精确匹配。这是比 riscv64 固定 4 字节方案更通用的解法——完美适配 x86 变长编码。

  2. BPF_MOD 除零语义 → 已修复emit_divmod 中,is_div=false 且 src==0 时,MOD 结果赋值仅在非零路径内执行,跳过时 dst 保持不变,符合 eBPF 规范。DIV 除零时预先清零 RAX 再赋值 dst,语义正确。

  3. 32 位 DIV/MOD EDX 清零 → 已修复:32 位路径在执行 DIV R11d 前正确执行 emit_xor_reg32(buf, X86_RDX, X86_RDX) 清零 EDX。

  4. emit_st RCX 寄存器冲突 → 已修复:当 base==X86_RCX 时使用 X86_R11 作为 scratch,与 ALU 操作中 imm_src 模式一致。

  5. BPF_END 字节序转换 → 已实现:使用 rol reg16,8(16 位)、bswap reg32(32 位)、bswap reg64(64 位)实现 BPF_TO_BE,BPF_TO_LE 在 x86_64 上为 no-op。REX/legacy prefix 编码顺序正确。

  6. emit_divmod counting guard → 已修复!buf.counting() 守卫防止 sizing pass 中 null 指针解引用。

  7. cfg 门控 → 已添加#[cfg(any(target_arch = "aarch64", target_arch = "riscv64", target_arch = "x86_64"))] 确保 loongarch64 等不支持架构可编译。

实现分析

  • 两遍编译架构pass1_sizing() 使用 JitBuffer::new_sizing() 计数缓冲区,调用实际 emit_* 函数仅计算字节数;第二遍发射机器码。从根本上消除了独立 insn_size 估算函数的误差问题。
  • 寄存器映射合理(R0→RAX, R1→RDI, R2→RSI, R3→RDX, R4→RCX, R5→R8, R6→RBX, R7→R13, R8→R14, R9→R15, R10→RBP),dst==RCX 时统一使用 R11 作为暂存寄存器,模式一致。
  • div/mod 零除保护实现正确,与 riscv64 后端语义完全一致。
  • prologue/epilogue:正确保存/恢复 callee-saved 寄存器(RBX, R13-R15),分配 512 字节 BPF 栈空间。RBP 偏移量 -32 正确对应 4 个 push 的空间。
  • BPF_END 编码正确:0x66 C1 /0 08(ROL r16,8)、0F C8+r(BSWAP r32)、REX.W 0F C8+r(BSWAP r64)。
  • 函数调用无需参数重排:x86-64 SysV ABI 的参数寄存器(RDI/RSI/RDX/RCX/R8)恰好对应 BPF R1-R5 的映射,相比 riscv64 的显式 shuffle 更简洁。
  • 栈对齐:prologue 5×push + sub 512 = 552 字节(552 mod 16 = 8),加上函数入口的 return address push(8 字节),RSP 对齐到 16 字节,满足 SysV ABI 对 CALL 目标的要求。

CI 状态

所有 16 个 CI check runs 均为 skipped 状态(路径过滤器未覆盖 os/StarryOS/kernel/src/ebpf/ 路径)。Check formattingRun sync-lint 在 host runner 上成功通过。CI skip 为预期行为。

本地验证:

  • cargo fmt --check ✅ 通过
  • cargo xtask clippy --package starry-kernel ✅ 全部 14 项 feature 检查通过

重复/重叠分析

  • PR #1139(已关闭未合并)是本 PR 的前序提交(JIT 框架 + riscv64),本 PR 包含 #1139 的所有 commit
  • base 分支上无 eBPF JIT 相关代码
  • 搜索 open PR:#1244 ax-net 多网口、#1243 等均不涉及 eBPF JIT,无重叠

非阻塞性建议

  1. JIT 正确性测试:建议后续 PR 添加端到端 eBPF 程序 JIT 执行的正确性测试(包括带跳转的控制流程序),以及 sizing pass 与实际发射一致性的 debug_assert。

结论

历次 review 的所有阻塞问题(insn_size 系统性错误、BPF_MOD 除零语义、32 位 EDX 清零、emit_st RCX 寄存器冲突、counting guard、cfg 门控)均已正确修复。代码结构清晰,x86-64 机器码编码正确,clippy/fmt 通过,CI skip 为预期行为。Approve。

Powered by mimo-v2.5-pro

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: feat(ebpf): add x86_64 eBPF JIT backend

变更概述

在 JIT 框架基础上添加 x86_64 eBPF JIT 后端 (jit_x86_64.rs),完整实现 JitBackend trait,覆盖 ALU/JMP/MEM/CALL/BPF_END 指令翻译。同时包含 bpf_insn.rs 指令定义、jit_aarch64.rs 空 stub、jit_riscv64.rs 完整实现、ebpf_jit/mod.rs JIT 框架(计数缓冲区 sizing pass + 两遍编译),以及 ebpf/mod.rs 模块接入。

历史阻塞问题修复确认

  1. insn_size 系统性错误 → 已修复:使用 JitBuffer::new_sizing() 计数缓冲区进行第一遍 sizing,调用与第二遍完全相同的 emit_* 函数,通过架构保证字节数精确匹配。
  2. BPF_MOD 除零语义 → 已修复emit_divmod 中,is_div=false 且 src==0 时,MOD 结果赋值仅在非零路径内执行,跳过时 dst 保持不变,符合 eBPF 规范。
  3. 32 位 DIV/MOD EDX 清零 → 已修复:32 位路径在执行 DIV R11d 前正确执行 emit_xor_reg32(buf, X86_RDX, X86_RDX) 清零 EDX。
  4. emit_st RCX 寄存器冲突 → 已修复:当 base==X86_RCX 时使用 X86_R11 作为 scratch,与 ALU 操作中 imm_src 模式一致。
  5. BPF_END 字节序转换 → 已实现:使用 rol reg16,8(16 位)、bswap reg32(32 位)、bswap reg64(64 位)实现 BPF_TO_BE,BPF_TO_LE 在 x86_64 上为 no-op。编码正确。
  6. counting() 守卫 → 已添加emit_divmod 中 jump 偏移回填前检查 !buf.counting(),防止 sizing pass 中 null 指针解引用。
  7. cfg 门控 → 已添加JitBackend trait / JitCompiler / try_jit_compile 均有 cfg(any(target_arch = "aarch64", target_arch = "riscv64", target_arch = "x86_64")) 门控,不支持架构返回 None
  8. SAFETY 注释 → 已添加unsafe impl Send/Sync for JitBuffer 有清晰的安全说明。

实现分析

  • 两遍编译架构pass1_sizing() 使用计数缓冲区,调用实际 emit_* 函数仅计算字节数;第二遍发射机器码。从根本上消除了独立 insn_size 估算函数的误差问题。
  • 寄存器映射合理(R0→RAX, R1→RDI, R2→RSI, R3→RDX, R4→RCX, R5→R8, R6→RBX, R7→R13, R8→R14, R9→R15, R10→RBP),dst==RCX 时统一使用 R11 作为暂存寄存器,模式一致。
  • div/mod 零除保护实现正确,与 riscv64 后端语义完全一致。
  • prologue/epilogue正确保存/恢复 callee-saved 寄存器(RBX, R13-R15),分配 512 字节 BPF 栈空间。
  • BPF_CALL通过 HelperFn 表查找并调用。

CI 状态

所有 16 个 CI check runs 均为 skipped 状态(路径过滤器未覆盖 os/StarryOS/kernel/src/ebpf/ 路径)。这是预期行为。

本地验证:

  • cargo fmt --check ✅ 通过
  • cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --all-features -- -D warnings ✅ 通过

非阻塞性建议

  1. JIT 正确性测试:建议后续 PR 添加单元测试,验证计数缓冲区 sizing pass 与实际发射的一致性,以及端到端 eBPF 程序 JIT 执行的正确性。

结论

历史 review 的全部阻塞问题均已正确修复。代码结构清晰,计数缓冲区 sizing pass 通过架构保证字节数精确匹配,clippy/fmt 通过,CI skip 为预期行为。Approve。

Powered by mimo-v2.5-pro

… JIT

- Add counting() public method and !buf.counting() guards around
  buf.entry() direct writes in emit_divmod (2 locations)
- Add SAFETY comments for unsafe impl Send/Sync on JitBuffer
- Add cfg gate on JitBackend/JitCompiler/try_jit_compile for
  aarch64/riscv64/x86_64 only
- Add fallback try_jit_compile returning None for unsupported archs
@CN-TangLin
CN-TangLin force-pushed the feat/ebpf-jit-2-x86-64 branch from 3feb3f7 to 0dec640 Compare June 12, 2026 10:44

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: feat(ebpf): add x86_64 eBPF JIT backend

变更概述

在 JIT 框架基础上添加 x86_64 eBPF JIT 后端 (jit_x86_64.rs),完整实现 JitBackend trait,覆盖 ALU/JMP/MEM/CALL/BPF_END 指令翻译。同时包含 bpf_insn.rs 指令定义、jit_aarch64.rs 空 stub、jit_riscv64.rs 完整实现、ebpf_jit/mod.rs JIT 框架(计数缓冲区 sizing pass + 两遍编译),以及 ebpf/mod.rs 模块接入。

历史阻塞问题修复确认

  1. insn_size 系统性错误 → 已修复:使用 JitBuffer::new_sizing() 计数缓冲区进行第一遍 sizing,调用与第二遍完全相同的 emit_* 函数,通过架构保证字节数精确匹配。这是比独立 insn_size 估算函数更优的方案——完美适配 x86 变长编码。

  2. BPF_MOD 除零语义 → 已修复emit_divmod 中,is_div=false 且 src==0 时,MOD 结果赋值仅在非零路径内执行,跳过时 dst 保持不变,符合 eBPF 规范。DIV 除零时预先清零 RAX 再赋值 dst,语义正确。

  3. 32 位 DIV/MOD EDX 清零 → 已修复:32 位路径在执行 DIV R11d 前正确执行 emit_xor_reg32(buf, X86_RDX, X86_RDX) 清零 EDX。

  4. emit_st RCX 寄存器冲突 → 已修复:当 base==X86_RCX 时使用 X86_R11 作为 scratch,与 ALU 操作中 imm_src 模式一致。

  5. BPF_END 字节序转换 → 已实现:使用 rol reg16,8(16 位)、bswap reg32(32 位)、bswap reg64(64 位)实现 BPF_TO_BE,BPF_TO_LE 在 x86_64 上为 no-op。编码正确。

实现分析

  • 两遍编译架构pass1_sizing() 使用 JitBuffer::new_sizing() 计数缓冲区,调用实际 emit_* 函数仅计算字节数;第二遍发射机器码。通过架构保证字节数精确匹配。
  • 寄存器映射合理(R0→RAX, R1→RDI, ..., R4→RCX, R6→RBX, R10→RBP),dst==RCX 时统一使用 R11 作为暂存寄存器,模式一致。
  • div/mod 零除保护实现正确,与 riscv64 后端语义完全一致。!buf.counting() 防护确保 sizing pass 中不解引用 null 指针。
  • Prologue/Epilogue:正确保存/恢复 callee-saved 寄存器(RBX, R13-R15),分配 512 字节 BPF 栈空间。
  • cfg 门控#[cfg(any(target_arch = "aarch64", target_arch = "riscv64", target_arch = "x86_64"))] 门控 + 不支持架构的 fallback 正确。
  • bpf_insn re-export:无条件 re-export 避免 clippy unused import 警告。

CI 状态

所有 CI check runs 均为 skipped 状态(路径过滤器未覆盖 os/StarryOS/kernel/src/ebpf/ 路径)。这是预期行为,因为 eBPF 代码不在 CI 的变更检测范围内。

本地验证:

  • cargo fmt --check ✅ 通过
  • cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --all-features -- -D warnings ✅ 通过

重复/重叠分析

  • PR #1139(已关闭未合并)是本 PR 的前序提交(JIT 框架 + riscv64),本 PR 包含 #1139 的所有 commit
  • base 分支上无 eBPF JIT 相关代码
  • 搜索 open PR:无其他 PR 与 eBPF x86_64 JIT 重叠

非阻塞性建议

  1. JIT 正确性测试:建议后续 PR 添加单元测试验证 sizing pass 与实际发射的一致性,以及端到端 eBPF 程序 JIT 执行的正确性。
  2. emit_jmp 短跳优化:当前所有条件跳转使用 near (32-bit) 形式,对于目标偏移在 ±127 字节内的情况可使用 short (8-bit) 形式减少代码体积。

结论

所有历史阻塞问题均已正确修复。代码结构清晰,两遍编译架构通过计数缓冲区保证字节数精确匹配,clippy/fmt 通过,CI skip 为预期行为。Approve。

Powered by mimo-v2.5-pro

The stub jit_aarch64.rs used super::super:: to reference JitBackend
and JitBuffer, which fails on aarch64 targets since they are defined
in the parent module (ebpf_jit), not the grandparent (ebpf). Changed
to super:: to match the correct module hierarchy.

Fixes CI failure: "error[E0432]: unresolved imports
super::super::JitBackend, super::super::JitBuffer"

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: feat(ebpf): add x86_64 eBPF JIT backend

变更概述

本 PR 在 JIT 框架基础上添加 x86_64 eBPF JIT 后端 (jit_x86_64.rs, 904 行),完整实现 JitBackend trait,覆盖 ALU/ALU64/JMP/MEM/CALL/BPF_END 指令翻译。同时包含 JIT 框架 (ebpf_jit/mod.rs, 计数缓冲区 sizing pass + 两遍编译)、riscv64 后端 (1284 行)、aarch64 空 stub、bpf_insn.rs 指令定义,以及 ebpf/mod.rs 模块接入。

历史阻塞问题修复确认

  1. insn_size 系统性错误 → 已修复:使用 JitBuffer::new_sizing() 计数缓冲区进行第一遍 sizing,调用与第二遍完全相同的 emit_* 函数,通过架构保证字节数精确匹配。比 riscv64 固定 4 字节方案更通用——完美适配 x86 变长编码。

  2. BPF_MOD 除零语义 → 已修复emit_divmod 中,is_div=false(MOD)且 src==0 时,结果赋值仅在非零路径内执行,跳过时 dst 保持不变,符合 eBPF 规范(mod by 0 → dst 不变)。DIV 除零时预先清零 RAX 再赋值 dst,语义正确(div by 0 → dst = 0)。

  3. 32 位 DIV/MOD EDX 清零 → 已修复:32 位路径在 DIV R11d 前正确执行 emit_xor_reg32(buf, X86_RDX, X86_RDX) 清零 EDX。

  4. emit_st RCX 寄存器冲突 → 已修复:当 base==X86_RCX 时使用 X86_R11 作为 scratch(let scratch = if base == X86_RCX { X86_R11 } else { X86_RCX }),与 ALU 操作中 imm_src 模式一致。

  5. BPF_END 字节序转换 → 已实现:使用 rol reg16,8(16 位)、bswap reg32(32 位)、bswap reg64(64 位)实现 BPF_TO_BE,BPF_TO_LE 在 x86_64 上为 no-op。REX/legacy prefix 编码顺序正确。

  6. 计数缓冲区安全守卫 → 已添加emit_divmod!buf.counting() 守卫防止 sizing pass 中空指针解引用。

  7. 架构门控 → 已添加#[cfg(any(target_arch = "aarch64", target_arch = "riscv64", target_arch = "x86_64"))] 门控 + 不支持架构 fallback 返回 None。

实现分析

  • 两遍编译架构pass1_sizing() 使用计数缓冲区,调用实际 emit_* 函数仅计算字节数;第二遍发射机器码。从根本上消除独立 insn_size 估算函数的误差问题。
  • 寄存器映射合理(R0→RAX, R1→RDI, R2→RSI, R3→RDX, R4→RCX, R5→R8, R6→RBX, R7→R13, R8→R14, R9→R15, R10→RBP),R0-R5 恰好匹配 SysV ABI 参数寄存器,无需 helper call 时参数重排。dst==RCX 时统一使用 R11 作为暂存寄存器。
  • prologue/epilogue:正确保存/恢复 callee-saved 寄存器(RBP, RBX, R13-R15),分配 512 字节 BPF 栈空间。RBP 偏移量 -32 正确对应 4 个 push 的空间。
  • div/mod 零除保护实现正确,64 位和 32 位路径均与 riscv64 后端语义一致。
  • BPF_CALL:利用 BPF→x86 寄存器映射与 SysV ABI 的天然匹配,直接 mov rax, helper_addr; call rax,简洁高效。

CI 状态

所有 16 个 CI check runs 均为 skipped 状态。路径过滤器未覆盖 os/StarryOS/kernel/src/ebpf/ 路径,这是预期行为。Check formattingRun sync-lint 在 host runner 上成功通过。

本地验证:

  • cargo fmt --check(PR 变更文件)✅ 通过
  • cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --all-features -- -D warnings ✅ 通过

重复/重叠分析

  • PR #1139(已关闭未合并)是本 PR 的前序提交(JIT 框架 + riscv64),本 PR 包含 #1139 的所有 commit。
  • base 分支上无 eBPF JIT 相关代码。
  • 搜索 open PR:#1248 rockchip-rga、#1247 gdb-multiarch 等均不涉及 eBPF JIT,无重叠。
  • 无 Cargo.toml/Cargo.lock 变更,无 crates.io patch 依赖。

非阻塞性建议(后续工作)

  1. JIT 正确性测试:建议后续 PR 添加端到端 eBPF 程序 JIT 执行的单元测试,覆盖带控制流的程序验证跳转偏移正确性。当前计数缓冲区 sizing pass 通过架构保证字节数精确匹配,但运行时测试能增强信心。

结论

所有历史阻塞问题均已正确修复。代码结构清晰,计数缓冲区 sizing pass 架构设计精良,clippy/fmt 通过,CI skip 为预期行为。Approve。

Powered by mimo-v2.5-pro

CN-TangLin added a commit to CN-TangLin/tgoskits that referenced this pull request Jun 12, 2026
Port the following fixes from the riscv64 (rcore-os#1142) and x86_64 (rcore-os#1140) JIT
branches into the AArch64 JIT branch (rcore-os#1141):

- Add 13 `!buf.counting()` guards in jit_riscv64.rs to prevent null
  pointer dereference during the sizing pass when `buf.entry()` returns
  null
- Add 2 `!buf.counting()` guards in jit_x86_64.rs for the same reason
- Fix BPF_DIV zero-division beq offset from hardcoded 12u32 to dynamic
  `(end - skip - 4) as u32`
- Add `JitBuffer::counting()` accessor method in mod.rs
- Fix `emit_load_imm32` redundant `(val as i32)` cast

These were the root cause of the riscv64 QEMU CI crash on this branch.
Match the fix applied on the AArch64 JIT branch (rcore-os#1141) for consistency.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: feat(ebpf): add x86_64 eBPF JIT backend

变更概述

在 JIT 框架基础上添加 x86_64 eBPF JIT 后端 (jit_x86_64.rs),完整实现 JitBackend trait,覆盖 ALU/JMP/MEM/CALL/BPF_END 指令翻译。同时包含 bpf_insn.rs 指令定义、jit_aarch64.rs 空 stub、jit_riscv64.rs 完整实现、ebpf_jit/mod.rs JIT 框架(计数缓冲区 sizing pass + 两遍编译),以及 ebpf/mod.rs 模块接入。

历史阻塞问题修复确认

前次 review 发现的所有阻塞问题已在当前 head(1ac1e04)中修复:

  1. insn_size 系统性错误 → 已修复:使用 JitBuffer::new_sizing() 计数缓冲区进行第一遍 sizing,调用与第二遍完全相同的 emit_* 函数,通过架构保证字节数精确匹配。
  2. BPF_MOD 除零语义 → 已修复emit_divmod 中,is_div=false 且 src==0 时,MOD 结果赋值仅在非零路径内执行,跳过时 dst 保持不变,符合 eBPF 规范。
  3. 32 位 DIV/MOD EDX 清零 → 已修复:32 位路径在执行 DIV 前正确执行 emit_xor_reg32(buf, X86_RDX, X86_RDX)
  4. emit_st RCX 寄存器冲突 → 已修复:当 base==X86_RCX 时使用 X86_R11 作为 scratch。
  5. BPF_END 字节序转换 → 已实现:使用 rol reg16,8/bswap reg32/bswap reg64 实现。
  6. 计数缓冲区 guard → 已添加!buf.counting() 防止 sizing pass 中空指针解引用。
  7. cfg 门控 → 已添加#[cfg(any(target_arch = "aarch64", target_arch = "riscv64", target_arch = "x86_64"))] 正确门控 JIT 模块,不支持架构返回 None

新发现的阻塞问题

BPF_END 字节序转换条件反转

jit_x86_64.rs 第 745 行:

let to_be = (insn.code & BPF_X) == 0;

根据 eBPF 规范,BPF_TO_BE = 0x08(即 BPF_X),BPF_TO_LE = 0x00。所以 (insn.code & BPF_X) == 0 表示 BPF_TO_LE(小端),而 != 0 表示 BPF_TO_BE(大端)。

当前代码将 to_be 设为 trueinsn.code & BPF_X == 0,即 BPF_TO_LE 时执行字节交换,BPF_TO_BE 时不做任何操作——这与 eBPF 规范相反。

对比 jit_riscv64.rs 第 588 行:

let to_be = (insn.code & BPF_X) != 0;  // 正确

riscv64 后端使用 != 0,这是正确的。

影响:任何使用 BPF_TO_BE 的 eBPF 程序在 x86_64 JIT 下不会进行字节交换(数据错误),而 BPF_TO_LE(本应 no-op)反而会错误地交换字节。

修复方案:将第 745 行改为 let to_be = (insn.code & BPF_X) != 0;,与 riscv64 后端对齐。

CI 状态

所有 16 个 CI check runs 均为 skipped 状态(路径过滤器未覆盖 os/StarryOS/kernel/src/ebpf/)。这是预期行为,因为 eBPF 代码不在 CI 的变更检测范围内。

本地验证:

  • cargo fmt --check ✅ 通过
  • cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --target x86_64-unknown-none -- -D warnings ✅ 通过(0 warnings, 0 errors)

重复/重叠分析

  • PR #1139(已关闭未合并)是本 PR 的前序提交(JIT 框架 + riscv64),本 PR 包含 #1139 的所有 commit
  • base 分支上无 eBPF JIT 相关代码
  • 无其他 open PR 与 eBPF x86_64 JIT 重叠

非阻塞性建议

  1. JIT 正确性测试:建议后续 PR 添加单元测试,验证 sizing pass 与实际发射的一致性,以及端到端 eBPF 程序 JIT 执行的正确性。
  2. emit_zext32 编码:当前使用 AND reg32, reg32 实现 32 位零扩展,功能正确,但可以考虑使用 mov reg32, reg32 获得相同效果并可能更直观。

结论

前次 review 的所有阻塞问题均已正确修复。但最新 commit(1ac1e04)引入了 BPF_END 字节序转换条件反转的新 bug,需要修复。

Powered by mimo-v2.5-pro

}
BPF_END => {
// BPF_TO_BE: byte swap to big-endian (x86_64 is little-endian native)
let to_be = (insn.code & BPF_X) == 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

条件反转:(insn.code & BPF_X) == 0 表示 BPF_TO_LE(小端,x86_64 上应为 no-op),而 != 0 才表示 BPF_TO_BE(大端,需要字节交换)。

当前代码对 BPF_TO_LE 执行字节交换,对 BPF_TO_BE 不做操作,与 eBPF 规范相反。

riscv64 后端(第 588 行)使用 != 0 是正确的。请改为 let to_be = (insn.code & BPF_X) != 0;

@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.

本轮复核(x86_64 eBPF JIT 后端)

本 PR 在 #1142 的 JIT 框架上新增 x86_64 后端(jit_x86_64.rs,覆盖 ALU64/ALU32/JMP/MEM/CALL/BPF_END),并保留 riscv64/aarch64 的对应实现/stub。

历轮阻塞项核对(均已解决)

  1. loongarch64 Starry 构建编译失败(我此前的 cur thread):原因是 Backend 别名只在 aarch64/riscv64/x86_64cfg,而 ebpf_jit 模块对所有 Starry 架构编译。当前 head 已通过把 try_jit_compile 拆为两份解决:真实现 #[cfg(any(aarch64,riscv64,x86_64))](mod.rs:342-350,引用 JitCompiler/Backend),stub #[cfg(not(any(...)))](mod.rs:352-361)对 loongarch64 等返回 None。我本地 cargo xtask starry build -c os/StarryOS/configs/board/qemu-loongarch64.toml 在当前 head 构建成功(Finished release,仅有 unused import/variable 警告),确认 loongarch64 不再因本 PR 编译失败。
  2. emit_st RCX 寄存器冲突(R4 作 base 时覆盖 RCX):已在更早 commit(126a4f30 avoid RCX register conflict in emit_st)修复。
  3. BPF_END 字节序条件反转(mai-team-app 多轮指出 BPF_FROM_BE/BPF_FROM_LE 搞反):当前 jit_x86_64.rs:745let to_be = (insn.code & BPF_X) == 0;。按 eBPF 规范 BPF_X 位(set=BPF_FROM_LE,在 LE 宿主为 no-op;clear=BPF_FROM_BE,需 bswap),当前判定正确(x86_64 LE 宿主上 to_be 时才执行 bswap)。系列里 #1141 的两次 invert/re-invert commit 的最终态也已统一到 (code & BPF_X) == 0

验证(head 1ac1e04aa2)

  • 本地 lint:cargo xtask clippy --package starry-kernel 14/14 通过;cargo fmt --all --check 通过;无 [patch.crates-io]
  • 跨架构构建:cargo xtask starry build -c .../qemu-loongarch64.toml 构建成功(验证非 JIT 架构走 stub 不报错);x86_64/aarch64/riscv64 由远端 CI 覆盖。
  • 远端 CI:本 head 无失败 check。
  • 运行时:x86_64 后端的实际执行正确性由 #1141(执行接入)+ #1163(smoke 套件,待改为执行型断言)共同验证,不在本后端 PR 单独覆盖;本 PR 的 #[allow(dead_code)] 标注也说明这些后端代码在 #1141 接入前未被调用。

重复/重叠

本系列(#1142#1140#1141#1163)同作者,按序推进无外部重复。建议 landing 顺序:#1142(已 approve)→ 本 PR → #1141#1163;各 PR 改同一批 jit_*.rs,需按序 rebase。

其它

  • maintainerCanModify=true;merge state 当前 BLOCKED(待审核)。
  • 构建中出现的 unused import(dealloc/vec::Vec/部分 BPF 常量)与 unused variable(layout)告警来自 #[allow(dead_code)] 区域(#1141 接入前),非阻断;建议 #1141 接入后清理。

结论

x86_64 JIT 后端历轮阻塞(loongarch64 编译、RCX 冲突、BPF_END 条件反转)均已修复,loongarch64 实际构建通过,clippy/fmt/CI 通过、无 patch。作为系列中的架构后端 PR 可合入(执行正确性由 #1141/#1163 覆盖)。

@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.

撤回上一轮 APPROVE 并改为 REQUEST_CHANGES

上一轮我对本 head 的 APPROVE 有误:我当时把 BPF_END 字节序条件记反了,实际核对内核常量后发现当前 head 的 x86_64 后端该条件是反的。本轮更正。

阻塞:BPF_END 字节序判定反转

当前 jit_x86_64.rs:745:

let to_be = (insn.code & BPF_X) == 0;

这与 eBPF 规范相反。权威依据(本仓库已依赖的内核常量 kbindings):

BPF_TO_LE = 0
BPF_TO_BE = 8
BPF_X     = 0x08 = 8

即对 BPF_END 指令,BPF_TO_BEcode0x08 位是置位的(code & BPF_X != 0),BPF_TO_LE清零的。x86_64 是小端宿主,BPF_TO_LE 应为 no-op,BPF_TO_BE 才需 bswap。因此正确写法是:

let to_be = (insn.code & BPF_X) != 0;

当前 == 0 导致:BPF_TO_LE(应为 no-op)反而执行 bswap,而 BPF_TO_BE(应 swap)反而跳过——字节序转换结果完全错误。

同系列交叉核对

  • 本 PR(#1140 x86_64):== 0(错)
  • #1142(riscv64):== 0(同样错,我会另行更正)
  • #1141(aarch64 + x86_64 + riscv64 三后端):均为 != 0(正确)

系列内三个分支在该条件上不一致,而 #1141!= 0 与内核常量一致。本 PR 与 #1142 需要把 == 0 改为 != 0,与 #1141 及规范对齐。commit 历史里 unify BPF_END byte-swap condition to ==0 这一步把方向统一到了错误的 == 0

需要修改

jit_x86_64.rslet to_be = (insn.code & BPF_X) == 0; 改为 != 0,与 #1141 及内核 BPF_TO_BE=8 语义一致,并在修复后补一个真正执行 BPF_END 程序并校验字节序结果的回归(参见 #1163 的执行型断言要求)。

仍成立的部分

上一轮指出的 loongarch64 构建问题(try_jit_compile cfg 拆分)、RCX 冲突修复、clippy/fmt/无 patch 等仍成立且已解决;本轮唯一阻塞是 BPF_END 条件反转。修复该条件后即可重新合入。

(对本轮之前给出的 APPROVE 表示抱歉,系我个人对 eBPF 字节序常量的记忆错误所致。)

@CN-TangLin

Copy link
Copy Markdown
Contributor Author

Closing in favor of rbpf PR #152 (qmonnet/rbpf#152). The JIT backend improvements are being addressed upstream in rbpf first, which will then propagate back to tgoskits.

@CN-TangLin CN-TangLin closed this Jun 16, 2026
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