本文件于 2026-07-15 更新,记录项目当前状态、近期进展与后续计划。
- 渲染链路切换:kei 转型期只做 vtty 不做 GUI。
just build browser(别名just build vtty)现在交叉编译 aris-render 的kei_tty(--no-default-features --features png,静态 musl ELF),取代原来的kei_desktopGUI 链路;just render/wslq-run/wslq-initramfs默认 initramfs 改为initramfs_kei_tty.cpio.gz(initramfs_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。 arisfix/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 端到端启动验证留待集成后进行。
- aarch64 SMP 支持实现:从 stub 到完整的多核启动:
packages/ostd/src/arch/aarch64/boot/smp.rs:count_processors()从 FDT/cpus节点统计 CPU 数量;bringup_all_aps()通过 PSCICPU_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 计数器,跳转到 Rustaarch64_ap_early_entry。packages/ostd/src/arch/aarch64/irq/chip/mod.rs:init_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}即可测试。
- 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:定义TlsLayouttrait(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 初始化逻辑。
- 新增
- riscv64 内核启动修复:
kernel/src/init.rs:添加ostd::early_println!()诊断标记(ostd::info!()因core::unicode::conversionsdiv-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::conversionsdiv-by-zero panic → kernel trap。
- x86_64 启动修复:
OSDK.tomlmicrovm 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()patche_machine也无效)。
- 新增
packages/webui/:kei 浏览器端仪表盘,tairitsu + hikari 技术栈。Cargo.toml:独立 crate(非 kei workspace 成员),依赖 tairitsu-vdom/hooks/macros/web + hikari-palette/components/icons,targetwasm32-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.tomlaarch64 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),需重建验证。
- aarch64:✅ 完整启动 → initramfs 解包 → dropbear 监听 port 22 →
- 待办:重建 initramfs(含 dropbear host key fix)→ 验证 SSH banner。
- 修复: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.sh中test/initramfs/→tests/initramfs/路径 typo。
- jh7110 skeleton guard:
packages/bsp/jh7110/src/lib.rs的compile_error!替换为#[deprecated]no-opinit()。 - 已提交:commit
416b136。
- 当前分支:
dev· 领先origin/dev1 commit(vtable 修复)· 工作区仅剩 kei-echo agent 的packages/bsp/jh7110/src/lib.rs - 最近提交:
🔧 Fix PerOpenFileOps vtable dispatch on aarch64.(99e7d95) - 已修复并验证:
PerOpenFileOpsvtable dispatch(commit99e7d95):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 PerOpenFileOpsvtable 调用(supertrait 继承);(2)as_any()改为PerOpenFileOps必选方法,每个 implementor 显式写self(按具体类型生成 vtable 条目,无 trait upcast 参与)。19 个 implementor +inode_handle.rs同步。IoMem::base()算术溢出(同 commit99e7d95):线性映射在 high kernel half 的kva.start() + self.offset在 aarch64 触发attempt to add with overflow。base()/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。
- 遗留疑问:
dropbear SSH banner 缺失✅ 已修复(commit416b136):build script + init script 两级 host key 生成。需重建 initramfs 后验证 SSH banner。- 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不变。 O_APPEND+open_file交互:仍为预存 FIXME(read()/write_at()中有标记),与本次 vtable 修复无关,且涉及并发语义,需独立设计。packages/bsp/jh7110/src/lib.rs:kei-echo agent 的compile_error!→#[deprecated]no-opinit()已提交(commit416b136)。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)仍待修。
- 后续动作:
验证网关模式✅ aarch64 启动链路通验证 vtable 修复✅ 全部 I/O syscall + dropbear listen- 下一步:(a) 修复 dropbear host key 让 SSH 端到端通;(b) 视 kei-echo 决定是否合入 jh7110 修改;(c) 跨仓
[patch]收敛到~/.cargo/config.toml(aster 派生链共用)。
- 跨仓依赖:vtty 协议与
kou对接;浏览器 UI 复用aris;内核 fork 自 aster(见顶层patches/长期方案)。
- 当前分支:
dev· 领先origin/dev0 commits · 工作区干净 - 最近提交:
🔧 Gateway mode: aris vtty + WS JSON-RPC server.(0f42289) - 未提交改动:无
- 后续动作:
- 验证网关模式:aris vtty + WS JSON-RPC 在工业 IoT 边缘硬件(aarch64)上端到端联通。
- 固化
kouvtty 协议到 kei 的 init shell,作为终端接入面。 - 跨仓
[patch]收敛到~/.cargo/config.toml(aster 派生链共用)。
- 跨仓依赖:vtty 协议与
kou对接;浏览器 UI 复用aris;内核 fork 自 aster(见顶层patches/长期方案)。
之前的"桌面 UI"路线(aris-render 预渲染桌面 → /dev/fb0 → QEMU SDL)存在根本性问题:
- Vello CPU 光栅化质量无法接受:软件光栅化的文字在所有分辨率下都偏糊,非 GPU 硬件渲染瓶颈
- QEMU TCG 性能限制:fb 写入极慢(~0.5ms/byte),实时交互不可行
- 复杂度与价值不匹配:桌面 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 显示 | |
| 主 poll 循环 | ✅ 多路复用 mouse_fd + ws_listen + ws_clients |
| IoMem 线性映射修复 | ✅ aarch64 virtio-mmio 设备探测和写入可用 |
- vtty 文字渲染:
render_html_with_font可渲染 CSS 颜色/背景,但文字节点无输出。render_html(catch_unwind 版本)触发 fontique panic 后降级到 fill_fallback 像素画。根因:(a) 24MB 全字体过大导致 parley::fontique 注册失败,(b) 86KB 子集字体注册成功但 paint_scene 不渲染文字节点。 - riscv64 内核:
core::unicode::conversions除零 panic(rustc 在 riscv64imac-unknown-none-elf 上的已知 bug) - x86_64 内核:64-bit multiboot1 ELF 无法用 QEMU -kernel 加载
- vtty 文字渲染修复:调查
render_htmlvsrender_html_with_font文字渲染差异。可能从 Blitz DOM 切换到更简单的渲染方式,或使用预渲染文字位图。 - webui 集成:kei.celestia.world 托管 webui 前端页面,通过 WS JSON-RPC 连接 kei 网关。页面加载后自动握手。
- HMI 远期:aris 嵌入 webui,通过 WebRTC 推流 aris-render 输出到浏览器。HMI 由 webui 控制打开。
- riscv64 + x86_64:kernel 侧 bug 需工具链/内核修复,短期无法解决。先聚焦 aarch64。
在 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) =
#21252Bcard 背景色
关键修复:
- 移除 tracing-subscriber(导致新 musl 二进制在 kei 上卡在初始化)
- Row-by-row fb write(每次 2560 字节,避免大 write 卡住 fb write_at)
- TLB flush 修复 mmap store-invisibility(所有 mmap 大小 0% corruption)
- 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:
-
fb write EL1 page fault(
kernel/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写入。 -
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 命令队列溢出。fbwrite_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 启动器 + screendumpscripts/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
已知限制:
-
用户态 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=0x0或far=0x10)。一致的损坏模式x21=0x7840407878404078(ASCIIx@@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 内部。 -
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 崩溃。 -
x86_64 编译有 9 个 acpi crate 错误(E0432/E0433/E0277):
acpi::madt/AcpiHandler等 API 在 acpi 6.1.1 变更,kei fork 未适配。预先存在的 regression,非本次引入。 -
WSL2 仅装了 qemu-system-arm(aarch64),x86_64/riscv64 的 system emulator 需
apt install qemu-system-x86 qemu-system-misc(需 sudo 密码)。Windows QEMU 有全部架构。
| 架构 | 编译 | 启动 | 用户空间 | 显示 | 备注 |
|---|---|---|---|---|---|
| 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) | -kernel 加载 |
— | — | 需要 GRUB ISO loader(无 sudo 无法安装 grub-mkrescue) |
2026-07-13 多架构验证里程碑:
-
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 = 壁纸顶色
-
riscv64 启动到组件阶段:内核在 QEMU virt + OpenSBI v1.5.1 下从 S-mode 启动,完整通过 ostd 初始化(frame allocator、kernel page table、SMP),到达 component bootstrap 后 trap。距 spawn_init_process 仅一步。
-
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)。
| 架构 | 编译 | 启动 | 显示 | 备注 |
|---|---|---|---|---|
| aarch64 | ✅ | ✅ 完整启动 + 用户空间 | ✅ aris-render 像素上屏 (70.6%) | WSL2 QEMU 验证,主开发架构 |
| riscv64 | — | — | inode cfg fix 后内核代码编译通过;vDSO 需交叉编译 | |
| x86_64 | ❌ 9 个 acpi crate 错误 | — | — | 预存 regression:acpi 6.1.1 API 变更未适配 |
修复的 riscv64 编译 bug(kernel/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 无交互逻辑,预期行为)
修正了长期被误判为「QEMU TCG used-ring bug」的黑屏根因。
通过捕获 QEMU 串口日志 + virtio-gpu trace(-d trace:virtio_gpu_cmd_*)发现真正的故障链:
aarch64_raw_gpu_probe::probe()先通过裸 MMIO 成功初始化 GPU:GET_DISPLAY_INFO resp=0x1101、RESOURCE_CREATE_2D resp=0x1100、ATTACH_BACKING resp=0x1100(fb_pa=0x40eb7000)、SET_SCANOUT resp=0x1100,scanout 绑定到 resource 0x1 @ 1280×800。- 随后
virtio::init()的 transport 循环(lib.rs:84)再次发现同一设备,执行write_device_status(DeviceStatus::empty())(lib.rs:89-91)——这会复位 QEMU virtio-gpu 的内部状态,清空 resource + scanout 绑定。 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) 用内核页分配器(DmaCoherent,GpuDevice::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=0x1100、display ready: 1280x800、readback 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_table 经 cursor.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 RAM(xp 读到 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 0x60000000→0xff00ff00ff00ff00(绿色像素,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 1280x800、readback VA[0]=0xff00ff00
kei virtio-gpu scanout 端到端像素输出验证通过。 提交:kei dev(fixed-PA FRAMEBUFFER + 精简 draw_test_pattern)。
重大里程碑: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)
修复的问题:
- FDT 内存区域溢出:链接脚本
KERNEL_VMA与kernel_loaded_offset()不匹配。重装 cargo-osdk 后链接脚本使用正确的0xffff800040080000(线性映射基址),全量重编译后修复。max_paddr从0x7fff40080000(128TB)降至正确的0xC0000000(3GB)。 - vbe_dispi x86 模块:
kernel/src/lib.rs中mod vbe_dispi未门控,添加#[cfg(target_arch = "x86_64")]。 - initramfs 架构错误:
initramfs.py使用宿主机 x86-64 busybox。添加find_busybox(arch)函数,支持按架构选择 busybox。
与 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 帧解析
全部 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-unknown-linux-musl,12MB 静态链接 ELF - 使用 musl.cc 交叉工具链 +
.cargo/config.tomllinker 配置 - 修复 AppContext feature 门控 bug(
capture/signaling字段未正确 cfg-gated) - 功能集:
hardware,protocol,serial,sensor,s7comm,bin,api,vault,manifest,tunnel,remote-ssh
新增 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_INFO→RESOURCE_CREATE_2D→RESOURCE_ATTACH_BACKING(绑定客户机 DMA 缓冲区)→SET_SCANOUT→publish()blit-backedFrameBuffer - 内核 printk 经
FramebufferConsole自动渲染到 QEMU 窗口 - QEMU 参数更新:
OSDK.tomlaarch64 scheme 加-device virtio-gpu-device,显示后端由$QEMU_DISPLAY控制(默认 sdl,CI 用 none) cargo osdk check(x86_64)编译通过,仅剩预存的 inode/set_tls 错误
已知限制:
/dev/fb0mmap 对 blit 后端返回 ENODEV(用户态暂走 read/write ioctl)poll_response运行时 flush 路径有竞态(probe 阶段串行不受影响),已在代码注释记录- 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_metadataspawn 会 panic。临时绕过:bind-mount 到 ASCII 路径(/opt/kei),但 fdt/unwinding 依赖解析仍需修复(可能需要给 base crate 注入 target-specific deps 或 patch cargo-osdk)
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 内核在 aarch64 QEMU 中实现了完整的用户空间 I/O。
裸金属 aarch64 init 程序通过 write(1, msg, 24) syscall 成功在串口输出:
=== kei ignition ===
根因与修复:
dyn PerOpenFileOpstrait object 的 vtable 在 aarch64(nightly-2026-04-03)上无法正确 dispatchFileOps::write_at到TtyFile::write_at- 修复:
sys_write()在 aarch64 上拦截 fd 1/2(stdout/stderr),直接通过pl011_send_byte()写 PL011 UART,绕过 vtable dispatch
完整验证链路:
- PL011 UART 控制台注册(替换 TODO stub)→
aster_console发现 "Uart-Console" ✅ - 串口 Tty 设备创建 →
/dev/ttyS0在 RamFs 注册 ✅ - init 进程 fd 0/1/2 连接到
/dev/ttyS0✅ - 用户空间
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
用户空间串口输出——init 进程已加载但 stdout 未连接到串口✅ 已修复(open_initial_console将 /dev/console 分配为 fd 0/1/2)- busybox ELF TLS 加载——busybox 的 TLS 段触发
copy_from_slice::len_mismatch_fail(FileSiz=0x40 vs 分配 buffer),需修复 ELF 加载器 TLS 处理 evernight aarch64 交叉编译——构建✅ 已完成aarch64-unknown-linux-muslevernight 二进制kei + evernight 联调——QEMU 中 kei 内核启动 → evernight 连接 gateway✅ 测试脚本已就绪
- M2 ARM64 Hardening:审计 ostd/src/arch/aarch64/,替换第三方 GICv3 crate
- M2 SMP/PSCI 多核启动
- M3 RK3566 BSP 驱动(GPIO / stmmac / DW UART)
- M2.4 在 NanoPi R3S 上运行 kei + evernight 全栈
- 性能基准测试 vs Linux baseline
kei 作为纯内核,在桌面系统中负责:
- syscall ABI:Linux 兼容系统调用(已有 ~240 个实现)
/dev/fb0fbdev 设备:用户态通过 mmap 直接写帧缓冲像素- virtio-gpu 2D scanout:QEMU SDL 窗口显示
- 帧缓冲控制台:内核态 ANSI 彩色 + Sixel 内联图像(已实现)
aris 作为系统中间件层,负责渲染引擎(Blitz + Vello CPU)、JS 引擎(Boa)、WASM 运行时(Wasmtime)、Linux ABI 兼容层。kei 不涉及渲染引擎和 ABI 兼容层。
为了让 aris 的渲染管线能在 kei 上运行,kei 需要以下改动:
当前 /dev/fb0 对 Blit 后端(virtio-gpu DMA buffer)返回 ENODEV。需要实现:
mmap系统调用对/dev/fb0文件描述符的支持- 将 virtio-gpu 的
FRAMEBUFFER静态数组映射到用户态地址空间 - 用户态写入后通过
MS_SYNCmsync 或自动 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 窗口上的关键依赖。
| 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 ✅。
如果需要 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 足以显示网页。
用户态(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 窗口更新
| 阶段 | 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 二进制可运行 |
Maintain a production-ready Rust OS kernel for ARM64 embedded devices derived from Asterinas (星绽), with Board Support Packages and multi-architecture QEMU testing.
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.
- 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
- FDT memory region parsing fix
- Audit ostd/src/arch/aarch64/
- SMP multi-core boot (PSCI)
- Real hardware boot on NanoPi R3S
- GPIO / Dual Ethernet / UART / SPI / I2C / Watchdog / SD
- RISC-V: JH7110 BSP
- x86_64: Intel N100 BSP
| 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 |