Skip to content

Latest commit

 

History

History
544 lines (402 loc) · 42.4 KB

File metadata and controls

544 lines (402 loc) · 42.4 KB

kei — 项目状态与计划 (PLAN)

本文件于 2026-07-15 更新,记录项目当前状态、近期进展与后续计划。

Refresh log 2026-07-17 (agent/vtty-linux-console:vtty 链路切到 kei_tty)

  • 渲染链路切换:kei 转型期只做 vtty 不做 GUI。just build browser(别名 just build vtty)现在交叉编译 aris-render 的 kei_tty--no-default-features --features png,静态 musl ELF),取代原来的 kei_desktop GUI 链路; just render / wslq-run / wslq-initramfs 默认 initramfs 改为 initramfs_kei_tty.cpio.gzinitramfs_render_new.cpio.gz 在树内已无生产者)。
  • vtty 风格:现代 Linux 内核控制台——黑底、浅色等宽字、[ 0.000000] kei: ... 内核日志式排版、底部 shell 提示符;无科幻元素。控制台帧由 aris 侧 prerender_vtty 在主机离线渲染成 PNG 入 aris 仓,kei_tty 内嵌解码 blit 到 /dev/fb0;WS JSON-RPC 网关(:8423)不变。
  • 文字渲染根因(aris 侧修复):fontique register_fonts 不填充 generic-family / fallback 映射 → CSS 通用族匹配 0 字体 → parley 零 glyph。 aris fix/font-in-tree 分支已修(new_embedded_font_context() 显式接线), 并新增 41 KB DejaVu Sans Mono 子集内嵌字体。
  • scripts/build_render_initramfs.py:默认 bin kei_ui → kei_tty;按 bin 映射 cargo feature(kei_tty=png / kei_ui=render / kei_fbtest=∅),全部 --no-default-features;打包前自建输出目录。
  • 跨仓依赖:需要 aris fix/font-in-tree 分支(celestia-island/aris 的 Draft PR,base dev)。联调:kei 根目录 .env(gitignored)把 ARIS_REPO 指到对应 aris 检出即可;仓库内默认仍是 ../aris
  • 验证:aarch64-unknown-linux-musl kei_tty 交叉编译成功;initramfs 打包 产出 initramfs_kei_tty.cpio.gz;QEMU 端到端启动验证留待集成后进行。

Refresh log 2026-07-15 #6 (aarch64 SMP/PSCI 多核启动)

  • aarch64 SMP 支持实现:从 stub 到完整的多核启动:
    • packages/ostd/src/arch/aarch64/boot/smp.rscount_processors() 从 FDT /cpus 节点统计 CPU 数量;bringup_all_aps() 通过 PSCI CPU_ON(0xC4000003)唤醒每个 AP,收集非 BSP 的 MPIDR。新增 psci_cpu_on() / read_mpidr_el1() / collect_ap_mpidrs() / aarch64_ap_early_entry() 等辅助函数。
    • packages/ostd/src/arch/aarch64/boot/ap_boot.S(新文件):AP 启动汇编 — 设置 MAIR_EL1/TCR_EL1/TTBR1_EL1,启用 MMU,加载 PerApRawInfo 中的栈和 CPU-local 指针,设置 TPIDR_EL1 和 VBAR_EL1,原子递增 CPU ID 计数器,跳转到 Rust aarch64_ap_early_entry
    • packages/ostd/src/arch/aarch64/irq/chip/mod.rsinit_on_ap() 实现完整的 GIC redistributor 唤醒(读取 MPIDR_EL1 计算 GICR 偏移,清除 ProcessorSleep,配置 GICR_SGI 寄存器,启用 timer PPI INTID 30)。
    • 通用框架 packages/ostd/src/boot/smp.rs 已完备(栈分配、ap_early_entry、等待 AP 就绪),本 commit 补全 aarch64 粘合层。
  • 启用方式OSDK.toml-smp ${SMP:-1} → 改为 ${SMP:-4} 即可测试。

Refresh log 2026-07-15 #5 (TLS trait 抽象 + busybox TLS 修复)

  • TLS 初始化重构:将 kernel/src/process/program_loader/elf/load_elf.rs 中 145 行 #[cfg(target_arch = "aarch64")] 的单体 setup_tls() 提取为架构无关的 trait 抽象:
    • 新增 kernel/src/process/program_loader/elf/tls.rs:定义 TlsLayout trait(pthread_size() / gap_above_tp() / init_tcb() / total_alloc() / compute_tp()),封装 musl TLS_ABOVE_TP 布局的架构差异。
    • 实现TlsLayoutAarch64(pthread=0xc8) / TlsLayoutRiscv64(pthread=0xc0) / TlsLayoutX8664(pthread=0xc8),均含完整 TCB 初始化(self/dtvc/locale)。
    • 泛型 setup_tls::<L: TlsLayout>():接受 load_bias 参数,正确计算 PIE 二进制的 TLS 模板重定位地址(修复 tls_phdr_vaddr 无 load bias 的 bug)。
    • load_elf.rs 调用处按 #[cfg(target_arch)] 选择对应 layout,非三大架构返回 None
    • 旧 non-aarch64 分支(仅分配 2 页、无 TCB 初始化)已移除 — riscv64/x86_64 现在与 aarch64 共享相同的 musl TCB 初始化逻辑。

Refresh log 2026-07-15 #4 (riscv64 + x86_64 修复)

  • riscv64 内核启动修复
    • kernel/src/init.rs:添加 ostd::early_println!() 诊断标记(ostd::info!()core::unicode::conversions div-by-zero bug 在 riscv64 上完全抑制);cmdline::init_no_component() 覆盖 riscv64(与 aarch64 相同的 component system 绕过);bsp_idle_loop / first_kthread 加 riscv64 early_println。
    • kernel/src/time/mod.rs:riscv64 使用 init_no_rtc() 绕过(与 aarch64 相同),跳过 system_time::init() / clocks::init() / softirq::init() 全路径。根因:全路径启用 timer 中断回调,回调可能触发 core::unicode::conversions div-by-zero panic → kernel trap。
  • x86_64 启动修复
    • OSDK.toml microvm scheme 新增 grub.boot_protocol = "linux",切换为 Linux bzImage 启动协议。packages/ostd/libs/linux-bzimage/ 基础设施已完备(setup header + bzImage builder),QEMU -kernel 原生支持 bzImage 格式。
    • 根因:原 multiboot2 ELF 为 64-bit,QEMU x86_64 -kernel 的 multiboot loader 仅接受 32-bit ELF(即使 make_elf_for_qemu() patch e_machine 也无效)。

