Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第一期月报(2026.01.20 - 2026.02.22)

开发分支axvisor/feature/ebpf | axebpf


执行摘要

项目 内容
本月目标 构建 AxVisor eBPF 追踪系统,覆盖静态追踪点、VMM 动态探针(hprobe)、Guest 内核探针(guest-kprobe)三条链路
完成度 Phase 1–4 基础目标全部完成;guest-kprobe M1(异常接管闭环)和 M2a/M2b(地址翻译基础链路)里程碑达成
项目价值 AxVisor 获得运行在 EL2 的 eBPF 动态追踪能力,可在不重新编译内核的情况下观测 VMM 内部行为及 guest 内核执行路径
主要风险 guest-kprobe 端到端验证受 guest 生命周期窗口限制:arceos guest 退出过快,linux guest 存在早期 panic,暂无稳定可持续运行的验证基线
下月里程碑 guest-kprobe Stage-2 恢复闭环;接入真实 guest 寄存器上下文;guest 符号表加载

术语说明

本报告首次出现的缩写定义如下:

术语 定义
hprobe Hypervisor Probe:探测 VMM 自身(EL2)函数的动态探针,基于 BRK 断点 + 指令槽软件单步实现
guest-kprobe 从 VMM(EL2)向下探测 guest 内核(EL1)函数的跨特权级动态探针
M1 guest-kprobe 里程碑 1:fault/BRK 匹配路径接管并返回 handled = true,结束"命中但未接管"状态
M2a guest-kprobe 里程碑 2a:实现 GVA→GPA 页表 walker(gva_to_gpa_with,含 L3 page/L2 block)
M2b guest-kprobe 里程碑 2b:VMM 完成 Stage-2 回调注册(guest_pt_read/vm_ttbr1/gpa_to_hpa/stage2_exec
Stage-2 单步 利用 AArch64 MDSCR_EL1.SS 位触发硬件单步异常(EC::SingleStepLowerEL),用于 guest 执行原指令后恢复 XN 权限的机制
GVA/GPA/HPA/HVA Guest Virtual/Physical Address,Host Physical/Virtual Address;四级地址翻译链见附录 A

一、提交历史

日期 Commit 内容
2026-01-31 9a586fc 0e7f87e 73a305d 83c6d2d 2925de2 eBPF 构建与符号支持;trace 命令组;定时器模块;eBPF 追踪集成
2026-02-05 9a9b311 0370bb5 axebpf 改为 git submodule;kprobe 追踪集成
2026-02-06 fd86cf6 989494a e50eeb5 6f7ddd3 kprobe eBPF 程序注册;ksym 命令;trace kprobe 强化;axcpu patch
2026-02-09 cfc9e8b eb61c44 9b24702 2898252 子模块更新;移除独立 ebpf-programs;简化 tracepoint;kprobe→hprobe 重命名
2026-02-10 96abd6a kallsyms:include_bytes! → linker section 注入
2026-02-21 662b3e6 708a828 916b8e7 trace stream/dump/stat;启用 guest-kprobe;kallsyms ELF 原地写入

命令命名历史(重要):2026-02-09 之前,trace kprobe 指 VMM 自身(EL2)探针。2898252 提交后完成重命名:

  • trace hprobe / hretprobe / unhprobe → VMM 探针(EL2,原 trace kprobe
  • trace kprobe / unkprobe → Guest 内核探针(EL1,新增)

旧命令 trace kprobe <symbol> 已废弃,等效替换为 trace hprobe <symbol>


二、已完成工作

2.1 阶段一(1.20 - 1.31):axebpf 模块基础建设

核心成果:从零构建 modules/axebpf,集成 5 个上游库,实现 eBPF 运行时 + Map + 静态追踪点 + Shell 命令全栈。

可验证证据

  • eBPF 程序加载并执行:trace enable shell:shell_command --prog printk && trace stat,输出 COUNTER_MAP 命中计数
  • 上游 PR(已合并):Starry-OS/kbpf-basic#1 — 修复 printf-compat VaList API 在 nightly 2025-12 上的编译失败
  • 相关提交:9a586fc(eBPF 集成)、83c6d2d(eBPF 构建与符号)

追踪点口径说明

  • 框架中定义:25+ 个(含 vcpu_run/hypercall 等规划态事件,详见附录 B)
  • 已插桩且可触发:8 个(vmm_init / config_load / image_load / vm_destroy / timer_tick / timer_event / shell_init / shell_command

2.2 阶段二(2.1 - 2.7):EL2 动态探针

核心成果:适配 EL2 异常处理差异,实现 hprobe 双 BRK 软件单步机制,集成内核符号表。

可验证证据

  • trace hprobe execute_command hprobe_entrytrace list 显示 hits 递增(需目标函数标注 #[inline(never)],见问题 4.1)
  • ksym lookup <symbol> 返回正确地址
  • 相关提交:0370bb5(kprobe 集成)、989494a(ksym 命令)

2.3 阶段三(2.8 - 2.21):架构重构与 Guest-Kprobe

核心成果:三项架构级改造 + guest-kprobe M1/M2 里程碑。

2.3.1 统一事件管线

axebpf 内部提交 9a76fd8:新增 event.rs,64B TraceEvent,所有探针来源统一通过 emit_event() 上报。

可验证证据trace stream -n 5 输出包含 probe_type 字段区分 tracepoint/hprobe/kprobe 来源。

2.3.2 ELF 加载器切换至 aya-obj

axebpf 内部提交 ab494b8:map 重定位和函数调用重定位与主流 eBPF 工具链对齐。

2.3.3 kallsyms 注入修复

可验证证据:修复前,cargo build 无变更也会清空符号,ksym lookup 返回空;修复后(916b8e7),多次 cargo build 后符号仍然有效。

2.3.4 Guest-Kprobe M1/M2(受限可用)

  • M1(2898252 + axebpf 内部 handler 修改):fault/BRK 路径返回 handled = true,不再触发默认异常升级
  • M2a/M2b(axebpf addr_translate.rs + kernel/src/vmm/mod.rs):GVA→GPA→HVA 翻译链路 + VMM hook 注册

可验证证据(受限)

axvisor:/$ trace kprobe vm1:0xffff800080012340 hprobe_entry
# 预期:进入 manager 注册,翻译失败时自动回滚,无 panic
# 当前限制:arceos guest 退出过快,常见 "VM is not in Running state"

三、遇到的问题与解决方案

3.1 LTO 导致被探测函数内联,hprobe 命中数为 0

  • 现象trace hprobe run_cmd_bytes hprobe_entry hits 始终为 0
  • 根因lto = true 使 LTO 跨 crate 内联目标函数,其符号地址处无有效指令,BRK 永远不触发
  • 解法:被探测函数添加 #[inline(never)],已应用至 run_cmd_bytes / execute_command / handle_builtin_commands

3.2 rbpf 内存边界检查导致 Map lookup 失败

  • 现象bpf_map_lookup_elem 返回指针后解引用触发 out of bounds memory load
  • 解法:静态 LOOKUP_BUFFER(512B,Mutex 保护)+ vm.register_allowed_memory() 注册

3.3 Rust nightly VaList API 变更

  • 现象:nightly >= 2025-12 编译报 cannot find type VaListImpl
  • 解法:Fork kbpf-basic,适配新 API,PR 已上游合并(#1

3.4 cargo hardlink 破坏 kallsyms 注入

  • 根因rust-objcopy --update-section 产生新 inode,cargo 下次构建从 deps 硬链接恢复旧文件,覆盖注入的符号
  • 解法inject_kallsymsxtask/src/symbols.rs)改为 ELF 原地写入(OpenOptions::write() + seek()),保持 inode 不变(916b8e7

3.5 Guest-kprobe attach 窗口问题(已知限制)

  • 现象:常见 VM is not in Running state 或翻译阶段回滚
  • 根因:arceos guest 退出过快;linux guest 在当前分支存在早期 not yet implemented panic
  • 当前状态:属于 guest 生命周期窗口限制,非 handler/manager 语义缺陷;下一步通过延长 guest 生命周期或使用长期运行 guest 建立验证基线

四、工作量统计

统一口径:以 git diff 计算提交行数(新增/删除/净增分开列示)。

时间段 新增行 删除行 净增行 主要模块数
1.20 - 1.31 ~3,000 ~0 ~3,000 12(symbols/tracepoint/runtime/maps/helpers/attach 等)
2.1 - 2.7 ~500 ~0 ~500 3 子模块(arm_vcpu/axvm/axplat-aarch64-dyn)
2.8 - 2.21 ~3,050(axebpf 2117 + axvisor 932) ~2,610(axebpf 1394 + axvisor 1212) ~440 axebpf 8 提交 / axvisor 9 提交
合计 ~6,550 行新增 ~2,610 行删除 ~3,940 行净增

2.8-2.21 删除量较大(~2600 行)是因为移除了手写 ELF 解析器和独立 ebpf-programs 构建流程,由 aya-obj 和子模块方式替代,属于有计划的代码整理。


五、当前功能状态(截至 2026-02-22)

能力 状态 限制说明
eBPF 运行时(rbpf + Map + Helper) ✅ 可用
静态追踪点(8 个已插桩事件) ✅ 可用 vCPU 运行时类事件(vcpu_run/hypercall 等)待 axvm 重构后插桩
hprobe/hretprobe(EL2 动态探针) ✅ 可用 被探测函数须标注 #[inline(never)],否则 LTO 内联导致命中失败
统一事件管线(stream/dump/stat) ✅ 可用
guest-kprobe 注册/命中统计/事件发射 ⚠️ 受限可用 需 guest 处于 Running 状态且已发生至少一次 VM-exit;arceos guest 退出过快,linux guest 有早期 panic
guest-kprobe 异常接管闭环(M1) ✅ 已完成 handler 语义正确;端到端验证受限于 guest 窗口
GVA→GPA→HVA 地址翻译(M2a/M2b) ✅ 基础链路完成 翻译失败时自动回滚,无 panic;单步恢复链路未完成
guest 符号名解析(vm<id>:<symbol>) ❌ 规划中 仅支持手动指定 GVA 地址
guest-kprobe 完整恢复链路 ❌ 待实现 缺少 Stage-2 单步(MDSCR_EL1.SS + EC::SingleStepLowerEL)
kretprobe trampoline(guest) ❌ 待实现
eBPF 验证器 ❌ 未实现 当前仅允许加载预编译可信程序

六、下阶段计划

优先级 任务 预计完成 验收定义(DoD)
P0 guest-kprobe Stage-2 恢复闭环 2026-03-07 在可持续运行的 guest 上,trace kprobe 命中后 guest 能继续正常执行(无 fault 循环、无 panic)
P0 接入真实 guest 寄存器上下文 2026-03-07 hprobe_entry 程序能从 eBPF map 读取被探测函数的 x0–x3 参数,与 ksym lookup 地址匹配
P1 guest 符号表加载 2026-03-21 trace kprobe vm0:<symbol> 命令成功注册,trace list 显示符号名而非裸地址
P1 kretprobe trampoline(guest) 2026-03-21 trace kprobe vm0:<addr> hprobe_exit --ret 能捕获 x0 返回值,输出在 trace stream 中可见
P2 标准化 benchmark 2026-04-04 建立 hprobe/tracepoint 命中延迟 p50/p95/p99 基线,写入 docs/perf-baseline.md

七、技术收获

7.1 系统软件方向

  1. eBPF 执行模型:程序加载 → ELF 解析 → Map 重定位 → 验证 → 执行 → Helper 调用约定(r1–r5 传参,r0 返回)完整链路
  2. AArch64 异常体系:EL2 同步异常处理(ESR_EL2.EC/ISS、VBAR_EL2、异常返回)与 EL1 的本质差异
  3. 动态二进制插桩:kprobe 双 BRK 软件单步原理;页表动态权限修改(AP 位、TLB 刷新、I-cache 同步)完整流程
  4. Hypervisor 内存虚拟化:AArch64 两级地址翻译(Stage-1:GVA→GPA;Stage-2:GPA→HPA)及执行权限(XN 位)动态控制

7.2 工程方向

  1. no_std 多库集成:在无标准库环境下集成 5+ 个外部依赖,处理 alloc、spin lock、linker section 等基础设施
  2. 构建系统深度:定位 cargo hardlink + objcopy inode 冲突,实现 ELF 原地写入方案
  3. Cargo feature 依赖链:跨 crate feature 传递(dep/feature 语法),hprobe/guest-kprobe feature 层级设计
  4. 渐进式架构演化:单体 kprobe → hprobe/kprobe 分层 → 统一 TraceEvent 管线,三次迭代均保持已有功能不退化

附录 A:地址翻译链路

GVA(Guest Virtual Address)
  ↓  guest 页表 walk(从 vCPU 上下文读 TTBR1_EL1,四级页表)
GPA(Guest Physical Address)
  ↓  Stage-2 页表(axaddrspace,VTTBR_EL2)
HPA(Host Physical Address)
  ↓  phys_to_virt() 线性映射
HVA(Host Virtual Address,VMM 可直接读写)

Stage-2 fault 模式只需 GPA(修改 XN 位);BRK 注入模式需完整链路至 HVA(读写 guest 指令)。


附录 B:追踪点插桩状态

追踪点 状态 插桩位置
vmm:vmm_init ✅ 可用 kernel/src/main.rs
vmm:config_load ✅ 可用 kernel/src/vmm/config.rs
vmm:image_load ✅ 可用 kernel/src/vmm/images/mod.rs
vmm:vm_destroy ✅ 可用 kernel/src/vmm/vm_list.rs
vmm:timer_tick/event ✅ 可用 kernel/src/vmm/timer.rs
shell:shell_init/command ✅ 可用 kernel/src/shell/
vmm:vcpu_run_enter/exit ❌ 未插桩 待 axvm 重构后在运行循环插桩
vmm:hypercall ❌ 未插桩 待 axvm 重构
vmm:external_interrupt ❌ 未插桩 待 axvm 重构
vmm:irq_inject/handle ❌ 未插桩 待 axvm 重构
vmm:page_fault ❌ 未插桩 arm_vcpu::exception::handle_data_abort
vmm:memory_map/unmap ❌ 未插桩 axaddrspace::AddrSpace