Refresh log 2026-07-15 #3 (webui 骨架 + QEMU 网络 + 三平台验证)

  • 新增 packages/webui/:kei 浏览器端仪表盘,tairitsu + hikari 技术栈。
    • Cargo.toml:独立 crate(非 kei workspace 成员),依赖 tairitsu-vdom/hooks/macros/web + hikari-palette/components/icons,target wasm32-wasip2
    • src/lib.rs:kei 状态仪表盘 — 系统信息卡片(kernel/arch/uptime/memory)、网络状态卡片(host/port/ws status)、终端日志查看器、页脚状态栏。
    • 构建:需 tairitsu-packager dev 启动 dev server(port 3000),浏览器通过 ws://localhost:8423/ws 连接 kei WS JSON-RPC。
  • QEMU 网络端口映射OSDK.toml aarch64 scheme 新增 hostfwd=tcp::8423-:8423,hostfwd=tcp::3000-:3000(webui WS + dev server)。
  • 三平台启动验证
    • aarch64:✅ 完整启动 → initramfs 解包 → dropbear 监听 port 22 → /dev/fb0 注册 → virtio-gpu scanout 320×240。无 OOPS。
    • riscv64⚠️→🔧 已修复代码(init_no_rtc() 绕过 + early_println! 诊断),需重建验证。
    • x86_64⚠️→🔧 已修复代码(microvm 切换 grub.boot_protocol = "linux" → bzImage),需重建验证。
  • 待办:重建 initramfs(含 dropbear host key fix)→ 验证 SSH banner。

Refresh log 2026-07-15 #2 (dropbear host key 修复 + jh7110 + initramfs 路径修复)

  • 修复:dropbear SSH host key 缺失(QEMU 2222 端口可连接但无 SSH banner)。
    • tests/initramfs/build_aarch64_rootfs.sh(line 30-43):构建时通过 qemu-aarch64-static → dropbearkey → ssh-keygen 三级 fallback 生成 ed25519 host key。
    • tests/initramfs/src/init_aarch64(line 11-14):启动时 fallback — 若 host key 不存在则用 /sbin/dropbearkey 生成。
    • 顺便修复:build_aarch64_rootfs.shtest/initramfs/tests/initramfs/ 路径 typo。
  • jh7110 skeleton guardpackages/bsp/jh7110/src/lib.rscompile_error! 替换为 #[deprecated] no-op init()
  • 已提交:commit 416b136

Refresh log 2026-07-15 (vtable 修复 + 收尾清点)

  • 当前分支dev · 领先 origin/dev 1 commit(vtable 修复)· 工作区仅剩 kei-echo agent 的 packages/bsp/jh7110/src/lib.rs
  • 最近提交🔧 Fix PerOpenFileOps vtable dispatch on aarch64. (99e7d95)
  • 已修复并验证
    • PerOpenFileOps vtable dispatch(commit 99e7d95):aarch64 nightly-2026-05-01 下 &dyn PerOpenFileOps → &dyn FileOps / &dyn Any 的 trait upcast vtable 错误导致 EL1 data abort。改为:(1) FileOps::read_at/write_at/readdir_at 直接通过 &dyn PerOpenFileOps vtable 调用(supertrait 继承);(2) as_any() 改为 PerOpenFileOps 必选方法,每个 implementor 显式写 self(按具体类型生成 vtable 条目,无 trait upcast 参与)。19 个 implementor + inode_handle.rs 同步。
    • IoMem::base() 算术溢出(同 commit 99e7d95):线性映射在 high kernel half 的 kva.start() + self.offset 在 aarch64 触发 attempt to add with overflowbase()/read_once()/write_once() 改用 wrapping_add,与 IoMem::new 中的 wrapping_sub 配对。
    • QEMU 启动验证SYS_OPENAT / SYS_SOCKET / SYS_BIND / SYS_LISTEN / SYS_WRITEV 全部成功;dropbear listen 22 端口成功;无 OOPS
  • 遗留疑问
    1. dropbear SSH banner 缺失 ✅ 已修复(commit 416b136):build script + init script 两级 host key 生成。需重建 initramfs 后验证 SSH banner。
    2. KEI_NO_DOM=1:env var 由 init_proc.rs 推给用户空间 init 程序消费(用于 aris-render 跳过 DOM 创建)。本次修复的是内核 vtable crash;用户空间 fontique/skrifa 的 vtable panic 仍未修(见 2026-07-15 早些时 kei-echo 的结论:fork 删除,转向修 kernel)。保留 KEI_NO_DOM=1 不变。
    3. O_APPEND + open_file 交互:仍为预存 FIXME(read() / write_at() 中有标记),与本次 vtable 修复无关,且涉及并发语义,需独立设计。
    4. packages/bsp/jh7110/src/lib.rs:kei-echo agent 的 compile_error!#[deprecated] no-op init() 已提交(commit 416b136)。
    5. packages/ostd/src/io/io_mem/mod.rs 的"linear mapping workaround" 是 aarch64 临时绕过方案(用 wrapping_* 算术恢复 linear_va),非通用正确实现。FIXME: We currently do not limit the I/O memory allocator with the maximum GPA(line 109)仍待修。
  • 后续动作
    1. 验证网关模式 ✅ aarch64 启动链路通
    2. 验证 vtable 修复 ✅ 全部 I/O syscall + dropbear listen
    3. 下一步:(a) 修复 dropbear host key 让 SSH 端到端通;(b) 视 kei-echo 决定是否合入 jh7110 修改;(c) 跨仓 [patch] 收敛到 ~/.cargo/config.toml(aster 派生链共用)。
  • 跨仓依赖:vtty 协议与 kou 对接;浏览器 UI 复用 aris;内核 fork 自 aster(见顶层 patches/ 长期方案)。

Refresh log 2026-07-14

  • 当前分支dev · 领先 origin/dev 0 commits · 工作区干净
  • 最近提交🔧 Gateway mode: aris vtty + WS JSON-RPC server. (0f42289)
  • 未提交改动:无
  • 后续动作
    1. 验证网关模式:aris vtty + WS JSON-RPC 在工业 IoT 边缘硬件(aarch64)上端到端联通。
    2. 固化 kou vtty 协议到 kei 的 init shell,作为终端接入面。
    3. 跨仓 [patch] 收敛到 ~/.cargo/config.toml(aster 派生链共用)。
  • 跨仓依赖:vtty 协议与 kou 对接;浏览器 UI 复用 aris;内核 fork 自 aster(见顶层 patches/ 长期方案)。

0. 当前架构:网关模式(2026-07-14 最新)

架构转变

之前的"桌面 UI"路线(aris-render 预渲染桌面 → /dev/fb0 → QEMU SDL)存在根本性问题:

  1. Vello CPU 光栅化质量无法接受:软件光栅化的文字在所有分辨率下都偏糊,非 GPU 硬件渲染瓶颈
  2. QEMU TCG 性能限制:fb 写入极慢(~0.5ms/byte),实时交互不可行
  3. 复杂度与价值不匹配:桌面 UI 的 tairitsu 组件 + Blitz/Vello 渲染管道极其复杂(24MB 字体、WASM SSR),但产出只是"看起来像桌面"的静态像素

新方向:网关模式

  • kei 作为路由器/网关运行,提供 WS JSON-RPC 服务端口(8423)供 webui 连入
  • HMI 显示由远程 webui 承担(kei.celestia.world),kei 本机只显示简单的 aris-rendered vtty 终端(状态信息)
  • 鼠标/键盘交互暂不处理(待机状态),焦点在 WS JSON-RPC 协议和网络连通性

已完成

项目 状态
aarch64 内核启动 ✅ 完整启动到用户空间
virtio-gpu 硬件光标 ✅ 内核层实现(CMD_UPDATE_CURSOR + CMD_MOVE_CURSOR),但 QEMU monitor mouse_button 不生成 EV_KEY
WS JSON-RPC 服务器 ✅ 端口 8423 监听,WebSocket 握手 + JSON-RPC 2.0 协议,Kei.Ping/Kei.Status/Kei.InputEvent 方法
aris-rendered vtty 显示 ⚠️ 背景色渲染正常,文字不渲染(fontique/parley 字体注册问题)
主 poll 循环 ✅ 多路复用 mouse_fd + ws_listen + ws_clients
IoMem 线性映射修复 ✅ aarch64 virtio-mmio 设备探测和写入可用

当前阻塞

  1. vtty 文字渲染render_html_with_font 可渲染 CSS 颜色/背景,但文字节点无输出。render_html(catch_unwind 版本)触发 fontique panic 后降级到 fill_fallback 像素画。根因:(a) 24MB 全字体过大导致 parley::fontique 注册失败,(b) 86KB 子集字体注册成功但 paint_scene 不渲染文字节点。
  2. riscv64 内核core::unicode::conversions 除零 panic(rustc 在 riscv64imac-unknown-none-elf 上的已知 bug)
  3. x86_64 内核:64-bit multiboot1 ELF 无法用 QEMU -kernel 加载

后续计划

  1. vtty 文字渲染修复:调查 render_html vs render_html_with_font 文字渲染差异。可能从 Blitz DOM 切换到更简单的渲染方式,或使用预渲染文字位图。
  2. webui 集成:kei.celestia.world 托管 webui 前端页面,通过 WS JSON-RPC 连接 kei 网关。页面加载后自动握手。
  3. HMI 远期:aris 嵌入 webui,通过 WebRTC 推流 aris-render 输出到浏览器。HMI 由 webui 控制打开。
  4. riscv64 + x86_64:kernel 侧 bug 需工具链/内核修复,短期无法解决。先聚焦 aarch64。

WSL2 QEMU 全流程打通:启动→aris-render→scanout 像素上屏(2026-07-12)🎉

在 WSL2 QEMU(Ubuntu-24.04, qemu-system-aarch64 8.2.2, cortex-a72 TCG)中完整跑通从内核启动到浏览器界面显示在屏幕的全过程。

最终突破(2026-07-12 晚):浏览器桌面 UI 渲染成功

kei_fbtest(aris-render 包的 binary,aris/packages/render/src/bin/kei_fbtest.rs)通过 row-by-row fb write 策略成功在屏幕上显示浏览器风格桌面界面:

  • 蓝色 header bar + 白色标题图案 + 地址栏
  • 三个信息卡片(含绿色/红色/灰色指示线)
  • 77.0% 非黑像素(screendump 验证)
  • 首像素 RGB=(97,175,239) = #61AFEF 蓝色 header
  • 中间像素 RGB=(33,37,43) = #21252B card 背景色

关键修复

  1. 移除 tracing-subscriber(导致新 musl 二进制在 kei 上卡在初始化)
  2. Row-by-row fb write(每次 2560 字节,避免大 write 卡住 fb write_at)
  3. TLB flush 修复 mmap store-invisibility(所有 mmap 大小 0% corruption)
  4. NULL page workaround(kei_ui 的 Vello NULL deref 不再崩溃)

kei_ui(Blitz DOM + Vello CPU)状态:成功启动并输出 rendering HTML,但 Vello 内部确定性 NULL deref(far=0x10)导致渲染循环。即使最小 HTML 也触发,说明 NULL 在 Vello 初始化而非 HTML 内容。qemu-user 下正常,根因在 ostd VM 与 musl/Vello 数据结构初始化的深层兼容性。

通过 QEMU monitor screendump + 自研零依赖 PPM→PNG 转换器(scripts/ppm_to_png.py)实现截屏分析,验证像素输出。

修复的两个核心 bug

  1. fb write EL1 page faultkernel/src/device/fb.rs):IoMem 的 KVirtArea 映射在重复 write() syscall 后触发 EL1 data abort(ESR=0x96000041, FAR=0xffffdfffffc81128)。修复:Blit 后端绕过 IoMem,直接用 BlitBackend 的固定 PA 线性映射(LINEAR_BASE + 0x60000000,PLAN.md 验证稳定)通过 write_bytes_at 写入。

  2. scanout 不刷新kernel/comps/virtio/src/aarch64_raw_gpu_probe.rs):raw_flush_callback 是 no-op,用户态写入 DMA buffer 后像素不显示。修复:flush callback 每 32 次调用执行一次 flush_framebuffer()(TRANSFER_TO_HOST_2D + RESOURCE_FLUSH),节流避免 QEMU TCG 命令队列溢出。fb write_at 末尾调用 framebuffer.flush_all()

验证证据

  • kei_fbtest 蓝色测试图:screendump 70.6% 非黑像素(之前 37.7% 仅 boot 测试图)
  • 首像素 RGB=(97,175,239) = #61AFEF,与 kei_fbtest 写入的蓝色 header 一致
  • 无 OOPS/page fault(之前每次 ~28s 后崩溃)

新工具链

  • scripts/wsl_qemu_aarch64.sh:WSL2 headless QEMU 启动器 + screendump
  • scripts/ppm_to_png.py:零依赖 PPM→PNG 转换器(含像素统计)
  • scripts/build_render_initramfs.py:构建含 kei_ui/kei_fbtest 的 initramfs
  • justfile wslq-* recipes:wslq-run/wslq-ui/wslq-screenshot/wslq-setup

已知限制

  1. 用户态 mmap store 不到达物理 RAM(ostd 页表构造器 bug,最终根因)kei_memtest 诊断程序(tests/initramfs/src/memtest.c)确认:mmap 匿名区域写入 8192 个 8 字节字后读回,8190 个损坏(99.98%)。fresh mmap 正确清零(0 nonzero),说明问题不在分配而在写入后数据丢失。sbrk 返回 -1(brk 扩展也失败)。malloc 100K 有 99984/102400 字节损坏。

    这是同一个 PLAN.md 记录的 fb store-invisibility bug,但影响所有用户态匿名映射。kei_fbtest 能工作因为它用固定 PA 0x60000000 的线性映射(绕过 bug),而 kei_ui/render_test/kei_desktop 用 heap/mmap(无法绕过)。

    影响链:所有使用堆分配的复杂用户态程序(含 kei_ui 的 Vello 渲染、kei_desktop 的 C 程序)都因脏内存导致 NULL/无效指针崩溃(far=0x0far=0x10)。一致的损坏模式 x21=0x7840407878404078(ASCII x@@x 重复)出现在所有崩溃中。

    修复方向(需深入 ostd packages/ostd/src/mm/page_table/cursor/map 逻辑):调查为何 demand-paged 用户映射在 TCG 下 store 不到达物理页。已排除:TLB 一致性(加 flush 无效)、页清零(alloc_frame 正确清零)、分配失败(frame 正常分配)。PLAN.md 前四轮迭代定位到"kernel PT 线性映射的 store 路径 vs boot PT 不一致",但深层根因仍在 cursor.map 内部。

  2. kei_ui 启动已验证(DIRECT_INIT 绕过 busybox):修改 build_render_initramfs.py/init 直接是 kei_ui ELF(不经 busybox shell),kei_ui 成功启动并输出 rendering 1280x800 UI...(在 Vello 渲染阶段因上述 mmap bug 崩溃)。busybox 本身也因同样 bug 崩溃。

  3. x86_64 编译有 9 个 acpi crate 错误(E0432/E0433/E0277):acpi::madt/AcpiHandler 等 API 在 acpi 6.1.1 变更,kei fork 未适配。预先存在的 regression,非本次引入。

  4. WSL2 仅装了 qemu-system-arm(aarch64),x86_64/riscv64 的 system emulator 需 apt install qemu-system-x86 qemu-system-misc(需 sudo 密码)。Windows QEMU 有全部架构。

跨架构编译状态(2026-07-13 更新)

架构 编译 启动 用户空间 显示 备注
aarch64 ✅ 完整启动 + 用户空间 ✅ kei_desktop 运行 ✅ aris-render Windows 风格桌面 81.5% 非黑像素 (640x480) ARM64 Image 格式启动,FDT@0x48200000
riscv64 ✅ (VDSO_LIBRARY_DIR 已设置) ✅ OpenSBI→S-mode→ostd init DONE→Components Bootstrap ❌ 组件初始化 trap(距用户空间一步) rv64,svpbmt,zkr;vDSO=vdso_riscv64.so
x86_64 ✅ (acpi 5.2.0 + tdx fix) ⚠️ multiboot1 64-bit ELF 无法用 QEMU -kernel 加载 需要 GRUB ISO loader(无 sudo 无法安装 grub-mkrescue)

2026-07-13 多架构验证里程碑

  1. aarch64 完整桌面渲染 🎉:通过 ARM64 Image 格式(objcopy 从 ELF 转换)让 QEMU 正确生成 FDT 并通过 x0 传递。kei_desktop(aris-render 包)渲染 Windows 风格桌面:

    • 什亭之匣白天壁纸渐变(#b8f7f8→#e9f1fc,采样自 shittim-chest bg.webp)
    • 桌面图标(浏览器/文件/终端/设置 2x2 网格)
    • "aris · kei" 窗口(标题栏 + 地址栏 + 内容)
    • 开始菜单(搜索框 + 6 个应用磁贴 + 电源按钮)
    • 任务栏(Start 按钮 + 固定应用 + 系统托盘 + 时钟)
    • 验证:640x480 screendump 81.5% 非黑像素,首像素 #b8f7f8 = 壁纸顶色
  2. riscv64 启动到组件阶段:内核在 QEMU virt + OpenSBI v1.5.1 下从 S-mode 启动,完整通过 ostd 初始化(frame allocator、kernel page table、SMP),到达 component bootstrap 后 trap。距 spawn_init_process 仅一步。

  3. x86_64 编译通过但启动受阻:acpi 6.1.1→5.2.0 降级 + tdx_guest cfg 修复后编译 0 错误。但 64-bit multiboot1 ELF 无法用 QEMU -kernel 加载("Cannot load x86-64 image, give a 32bit one")。需要 GRUB rescue ISO(boot.method = "grub-rescue-iso"),但环境无 grub-mkrescue/xorriso。

关键修复(本次会话)

  • aarch64 FDT 缺失:OSDK 输出的 ELF 不触发 QEMU 的 ARM64 Image 检测,导致 FDT 不生成(x0=0,RAM 全零)。修复:aarch64-linux-gnu-objcopy -O binary 生成 ARM64 Image 格式(带 "ARMd" magic @ offset 56),QEMU 正确生成 FDT 并通过 x0 传递。
  • riscv64/x86_64 编译VDSO_LIBRARY_DIR=tests/vdso 环境变量;wsl_build_kernels.sh 自动设置。
  • DrvFs root-owned 文件权限:WSL target/ 下有 1928 个 root 拥有的 build artifact(来自历史 root 构建),导致 cargo "Permission denied"。清理 release/{deps,.fingerprint,build,incremental} 后修复。
  • CJK 路径/mnt/d/源代码/... 下 cargo-osdk 可工作但慢;通过 bash script.sh(而非内联 bash -lc)避免变量展开破坏。

kei_desktop 二进制aris/packages/render/src/bin/kei_desktop.rs):纯像素渲染(5x7 位图字体 + Bgrx 背景色),通过 /dev/fb0 write 路径输出。避免 tracing-subscriber(musl malloc 初始化卡死)。支持 KEI_FB 环境变量覆盖 fb 路径(主机测试用)。所有 3 架构交叉编译成功(aarch64/riscv64gc/x86_64-unknown-linux-musl)。

跨架构编译状态(2026-07-12 存档)

架构 编译 启动 显示 备注
aarch64 ✅ 完整启动 + 用户空间 ✅ aris-render 像素上屏 (70.6%) WSL2 QEMU 验证,主开发架构
riscv64 ⚠️ 仅缺 vdso_riscv64.so inode cfg fix 后内核代码编译通过;vDSO 需交叉编译
x86_64 ❌ 9 个 acpi crate 错误 预存 regression:acpi 6.1.1 API 变更未适配

修复的 riscv64 编译 bugkernel/src/fs/file/inode_handle.rs):file_ops_and_is_offset_aware 的 aarch64 fallback 只门控了 let inode 但后续行无条件使用 inode,导致 riscv64 E0425。修复:整个 fallback 块用 cfg(target_arch = "aarch64") 门控。

输入设备验证(WSL2 QEMU monitor 模拟):

  • virtio-keyboard:注册成功(QEMU Virtio Keyboard, KEY=true)
  • virtio-mouse:注册成功(QEMU Virtio Mouse, KEY=true, REL=true)
  • 点击模拟(mouse_move/mouse_button/sendkey):前后截屏像素一致(kei_fbtest 无交互逻辑,预期行为)

virtio-gpu 黑屏根因修正 + 双初始化修复(2026-07-10 → 07-11 修正)🐛

修正了长期被误判为「QEMU TCG used-ring bug」的黑屏根因。

通过捕获 QEMU 串口日志 + virtio-gpu trace(-d trace:virtio_gpu_cmd_*)发现真正的故障链:

  1. aarch64_raw_gpu_probe::probe() 先通过裸 MMIO 成功初始化 GPU:GET_DISPLAY_INFO resp=0x1101RESOURCE_CREATE_2D resp=0x1100ATTACH_BACKING resp=0x1100(fb_pa=0x40eb7000)、SET_SCANOUT resp=0x1100,scanout 绑定到 resource 0x1 @ 1280×800。
  2. 随后 virtio::init() 的 transport 循环(lib.rs:84再次发现同一设备,执行 write_device_status(DeviceStatus::empty())(lib.rs:89-91)——这会复位 QEMU virtio-gpu 的内部状态,清空 resource + scanout 绑定
  3. GpuDevice::init() 随后返回 UnsupportedConfig,scanout 再无重建,窗口恒黑。

修复:在 transport 循环中,若 raw probe 已声明 GPU(is_ready() 为真),则跳过该设备的复位与重初始化(continue),保持 raw probe 建立的 scanout。修复后串口日志确认:[virtio] dev #1: GPU already claimed by raw probe, skipping reset,screendump 从 640×480(未绑定的默认面)变为 1280×800(正确 scanout)。

残留(2026-07-11 二次修正根因):先前判定「QEMU TCG 2D blit 问题」仍属误判。真正的根因是 kei 的 EL2 stage-2 地址翻译表与 stage-1 线性映射不一致

  • kei 运行于 EL1,但 virtualization=on 下 QEMU virt 的 EL2 仍活跃,stage-2(VTTBR_EL2)翻译表处于生效状态。
  • AT S1E1R 只走 stage-1,返回 IPA(中间物理地址),不是设备 DMA 看到的真 PA。
  • 通过 QEMU monitor xp /xg <addr> 直接读客户机物理内存证实:FRAMEBUFFER 的 IPA(如 0x40eb8000)在 QEMU RAM 中全零,而同段的 VQ_MEM IPA(0x412a1000有数据——说明 stage-2 表把 FRAMEBUFFER 这 4MB 区域的 IPA 重映射到了别的真 PA,内核写入落在了 stage-2 未覆盖/错位的页上,DMA 因此读到零。
  • AT S12E1R(stage-1+stage-2 联合翻译,能给出真 PA)在 kei 的 HCR_EL2 配置下会 trap(ESR EC=0),无法从 EL1 执行,故无法直接读取真 PA。
  • VQ_MEM(16KB)写入能到达 QEMU RAM,FRAMEBUFFER(4MB)不能——差异在 stage-2 表覆盖范围。

这是 kei 内核侧的 stage-2 页表 bug,不是 QEMU 的限制。 修复方向:(1) 让 EL2 stub 在 drop 到 EL1 前禁用 stage-2(HCR_EL2.VM=0,使 IPA==PA),或 (2) 修复 stage-2 表覆盖全部内核 .bss(含 4MB FRAMEBUFFER),或 (3) 用内核页分配器(DmaCoherentGpuDevice::init 路径已用)替代裸 .bss 静态数组——分配器走的页会被 stage-2 正确映射。此修复涉及 ostd/EL2 boot 代码,超出本会话范围。

2026-07-11 三次修正(QEMU xp 全 RAM 扫描):上述 stage-2 假设也不完全准确。进一步用 QEMU monitor xp /xg 对整个 2GB RAM(0x40000000..0xC0000000,4MB 步长)扫描 0xff00ff00/0xcafebabe 标记,全 RAM 无一命中——内核写入 FRAMEBUFFER VA 的 4MB 数据在 QEMU 物理内存中任何位置都不存在,尽管内核从该 VA 读回 0xff00ff00 且无页错误。HCR_EL2=0x80000000(仅 RW=1,VM=0)表明 stage-2 实际未启用,故 IPA==PA,AT S1E1R 返回的应是真 PA。结论:kei 内核页表(ostd 构建)将 FRAMEBUFFER 的 4MB .bss 静态区域映射到了一个 AT S1E1R 报告的 PA(0x40eb7000,在 QEMU RAM 范围内),但实际 store 指令落在了别处且无故障——这是 ostd 页表构造器与 TCG store 路径不一致的深层 bug。 16KB 的 VQ_MEM 正常,4MB 的 FRAMEBUFFER 异常,差异在区域大小与可能的块映射(2MB block)边界。修复需深入 ostd 页表构造代码。lib.rs 已加 RAW_GPU_PROBE_ENABLED 常量(默认 true)便于 A/B 测试 asterinas GpuDevice::init(DmaCoherent)路径——但实测该路径返回 UnsupportedConfig,同样不通。

2026-07-11 四次修正(页分配器 Segment 路径):将 FRAMEBUFFER 从 4MB .bss 静态改为页分配器 FrameAllocOptions::alloc_segment 分配(落在 Usable 内存区,PA 0x60c00000),与 GpuDevice::init 用同一类内存。probe 完整跑通:SET_SCANOUT resp=0x1100display ready: 1280x800readback VA[0]=0xff00ff00但 QEMU xp /xg 0x60c00000 仍返回 0——即使 Usable 区的页分配器内存,内核 PT 下的 store 也未到达 QEMU RAM。对比:meta::init 在 boot PT 期间向 0xffff800048300000(同区)写入 0xaa 成功(readback OK),而 probe 在 kernel PT 期间向 0xffff800060c00000 写入失败。结论收敛:根因是 kernel page table(init_kernel_page_tablecursor.map 构建)的线性映射,在 kernel PT 下 store 指令不到达 QEMU 物理 RAM,而 boot PT 下的 store 正常。 这不是内存区域问题(Usable 区同样失效),而是 kernel PT 本身的线性映射 PTE 问题。该路径用 FrameAllocOptions::alloc_segment(debug 构建触发 frame allocator 的 debug_assert,需 release 构建绕过,但 WSL CJK 路径权限阻塞了 release 构建)。深层修复需调试 ostd/src/mm/page_table/cursor/map 逻辑为何在 TCG 下产出不可见的 store。

2026-07-11 ✅ 修复完成(固定 PA 0x60000000):通过在 activate_kernel_page_table 后向固定 PA 0x60000000(region 7 Usable 区)写入标记并用 QEMU xp 验证,发现该 PA 的 store 能到达 QEMU RAMxp 读到 0xdeadbeefcafebabe)——即 kernel PT 线性映射对某些 PA 工作正常,对 4MB .bss 与页分配器 segment 的 PA 不正常。根因最终定性:.bss 大静态与 page-allocator segment 的 PA 在 kernel PT 下的映射有缺陷,但固定 PA 区间(0x60000000 起)的线性映射正常。

修复:将 FRAMEBUFFER 从 .bss/segment 改为固定 PA 0x60000000(region 7,经 LINEAR_BASE + 0x60000000 映射),并缩小 draw_test_pattern(4MB volatile 写在 TCG 下太慢,会阻塞 flush)。验证证据:

  • QEMU xp /xg 0x600000000xff00ff00ff00ff00(绿色像素,DMA 可见)
  • virtio-gpu trace:res_xfer_toh_2d + res_flush 均执行
  • screendump:778002/1024000 非黑像素(76%),首像素 (0,255,0) 绿色 + (255,119,0) 橙色
  • 串口:display ready: 1280x800 scanout was 1280x800readback VA[0]=0xff00ff00

kei virtio-gpu scanout 端到端像素输出验证通过。 提交:kei dev(fixed-PA FRAMEBUFFER + 精简 draw_test_pattern)。

kei 内核完整启动 + 用户空间进程(2026-07-04)🎉

重大里程碑:kei 内核在 QEMU arm64 上完整启动并成功加载用户空间 ELF 进程。

通过 Docker QEMU 镜像(qemu-system-aarch64)在 QEMU virt(cortex-a72, GICv3, 2GB)上验证:

[kei] FDT parsed → DEVICE_TREE initialized
[ostd] frame::meta::init: max_paddr=0xC0000000 (正确的 3GB)
[ostd] init: DONE — GIC, timer, SMP, page tables, IRQ 全部通过
[kernel] 组件初始化: arch, thread, driver, net, sched, process, fs, security
[kernel] initramfs.cpio.gz 解包 → rootfs ready
[kernel] spawn_init_process: 用户空间 ELF 加载成功(init=/init)

修复的问题

  1. FDT 内存区域溢出:链接脚本 KERNEL_VMAkernel_loaded_offset() 不匹配。重装 cargo-osdk 后链接脚本使用正确的 0xffff800040080000(线性映射基址),全量重编译后修复。max_paddr0x7fff40080000(128TB)降至正确的 0xC0000000(3GB)。
  2. vbe_dispi x86 模块kernel/src/lib.rsmod vbe_dispi 未门控,添加 #[cfg(target_arch = "x86_64")]
  3. initramfs 架构错误initramfs.py 使用宿主机 x86-64 busybox。添加 find_busybox(arch) 函数,支持按架构选择 busybox。

evernight 联调(2026-07-04)

与 aris + evernight 进行宿主机联调测试,验证 IoT 网关数据链路:

Modbus TCP sim → evernight sensor-poll → WebSocket → evernight-server
  • evernight 二进制构建成功,device.register + device.telemetry 双向验证通过
  • aris ignition_test.py 修复:SENSOR_DATA_DIR 注入 + Modbus TCP sim 帧解析

多架构构建验证(2026-07-04)

全部 4 种架构编译成功,产出有效 ELF 内核二进制:

架构 OSDK Scheme 状态 产物
aarch64 aarch64 ✅ 完整启动 + 用户空间 ELF 64-bit ARM aarch64 (7MB)
x86_64 microvm ✅ 编译通过 ELF 64-bit x86-64 (需 vDSO)
riscv64 riscv ✅ 编译通过 ELF 64-bit RISC-V (需 vDSO)
loongarch64 loongarch ✅ 编译通过 ELF 64-bit LoongArch

x86_64/riscv64 需要 VDSO_LIBRARY_DIR 环境变量指向预构建的 vDSO .so 文件。 aarch64/loongarch64 不需要 vDSO(vdso 模块仅 x86_64/riscv64 启用)。

evernight aarch64 交叉编译(2026-07-04)

  • evernight 交叉编译成功:aarch64-unknown-linux-musl,12MB 静态链接 ELF
  • 使用 musl.cc 交叉工具链 + .cargo/config.toml linker 配置
  • 修复 AppContext feature 门控 bug(capture/signaling 字段未正确 cfg-gated)
  • 功能集:hardware,protocol,serial,sensor,s7comm,bin,api,vault,manifest,tunnel,remote-ssh

virtio-gpu 2D 显示驱动(2026-07-06)

新增 kei 的第一个图形显示路径:virtio-gpu 2D scanout 驱动,让内核能在 QEMU 窗口显示像素。

  • kernel/comps/virtio/src/device/gpu/:全新 virtio-gpu 驱动(mod.rs spec 类型 + device.rs 驱动主体),实现 OASIS virtio-gpu 2D 协议
  • kernel/comps/framebuffer/src/framebuffer.rs:重构 framebuffer 子系统支持 late-init + blit 后端(FrameBufferBackend::Blit),让设备探测时(晚于 boot)能 publish framebuffer
  • 探测链路:GET_DISPLAY_INFORESOURCE_CREATE_2DRESOURCE_ATTACH_BACKING(绑定客户机 DMA 缓冲区)→ SET_SCANOUTpublish() blit-backed FrameBuffer
  • 内核 printk 经 FramebufferConsole 自动渲染到 QEMU 窗口
  • QEMU 参数更新:OSDK.toml aarch64 scheme 加 -device virtio-gpu-device,显示后端由 $QEMU_DISPLAY 控制(默认 sdl,CI 用 none)
  • cargo osdk check(x86_64)编译通过,仅剩预存的 inode/set_tls 错误

已知限制

  1. /dev/fb0 mmap 对 blit 后端返回 ENODEV(用户态暂走 read/write ioctl)
  2. poll_response 运行时 flush 路径有竞态(probe 阶段串行不受影响),已在代码注释记录
  3. aarch64 cargo osdk build 受阻于 cargo-osdk 0.18.0 的 base crate 隔离机制:base crate 用 ostd = "0.18.0"(version)声明依赖,虽然 [patch.crates-io] 重定向到本地 ostd 源码,但依赖图仍用 crates.io 版本的 metadata(不含 kei fork 的 aarch64 target 依赖如 fdt/unwinding)。CJK 路径(/mnt/d/源代码/...)上 cargo-osdk 的 get_cargo_metadata spawn 会 panic。临时绕过:bind-mount 到 ASCII 路径(/opt/kei),但 fdt/unwinding 依赖解析仍需修复(可能需要给 base crate 注入 target-specific deps 或 patch cargo-osdk)

设备树(FDT)验证(2026-07-04)

QEMU virt FDT 包含标准 Linux 绑定的网络设备节点:

virtio_mmio@a000000 {
    dma-coherent;
    interrupts = <0x00 0x10 0x01>;    ← GIC SPI #16
    reg = <0x00 0xa000000 0x00 0x200>; ← MMIO 512 bytes
    compatible = "virtio,mmio";        ← 标准 Linux 绑定
};
  • 16 个 virtio_mmio 插槽(0xa000000 – 0xa001e00),每个 512 字节
  • GICv3 3-cell 中断格式,interrupt-parent 指向 /intc
  • kei aarch64.rs::probe_for_device() 完整解析 compatible/reg/interrupts
  • 完全兼容 Linux 设备树(使用标准 DTB 绑定,非自定义格式)

kei 内核用户空间 I/O 打通(2026-07-04)🎉🎉🎉

kei 内核在 aarch64 QEMU 中实现了完整的用户空间 I/O。

裸金属 aarch64 init 程序通过 write(1, msg, 24) syscall 成功在串口输出:

=== kei ignition ===

根因与修复

  • dyn PerOpenFileOps trait object 的 vtable 在 aarch64(nightly-2026-04-03)上无法正确 dispatch FileOps::write_atTtyFile::write_at
  • 修复:sys_write() 在 aarch64 上拦截 fd 1/2(stdout/stderr),直接通过 pl011_send_byte() 写 PL011 UART,绕过 vtable dispatch

完整验证链路

  1. PL011 UART 控制台注册(替换 TODO stub)→ aster_console 发现 "Uart-Console" ✅
  2. 串口 Tty 设备创建 → /dev/ttyS0 在 RamFs 注册 ✅
  3. init 进程 fd 0/1/2 连接到 /dev/ttyS0
  4. 用户空间 write(1, buf, 24) syscall → PL011 MMIO → 串口输出 ✅

** celestia-devtools 集成**:

  • aris 和 kei 导入 celestia-devtools.just
  • 共享 recipes:cache-guard、fmt-markdown、prefetch、cross-check
  • 宿主机 QEMU/dtc/交叉编译器安装自动化(setup_env.py
  • tests/e2e_qemu_ignition.sh(177 行):QEMU arm64 中 kei 内核启动 → evernight sensor-poll → gateway 全链路测试脚本
  • evernight-server 作为 mock entelecheia gateway(8443 端口)
  • QEMU user-mode NAT 网络(guest 10.0.2.15 ↔ host 10.0.2.2)
  • evernight aarch64 二进制嵌入 initramfs(6.2MB cpio.gz)

既往提交

  • fix: gate vbe_dispi module to x86_64 only (aarch64 build fix)
  • feat: fix build/test pipeline + verify aarch64 QEMU boot
  • milestone: kei Asterinas kernel FULLY BOOTS on aarch64 QEMU

5. 后续计划

短期

  1. 用户空间串口输出——init 进程已加载但 stdout 未连接到串口 ✅ 已修复(open_initial_console 将 /dev/console 分配为 fd 0/1/2)
  2. busybox ELF TLS 加载——busybox 的 TLS 段触发 copy_from_slice::len_mismatch_fail(FileSiz=0x40 vs 分配 buffer),需修复 ELF 加载器 TLS 处理
  3. evernight aarch64 交叉编译——构建 aarch64-unknown-linux-musl evernight 二进制 ✅ 已完成
  4. kei + evernight 联调——QEMU 中 kei 内核启动 → evernight 连接 gateway ✅ 测试脚本已就绪

中期

  1. M2 ARM64 Hardening:审计 ostd/src/arch/aarch64/,替换第三方 GICv3 crate
  2. M2 SMP/PSCI 多核启动
  3. M3 RK3566 BSP 驱动(GPIO / stmmac / DW UART)

长期

  1. M2.4 在 NanoPi R3S 上运行 kei + evernight 全栈
  2. 性能基准测试 vs Linux baseline

6. 桌面系统支持路线图(2026-07-10 制定)

6.1 kei 的职责

kei 作为纯内核,在桌面系统中负责:

  • syscall ABI:Linux 兼容系统调用(已有 ~240 个实现)
  • /dev/fb0 fbdev 设备:用户态通过 mmap 直接写帧缓冲像素
  • virtio-gpu 2D scanout:QEMU SDL 窗口显示
  • 帧缓冲控制台:内核态 ANSI 彩色 + Sixel 内联图像(已实现)

aris 作为系统中间件层,负责渲染引擎(Blitz + Vello CPU)、JS 引擎(Boa)、WASM 运行时(Wasmtime)、Linux ABI 兼容层。kei 不涉及渲染引擎和 ABI 兼容层。

6.2 kei 侧需要补全的功能

为了让 aris 的渲染管线能在 kei 上运行,kei 需要以下改动:

P0:/dev/fb0 mmap 支持(阶段 2,~3-5 天)

当前 /dev/fb0 对 Blit 后端(virtio-gpu DMA buffer)返回 ENODEV。需要实现:

  • mmap 系统调用对 /dev/fb0 文件描述符的支持
  • 将 virtio-gpu 的 FRAMEBUFFER 静态数组映射到用户态地址空间
  • 用户态写入后通过 MS_SYNC msync 或自动 flush 触发 TRANSFER_TO_HOST_2D + RESOURCE_FLUSH
  • 文件位置:kernel/src/device/fb.rs(修改 mmap handler)+ kernel/comps/virtio/src/aarch64_raw_gpu_probe.rs(暴露 DMA buffer 的物理地址)

这是让 Blitz 的 Vello CPU 像素 buffer 能显示在 QEMU SDL 窗口上的关键依赖。

P1:缺失 syscall 补全(阶段 2,与 P0 并行)

syscall 用途 复杂度
SYSV shm (shmget/shmat/shmdt/shmctl) 部分多媒体/音频库
posix_spawn 进程创建(musl 会 fallback)
prctl(PR_SET_VMA) 内存命名
扩展 ioctl(终端/PTY) shell 支持

kei 已有的核心 syscall 覆盖足够运行 Servo/Blitz + Boa + Wasmtime:mmap/munmap/mprotect/mremap ✅、clone3+完整线程 ✅、futex 全操作 ✅、epoll 全家族 ✅、pipe2/socketpair ✅、TCP/UDP/Unix socket ✅、memfd_create ✅、getrandom ✅、/dev/shm POSIX shm ✅。

P2:DRM ioctl 框架(远期,按需)

如果需要 GPU 加速或窗口管理(Wayland compositor),需要实现:

  • /dev/dri/card0 + /dev/dri/renderD128 设备节点
  • DRM ioctl 处理(DRM_IOCTL_MODE_*, DRM_IOCTL_GEM_*
  • virtio-gpu 3D 支持(VIRTIO_GPU_CAPSET_*)

阶段 1-5 不需要 DRM——Vello CPU 纯软件渲染 + /dev/fb0 足以显示网页。

6.3 数据流(kei 视角)

用户态(aris render 包):
  Vello CPU render_to_buffer(&mut [u8] RGBA)
    → mmap /dev/fb0(kei 映射 virtio-gpu DMA buffer)
    → memcpy RGBA buffer 到 mmap 区域
    → msync 或写 ioctl FBIO_WAITFORVSYNC 触发 flush

内核态(kei):
  /dev/fb0 mmap handler
    → 返回 FRAMEBUFFER 物理页的 user-accessible 映射
  msync / ioctl handler
    → 调用 flush_framebuffer()
    → virtio-gpu TRANSFER_TO_HOST_2D + RESOURCE_FLUSH
    → QEMU SDL 窗口更新

6.4 里程碑对齐

阶段 kei 工作项 aris 工作项 交付物
阶段 1 aris Linux + WebKitGTK kiosk 验证 QEMU 中网页截图
阶段 2 /dev/fb0 mmap + syscall 补全 kei 上用户态写 fb0 → SDL 显示
阶段 3 Blitz + Vello CPU 集成 → fb0 aris Linux 上 Blitz 渲染 HTML
阶段 4 Boa + Wasmtime + WIT host kei 上 tairitsu 组件渲染
阶段 5 evernight 迁移 + 镜像组装 可部署 sdcard.img
阶段 6 DRM 框架(按需) ABI 完整兼容层 任意 Linux 二进制可运行

kei — Project Plan

Goal

Maintain a production-ready Rust OS kernel for ARM64 embedded devices derived from Asterinas (星绽), with Board Support Packages and multi-architecture QEMU testing.

Upstream Relationship

KEI is derived from Asterinas(星绽). Upstream changes are absorbed periodically through directory-level vendoring (just vendor), not git merge. ARM64 arch code (ostd/src/arch/aarch64/, kernel/src/arch/aarch64/), BSP, board configs, and docs are independently maintained. See upstream-sync guide.

Vendoring frequency: every 3–6 months, or on critical fixes.

Milestones

M1 — Core Boot ✅

  • QEMU aarch64 boot → user-space init (2026-07-04)
  • virtio-gpu 2D scanout with pixel output (2026-07-11)
  • Multi-architecture build (aarch64, x86_64, riscv64, loongarch64)
  • kei + evernight E2E ignition test

M2 — ARM64 Hardening

  • FDT memory region parsing fix
  • Audit ostd/src/arch/aarch64/
  • SMP multi-core boot (PSCI)
  • Real hardware boot on NanoPi R3S

M3 — RK3566 BSP

  • GPIO / Dual Ethernet / UART / SPI / I2C / Watchdog / SD

M4 — Multi-Arch Expansion

  • RISC-V: JH7110 BSP
  • x86_64: Intel N100 BSP

Risk Assessment

Risk Impact Mitigation
Upstream API breaks at vendor time Medium Compile test + fix cycle
ARM64 code bugs on real hardware High Hardware testing milestone
Falling behind upstream features Low Periodic vendoring