2026-07-31 13:53:49 +08:00
|
|
|
|
# Deshab Bug 记录
|
|
|
|
|
|
|
|
|
|
|
|
> 所有测试与开发过程中发现的 bug 统一登记于此。每个 bug 按 BUG-YYYYMMDD-NNN 编号。
|
|
|
|
|
|
> 测试用例文档位于 RE/test-cases/。
|
|
|
|
|
|
>
|
|
|
|
|
|
> 2026-07-29 文档治理:此前 8 条遗留纯文本 bug 已按模板补全(编号 001–008,
|
|
|
|
|
|
> 日期为桌面测试期的近似日期);同时补登 B5/B6 及 BSS NOBITS、go_up 条目。
|
|
|
|
|
|
|
|
|
|
|
|
## 严重程度定义
|
|
|
|
|
|
|
|
|
|
|
|
- P0 阻断: 影响主链路启动或核心功能完全不可用(必须立即修复)
|
|
|
|
|
|
- P1 严重: 功能可降级但关键路径受损(本轮内修复)
|
|
|
|
|
|
- P2 一般: 非关键路径异常或体验问题(下一里程碑前修复)
|
|
|
|
|
|
- P3 提示: 日志/小问题,不影响功能(记录备查)
|
|
|
|
|
|
|
|
|
|
|
|
## Bug 条目格式
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
### BUG-YYYYMMDD-NNN [P级] [模块] 简述
|
|
|
|
|
|
- 现象:
|
|
|
|
|
|
- 复现步骤:
|
|
|
|
|
|
- 串口/日志证据:
|
|
|
|
|
|
- 根因分析:
|
|
|
|
|
|
- 修复方案:
|
|
|
|
|
|
- 状态: [OPEN/FIXING/FIXED/CLOSED]
|
|
|
|
|
|
- 修复提交: <commit hash 或 "待提交">
|
|
|
|
|
|
- 验证: <验证方法与结果>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Bug 列表
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 在此追加 bug 条目,最新放在顶部 -->
|
|
|
|
|
|
|
2026-08-04 18:08:08 +08:00
|
|
|
|
### BUG-20260803-009 [P3] [DKM/apic] PIT mode3 方波在 IOAPIC edge 触发下每周期双投递:100Hz 设定实测 200Hz(tick 2x 定论)
|
|
|
|
|
|
- 现象: apic_route=1 接管验证时,500ms 窗口数到 ~100 ticks(PIT ch0 mode3 设定 100Hz,预期 50);tick handler 计数恰为 2 倍,且持续投递窗口(sustain)同样双倍。
|
|
|
|
|
|
- 复现步骤: FUCK [drivers] apic_route=1 启动 → ROUTE VERIFY 阶段计数复现;apic_diag=1 时 HPET 对拍实验自动输出定论。
|
|
|
|
|
|
- 串口/日志证据: `.build_tmp/tests/apicroute-b7p2-071006.log`:`calib window(us)=10132` / `verify window(us)=504883` / `tick rate(Hz x10)=2000` / `route verify ticks=101` / `sustain window ticks=100` / `TICK2X VERDICT: PIT mode3 double-clocked on IOAPIC edge (~200Hz real)`。
|
|
|
|
|
|
- 根因分析: HPET 绝对时基(ACPI HPET 表 → MMIO 主计数器,QEMU 100MHz)对拍逐一排除候选假设:① "TSC 校准测半"——calib 窗口实测 10132us ≈ 10.13ms,准确,排除;② "验证窗口偏长"——实测 504883us ≈ 504.9ms,准确,排除。窗口与校时皆正确而计数双倍,定论为 PIT mode3(方波发生器)OUT 引脚每个全周期含上升沿+下降沿各一次翻转,QEMU IOAPIC edge 触发重定向项的输入采样等效双沿触发 → 每 PIT 周期产生 2 次中断,真实投递频率 ~200Hz。与 LESSONS_LEARNED 2026-08-03 B7 阶段1 记录的 "PIT mode3 计数器每 CLK 减 2"(同一硬件特性:mode3 半周期翻转)互证。
|
|
|
|
|
|
- 修复方案: 无需修复(观测性定论,非功能缺陷;EOI 钩子链路与窗口校时均验证正确)。后续约束:① route 模式下凡按 PIT 中断次数计时的代码须按 200Hz 折算,或改用 PIT mode2(rate generator,每周期单脉冲)根除双触发;② 时延派生一律走 HPET/TSC 绝对时基,禁止用 tick 计数当时间源;③ apic_diag 开关保留(FUCK 默认 0),真机冒烟时可复开对拍。
|
|
|
|
|
|
- 状态: [CLOSED]
|
|
|
|
|
|
- 修复提交: 工作区(CODE/DKM/apic/apic.c:HPET 表解析 + 主计数器时基 + TICK2X VERDICT 对拍实验)
|
|
|
|
|
|
- 验证: apic-route-verify.ps1 18 项全 PASS(route=1+legacy=1+diag=1);boot-regression.ps1 B1-B5 全 PASS(route=1+legacy=1+diag=0,B1 向导按键全程走 IOAPIC→LAPIC→IDT→ps2kbd 链路);route=0 回归 B1+B2 PASS(PIC 锚点在、钩子未注册、行为与旧版一致)。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260801-008 [P1] [tools/desktop_app.h] da_mouse_init 读配置字前未冲刷输出缓冲:残留字节写回控制器配置 → KBD 时钟禁用位被置位 → 键盘控制器级全灭且跨应用持续
|
|
|
|
|
|
- 现象: dev_mode shell 中 `run FILEMAN.ELF`(或 BROWSER.ELF)后应用内键盘全灭:Esc/方向键/回车均无响应;鼠标移动/点击正常。退出应用返回 shell 后键盘仍不恢复(会话级持续,直至重启)。editor(不调用 da_mouse_init)与启动初期 shell 键盘正常。
|
|
|
|
|
|
- 复现步骤: dev_mode shell → 键入 `run FILEMAN.ELF` 回车 → fileman 内按 Esc/方向键 → 无响应、串口零输出。
|
|
|
|
|
|
- 串口/日志证据: `.build_tmp/w3b_s2_tools.log`:`[fileman] boot` 后 monitor sendkey esc/down/ret 串口零增量、screendump 选区不动;mouse_move 光标正常移动、mouse_button 点击可选中条目(FIRSTINT.XT 高亮)并可点关闭按钮退出(`[fileman] close button clicked` → `[shell] run: tool returned`);退回 shell 后 sendkey i/d/ret 仍零输出(键盘未恢复)。运行中 fileman.elf 反汇编证实 da_mouse_poll 与键盘轮询指令顺序均正确(`test al,0x21` 后才 `in 0x60`),排除 BUG-20260801-003 残留。
|
|
|
|
|
|
- 根因分析: da_mouse_init 序列中 `outb(0x64,0x20)`(读控制器配置字)之前未冲刷输出缓冲。shell 启动应用时最后键入的回车 break code(0x9C)或鼠标流字节残留于输出缓冲 → OBF 等待立即返回、`inb(0x60)` 读到残留字节而非配置字 → `cfg|=0x02; cfg&=~0x20` 后写回 → 残留字节 bit4(0x10)=1(0x9C 即满足)置位配置字 KBD 时钟禁用位 → i8042 控制器级禁用键盘,且应用退出后无人恢复该配置 → 会话级键盘全灭。另:鼠标复位(0xFF)实际返回 FA AA 00 共 3 字节,原实现仅读 1 字节,残留响应同样可污染后续配置字读写。desktop/main.c:ps2_mouse_init(键盘鼠标长期共存的参照实现)首尾均有 ps2_drain 且读完全部响应,故桌面不受影响。
|
|
|
|
|
|
- 修复方案: da_mouse_init 对齐 desktop/main.c:ps2_mouse_init:①序列开头新增 da_ps2_drain() 冲刷残留;②配置字 `cfg &= ~0x20; cfg |= 0x02; cfg |= 0x40`(补键盘翻译位,与 desktop/mouseInit 0x47 一致);③复位后有界读完 FA AA 00 全部响应、使能数据报告后读完 ACK;④结尾再次 da_ps2_drain()。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/tools/desktop_app.h da_mouse_init + 新增 da_ps2_drain),2026-08-04 全量构建闭环(BUILD.lock 互斥):fileman.elf 46848→46888B、browser.elf 48896→48928B、editor.elf 同步重编(MAKEFILE 无头文件依赖,已删 .o 强制重编),ISO/deshab.img 768MB 重打包 + SATA 镜像重建,构建零警告。
|
|
|
|
|
|
- 验证: 2026-08-04 QEMU 验收 12/12 ALL PASS(`.build_tmp/w4a/w4a_bug008.log`,-snapshot,monitor 45601,WHPX):dev_mode shell `run FILEMAN.ELF` → `[fileman] boot`(L4794)→ sendkey 方向键选区移动(screendump w4a_fm1/fm2.ppm 像素差异采样 1831)→ ret 打开条目(w4a_fm3.ppm 差异 2170)→ esc → `[fileman] exit`(L4803)→ `[shell] run: tool returned`(L4804)→ 键入 `id` → `uid=0(root) gid=0(root)`(L4806,键盘跨应用存活闭环);`run BROWSER.ELF` → `[browser] boot`(L5197)→ esc → `[browser] exit`(L5198)→ tool returned(L5199)→ `id` → `uid=0(root)`(L5201)同链路通过;渲染 screendump w4a_fm1/fm2/fm3/br1/shell.ppm 均正常。回归:boot-regression.ps1 PASS(257.8s,B1 首启向导/B2 正常启动/B3 dev_mode/B4 无盘降级/B5 无 NIC 全过,无 [PANIC]);userapps-matrix.ps1 系统行为全 PASS(dev_tests/help/pci 存活/Esc→cmd→desktop 链路/fileman boot/browser boot),唯一 FAIL 为 editor 断言陈旧——脚本仍期待 BUG-002 修复前的 "run: ELF 加载失败",实测 `[editor] boot`→`[editor] exit` 正常(userapps-matrix-125211.log L5066-5067),该断言升级属测试脚本维护范畴,非系统回归。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260801-007 [P1] [UTSM/pe] PE32 解释器 shim fn64 回退把 guest 指针当 host 指针:shim_printf 解引用 0x401017 → #PF → 三重故障
|
|
|
|
|
|
- 现象: `pe HELLO32.EXE` 解释执行时串口止于 "[PE] running PE32 via x86emu32",无 "Hello from PE32!",guest 三重故障,QEMU(-no-reboot)静默退出。TCG 与 WHPX 表现一致。
|
|
|
|
|
|
- 复现步骤: x86emu32-coverage.ps1(AUTOEXEC `pe HELLO32.EXE`)→ 会话在 "[PE] running PE32 via x86emu32" 后立即退出。
|
|
|
|
|
|
- 串口/日志证据: `.build_tmp/tests/x86emu32-tcg-134351.log` 尾部止于 "[PE] running PE32 via x86emu32";此前 QEMU `-d int` 捕获 v=0e(#PF)RIP 落在 shim_printf 函数体内(utsm.elf 反汇编确认),无 "[PE32] emulator error"——**解释器本身无差错,故障在 host 侧 shim**。
|
|
|
|
|
|
- 根因分析(静态全链定案):
|
|
|
|
|
|
1. pe_shim.c shim 表条目第 4 初始化元全为 0(如 `{"msvcrt.dll","printf",(void*)shim_printf,0}` 只设 fn64)→ **全表 fn32=NULL,pe_shim.h 设计的 fn32 列("从模拟栈读参数调用 fn32")整体缺失**。
|
|
|
|
|
|
2. x86emu32.c try_iat_call() 拦截 CALL IAT(合成地址 0x0001xxxx)后 fn32 为空 → 走 fn64 回退 `f(a0,a1,a2,a3)`,a0..a3 是从模拟栈读出的**原始 32 位 guest 值**:hello32 的 `push 0x401017`(msg guest VA = image_base 0x400000 + 0x1017)→ a0=0x401017。
|
|
|
|
|
|
3. shim_printf(pe_shim.c L219)`const char *f = (const char *)fmt;` 把 guest VA 直接当 host 指针解引用,**无 guest→host 转换**(解释器映像驻留在 emu->mem 大缓冲区,正确地址应为 emu->mem + 0x401017)→ host 低地址 0x401017 未映射 → #PF → BUG-20260801-005 放大为三重故障。
|
|
|
|
|
|
拦截前链路均正确:0x68 push imm32、FF /2 `call [disp32]` ModRM 解码、read_rm32 读 IAT 合成地址、try_iat_call 参数读取——解释器覆盖率不记倒退。
|
|
|
|
|
|
- 修复方案(系统侧,本轮测试任务约束不改系统代码,仅登记): ①为每个含指针参数的 shim 实现 fn32(接收 esp_ptr=&emu->mem[esp],guest VA 经 emu->mem 基址转换为 host 指针);②或 fn64 回退前设置全局 g_emu_mem_base,shim 内对 <0x10000000 的指针统一加基址转换;③kernel32 WriteFile/ReadFile 等指针参数函数同理。
|
|
|
|
|
|
- 状态: [OPEN]
|
|
|
|
|
|
- 修复提交: 待提交
|
|
|
|
|
|
- 验证: 修复后 x86emu32-coverage.ps1 应见 "Hello from PE32!" → "[cmd] PE run end" → "[DSK] cmd.elf returned";pe-compat.ps1 会话 B 同步验证(两处均已留自动升级断言:日志出现即升 PASS)。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260801-006 [P1] [UTSM/pe] pe_shim setjmp/longjmp 跨已返回函数 UB:longjmp 恢复脏栈寄存器 → 野指针 call → 三重故障
|
|
|
|
|
|
- 现象: `pe HELLO64.EXE` 原生执行成功打印 "Hello from PE32+!"(BUG-004 修复后),随后在 ExitProcess 阶段 guest 三重故障,QEMU(-no-reboot)静默退出;后续 AUTOEXEC 命令(HELLO32/NONEXIST/exit)全部不再执行。TCG 与 WHPX 表现一致。
|
|
|
|
|
|
- 复现步骤: pe-compat.ps1(AUTOEXEC `pe HELLO64.EXE`)→ 串口止于 "Hello from PE32+!"。
|
|
|
|
|
|
- 串口/日志证据: QEMU `-d int` 追踪(`.build_tmp/tests/pe-int-dbg.log`):
|
|
|
|
|
|
`v=0e e=0003 IP=0028:ffffffff80014796 SP=0030:ffffffff80003030 CR2=ffffffff80003028`(**写保护违例**,非缺页)→ 投递 #PF 即 #GP(BUG-005 放大)→ v=08 → Triple fault。
|
|
|
|
|
|
现场寄存器:R12=0x6666666666667830("0xfffffff")、R13=0x3033326530386666("ff80e230")——正是 log_hex64("[PE] stack_top=",0xffffffff80e23000) 格式化缓冲区 ASCII 残片;R14/R15/RBP 均为脏值。
|
|
|
|
|
|
反汇编定案(utsm.elf):fault RIP `pe_service_run+0x226` = `call *%r15`(pe_call_on_stack 内联汇编调 PE 入口那条);但 R15=0xffffffff8055b260 并非 PE 入口 0xffffffff80d22000、RSP=0xffffffff80003030 并非 PE 栈顶 0xffffffff80e23000——**这是 longjmp 用脏栈"恢复"出来的假现场**,不是正常调用路径。
|
|
|
|
|
|
pe_shim_setup_exit(0xffffffff80014d60)反汇编:clang 把 __builtin_setjmp 实现为 `g_exit_jmp={RBP,RSP,resume=0x80014d94}`,恢复后从 0x80014d94 起执行函数尾声 `pop rbx;pop r12;pop r13;pop r14;pop r15;pop rbp;ret`——**从恢复的栈上弹 7 个槽**。
|
|
|
|
|
|
- 根因分析: pe_shim_setup_exit() 内调 __builtin_setjmp 后**即返回**(C 标准:含 setjmp 的函数已返回时再 longjmp 为未定义行为)。setjmp→longjmp 之间 pe_service_run 又调用 log_hex64×2("[PE] entry="/"[PE] stack_top="),其栈帧**精确复用** pe_shim_setup_exit 尾声要弹的那片栈区 → longjmp 尾声 pop 出的 rbx/r12-r15/rbp 全是 log_hex64 帧残片(R12/R13 即十六进制字符串残片),最后 `ret` 弹到 [X-8] 槽位的残留返回地址 0x8001478c(log_hex64 调用点返回地址)→ 落到 pe_call_on_stack 内联汇编正中间(`mov %rsp,g_pe_saved_rsp; mov %r14,%rsp; call *%r15`)→ 以脏 R14 为栈、脏 R15 为入口野调用 → 写返回地址到只读页 0xffffffff80003028 → #PF(保护违例) → BUG-005 放大为三重故障。PE32 解释器路径同一 setjmp/longjmp 机制,同样暴露在 UB 下(只是中间无 log 调用、脏数据不同,崩溃形态可能不同)。
|
|
|
|
|
|
- 修复方案(系统侧,本轮测试任务约束不改系统代码,仅登记): ①把 setjmp 下沉到 pe_service_run 本体内(含 PE 调用全程存活的作用域),不要用"setjmp 包装函数";②或弃用 __builtin_setjmp/longjmp,改用显式上下文保存结构(保存 callee-saved + RSP/RIP 到 pe_service_run 帧内,ExitProcess 经受控 trampoline 返航);③PE32 路径同理。
|
|
|
|
|
|
- 状态: [OPEN]
|
|
|
|
|
|
- 修复提交: 待提交
|
|
|
|
|
|
- 验证: 修复后 pe-compat.ps1 应见 "[PE] ExitProcess code=" → "[cmd] PE run end" → "[DSK] cmd.elf returned" 完整链路;x86emu32-coverage.ps1 动态链路同步验证。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260801-004 [P1] [tools/pe-samples] gen_pe.py PE32+ 二进制双重构造缺陷 → 原生执行三重故障
|
|
|
|
|
|
- 现象: `pe HELLO64.EXE` 原生执行时 guest 直接三重故障,QEMU(-no-reboot)进程退出;串口最后一行为 `[PE] stack_top=...`,无 "Hello from PE32+!"。WHPX 下表现为 "Unexpected VP exit code 4",TCG 下同样退出(此前误判为 WHPX 平台限制)。
|
|
|
|
|
|
- 复现步骤: pe-compat.ps1(AUTOEXEC `pe HELLO64.EXE`)→ 会话在 `[PE] running PE32+ natively` 后退出。
|
|
|
|
|
|
- 串口/日志证据: QEMU `-d int,cpu_reset` 追踪(`.build_tmp/pe-dbg-qemu.log` 尾部):`v=0e e=0010 IP=0028:...0300 CR2=0x300`(在 0x300 取指缺页)→ 投递 #PF 时 #GP → `v=08` → Triple fault。RIP=0x300 正是未被 shim 修补的 IAT[0] 原始值(printf 名称 RVA)。
|
|
|
|
|
|
- 根因分析(双重缺陷,均属 gen_pe.py 构造错误):
|
|
|
|
|
|
1. **call disp32 写错偏移**:call 指令位于 code[7..12](FF 15 + disp32),disp32 应写偏移 9,实际写偏移 10 → disp 左移一字节变为 0x1F300,同时覆盖下一条指令首字节。
|
|
|
|
|
|
2. **import 区 RVA 全部缺 +0x1000(code_rva)偏置**(修复①后仍失败的真正主因):build_pe32_plus/build_cmd_exe 中 printf_name/exitproc_name/msvcrt/kernel32/import_desc 写成裸缓冲区偏移 0x300/0x320/0x350/0x360/0x400 → 数据目录 Import RVA=0x400 落在 headers 区 → rva_to_offset 返回 0xFFFFFFFF → resolve_imports 静默返回 → IAT 永不被 shim 修补 → `call [rip+0x1F3]` 跳到 0x300 → #PF → 三重故障。build_pe32 一直是正确的(0x1300 等带偏置),PE32+ 两个 builder 抄错。
|
|
|
|
|
|
3. 放大器(系统侧,另立 BUG-20260801-005):DSK 阶段任何 CPU 异常都无法投递,直接三重故障重启,串口零诊断。
|
|
|
|
|
|
- 修复方案: ①两处 disp32 pack_into 偏移 10→9;②build_pe32_plus/build_cmd_exe 的 name/DLL/import_desc RVA 全部加 code_rva 偏置(0x1300/0x1320/0x1350/0x1360/0x1400),IAT thunk 同步修正;③重新生成 hello64.exe/hello32.exe/cmd.exe 并同步 SYSTEM/bin/。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/tools/pe-samples/gen_pe.py build_pe32_plus/build_cmd_exe)
|
|
|
|
|
|
- 验证: hello64.exe 静态校验全绿——.text `call [rip+0x1F3]`→IAT 0x1200、ImportDir RVA=0x1400、desc0/desc1 OFT/FT=0x1200/0x1210、Name=0x1350/0x1360、IAT thunk=0x1300/0x1320;pe-compat.ps1 复测。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260801-005 [P1] [UTSM/IDT] DSK 阶段 CPU 异常无法投递:#PF 投递即 #GP → 三重故障重启,串口零诊断
|
|
|
|
|
|
- 现象: DSK/cmd/PE 阶段一旦发生 #PF/#GP 等异常,guest 立即三重故障,QEMU(-no-reboot)静默退出,串口无任何异常信息(无向量号/RIP/CR2)。
|
|
|
|
|
|
- 复现步骤: 运行含缺陷的 HELLO64.EXE(BUG-004,call 到未映射地址 0x300)→ QEMU 直接退出;或任何 DSK 阶段空指针解引用。
|
|
|
|
|
|
- 串口/日志证据: QEMU `-d int` 追踪(`.build_tmp/pe-dbg-qemu.log`):`check_exception old: 0xffffffff new 0xe`(#PF at RIP=0x300, CR2=0x300, RSP=0xffffffff80e22ff0 栈有效)→ `old: 0xe new: 0xd`(**投递 #PF 时即 #GP**)→ `old: 0x8 new 0xd`(投递 DF 时再 #GP)→ Triple fault。现场:IDT=ffffffff8002b000 lim=0xfff,GDT=ffff80007fe3d000 lim=0x47,CS=0028/SS=0030,TR=0038 且 TSS base=0。
|
|
|
|
|
|
- 根因分析: BUG-20260729-013 的 `idt_halt_all()` 把 256 个 IDT 条目换成 halt stub,意图 cli;hlt 安全停机;但实测异常**投递本身**就 #GP——halt 门描述符的选择子/IST 与 DSK 阶段 GDT/TSS(TSS base=0)不匹配,异常帧无法压栈。净效果:DSK 阶段是无异常容错的裸奔环境,任何 guest bug 都表现为"QEMU 静默退出",测试侧只能开 `-d int` 才能定位。
|
|
|
|
|
|
- 修复方案(系统侧,本轮测试任务约束不改系统代码,仅登记): ① halt IDT 门用 DSK 阶段 GDT 内有效选择子重建、IST=0;② 或 DSK 入口自建最小 IDT(#PF/#GP/#DF 打印向量+CR2+RIP 后 cli;hlt);③ 恢复 TSS 有效基址。
|
|
|
|
|
|
- 状态: [OPEN]
|
|
|
|
|
|
- 修复提交: 待提交
|
|
|
|
|
|
- 验证: 修复后重跑含缺陷 PE:串口应输出异常诊断而非 QEMU 静默退出。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260801-003 [P1] [tools/desktop_app.h] da_mouse_poll 吞键盘扫描码导致应用键盘全灭
|
|
|
|
|
|
- 现象: fileman/browser/editor(所有 #include desktop_app.h 的全屏应用)内键盘输入完全无效:Esc 无法退出、方向键/回车无响应;应用只能由宿主动作(关机/会话终止)结束。
|
|
|
|
|
|
- 复现步骤: dev_mode shell → `run FILEMAN.ELF` → 启动后按 Esc → 无 `[fileman] exit`,应用永久停留。
|
|
|
|
|
|
- 串口/日志证据: `.build_tmp/tests/userapps-matrix-021449.log`:`[fileman] boot` 后 3 次 Esc(每次等 20s)均无 `[fileman] exit`。
|
|
|
|
|
|
- 根因分析: `da_mouse_poll()`(desktop_app.h L287-291)先 `inb(0x64)` 判有数据即 `inb(0x60)` 读走字节,再判 `st & 0x20` 发现是键盘字节直接 return 丢弃 → 键盘扫描码被鼠标轮询消耗。应用主循环每轮先调 da_mouse_poll 再轮询键盘 → 键盘字节永远到不了键盘分支。desktop/main.c 的 `ps2_mouse_poll()` 顺序正确(先判 0x20 再读 0x60),桌面不受影响;desktop_app.h 注释自称"与 desktop 保持一致"但实际不一致。
|
|
|
|
|
|
- 修复方案: `da_mouse_poll()` 调整为:`(st & 1) && (st & 0x20)` 时才 `inb(0x60)`,与 desktop/main.c ps2_mouse_poll 对齐。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/tools/desktop_app.h da_mouse_poll:先判 AUX 位 st&0x20 再读 0x60)
|
|
|
|
|
|
- 验证: QEMU 实测(`.build_tmp/w3b_s2_tools.log`):editor 键盘输入与 Esc 退出正常(`[editor] boot`→`[editor] exit`→`[shell] run: tool returned`);fileman 鼠标移动/点击选中/关闭按钮退出正常;运行中 fileman.elf 反汇编确认键盘字节(st&0x20==0)不再被鼠标轮询消耗。注:fileman/browser 键盘在修复后仍全灭,深挖定位为另一独立根因——da_mouse_init 配置字污染(BUG-20260801-008),该条目修复后 `[fileman] exit`/`[browser] exit` 断言方可完全恢复。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260801-002 [P1] [shell] g_run_image 仅 256KB,editor.elf(496KB 内存镜像)run 拒绝加载
|
|
|
|
|
|
- 现象: dev_mode shell 中 `run EDITOR.ELF` 输出 "run: ELF 加载失败(无效格式或过大)",编辑器无法从 shell 启动(桌面宿主 g_elf_image=1MB,可正常启动)。
|
|
|
|
|
|
- 复现步骤: dev_mode shell → `run EDITOR.ELF`。
|
|
|
|
|
|
- 串口/日志证据: `.build_tmp/tests/userapps-matrix-021449.log` L4821/5167/5513 "run: ELF 加载失败(无效格式或过大)" ×3。
|
|
|
|
|
|
- 根因分析: shell `g_run_image[262144]`(256KB)上限;editor.elf 文件 43KB 但 BSS NOBITS 内存镜像 496KB(编辑器大文本缓冲)→ `sh_load_elf` 返回 -5。其余工具内存镜像均在限内:fileman 208KB / browser 116KB / ping 128KB / curl 200KB。
|
|
|
|
|
|
- 修复方案: `g_run_image` 扩至 1MB(与 desktop g_elf_image 对齐),或改为按 ELF memsz 动态划分。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/shell/main.c g_run_image 262144→1048576,与 desktop 宿主 g_elf_image 对齐)
|
|
|
|
|
|
- 验证: QEMU dev_mode shell 实测(`.build_tmp/w3b_s2_tools.log` L4732-4735):`run EDITOR.ELF` → `[shell] run: jumping to tool` → `[editor] boot` → `[editor] exit` → `[shell] run: tool returned`,editor.elf 496KB 内存镜像成功载入 1MB 缓冲并运行、退出;userapps-matrix.ps1 的 `[editor] boot` 断言应可升级。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260801-001 [P1] [shell] 扫描码 0x15/0x17/0x0B 被误当 Ctrl+U/W/K,字母 y/i/0 无法输入
|
|
|
|
|
|
- 现象: shell 交互输入中字母 i、y、数字 0 被吞:`id` 变 "d"、`ping` 变 "ng"、`whoami`/`exit`/`editor` 等含 i 命令均无法键入;串口回显 "未知命令: d" / "未知命令: ng"。
|
|
|
|
|
|
- 复现步骤: dev_mode shell 提示符下键入 `id` 回车(QEMU monitor sendkey 或真实键盘均可复现)。
|
|
|
|
|
|
- 串口/日志证据: `.build_tmp/tests/userapps-matrix-021449.log` L4431/4438/4445 "未知命令: d" ×3,L4460/4467/4474 "未知命令: ng" ×3。
|
|
|
|
|
|
- 根因分析: shell 主循环(CODE/shell/main.c L3399-3401)将扫描码 0x15(y)/0x17(i)/0x0B(0) 直接映射为 Ctrl+U(kill_line)/Ctrl+W(删整行)/Ctrl+K(kill_to_end) 快捷键,但 shell 未跟踪 Ctrl 修饰键状态,也无 Ctrl 按下判定 → 普通按键被当作快捷键吞掉。`ping` 的 p 插入后 i 触发"删整行"→ 剩 "ng"。
|
|
|
|
|
|
- 修复方案: 增加 Ctrl 修饰键跟踪(0x1D/0x9D 左右 Ctrl),仅在 Ctrl 按下时启用 0x15/0x17/0x0B 快捷键分支。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/shell/main.c:新增 ctrl 变量跟踪 0x1D 按下/0x9D 释放,0x15/0x17/0x0B 快捷键分支加 && ctrl 条件)
|
|
|
|
|
|
- 验证: QEMU dev_mode shell monitor sendkey 实测(`.build_tmp/w3b_s1_shell.log`):`id` → 输出 `uid=0(root) gid=0(root)`(L4405,i 不再被吞);吞键对照测试 `y0i ok` 完整回显(L4407,y/0/i 三键全通,修复前分别触发 Ctrl+U/W/K 被吞);`ping` → `[ping] boot`(L5214,i 不再被吞)。Ctrl+U/W/K 快捷键逻辑保留,仅在按住 Ctrl 时生效。userapps-matrix.ps1 的 id/whoami/ping MANUAL 断言可升级。
|
|
|
|
|
|
|
2026-07-31 13:53:49 +08:00
|
|
|
|
### BUG-20260729-021 [P2] [DSK/kernel_api] 硬偏移读取 kernel_api.block 脆弱性
|
|
|
|
|
|
- 现象: DSK 通过 `*(u64*)(api + 0xA8)` 硬偏移读取 `dkm_kernel_api.block`,若结构体在 `block` 字段前插入新字段,DSK 将读取到错误指针 → 解引用 → 立即崩溃,无日志。
|
|
|
|
|
|
- 复现步骤: 修改 dkm.h 中 `dkm_kernel_api` 在 `block` 字段前增加任意字段 → 编译 DSK(不重新编译)→ 启动。
|
|
|
|
|
|
- 串口/日志证据: 安全审查Agent报告(bd89e1b9),4.1节。
|
|
|
|
|
|
- 根因分析: DSK 独立编译不含 `dkm_kernel_api` 结构体定义,无法在编译期校验偏移一致性;注释虽警告"新增字段只允许追加在末尾",但无编译期保障。
|
|
|
|
|
|
- 修复方案: ① DSK 端 include `dkm_kernel_api` 结构体定义并用字段名访问;② 或添加 `_Static_assert(offsetof(..., block) == 0xA8, ...)` 编译期校验。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/dsk/main.c + CODE/shell/main.c)
|
|
|
|
|
|
- 验证: DSK/shell 均添加 dsk_kernel_api_mirror/shell_kernel_api_mirror 镜像结构体 + _Static_assert 编译期校验 + 字段名访问,不再使用硬偏移。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260729-020 [P1] [UTSM/IDT] IOAPIC 中断路由可能绕过 PIC mask
|
|
|
|
|
|
- 现象: 实机通过 IOAPIC 路由中断时,`dsk_load_and_jump()` 中的 PIC mask 不影响 IOAPIC redirection entry,中断可能绕过 PIC mask 直接到达 CPU。
|
|
|
|
|
|
- 复现步骤: 在使用 IOAPIC 的实机上启动 → UTSM mask PIC → DSK 运行期间 IOAPIC 路由的 IRQ 到达 → IDT halt stub 触发(修复 BUG-013 后)→ 安全停机而非崩溃。
|
|
|
|
|
|
- 串口/日志证据: 系统日志Agent报告(aa2d3f5a),崩溃点B分析。
|
|
|
|
|
|
- 根因分析: `dsk_load_and_jump()` 仅操作 8259 PIC 的 IMR 寄存器,未处理 IOAPIC 的 24 个 redirection entry。实机(尤其是多核平台)中断路由通常经 IOAPIC 而非 PIC。
|
|
|
|
|
|
- 修复方案: ① 在 `dsk_load_and_jump()` 中 mask IOAPIC 全部 24 个 redirection entry(设 mask 位);② 或在 LAPIC 中设置 TPR=0xFF 屏蔽所有中断。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/UTSM/kernel/dsk_loader.c dsk_load_and_jump)
|
|
|
|
|
|
- 验证: 采用方案②:通过 IA32_APIC_BASE MSR 读取 LAPIC 基地址 + HHDM 偏移,写入 TPR=0xFF 屏蔽所有可屏蔽中断优先级。仅在 LAPIC 全局启用时(bit 11)执行。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260729-019 [P1] [UTSM+DSK/FAT32] FAT 表缓冲区在实机大容量磁盘上溢出
|
|
|
|
|
|
- 现象: FAT32 FAT 表缓冲区 `g_dsk_fat32_disk[131072]`(128KB/256扇区)在实机大容量磁盘上不足。2GB 以上分区的 FAT 表超过 128KB,FAT 链遍历在缓冲区边界处中断,文件读取截断或失败。
|
|
|
|
|
|
- 复现步骤: 在 ≥2GB FAT32 分区上启动 → UTSM 从 SATA 盘读取 deshab.elf → FAT 条目偏移超过 128KB → `fat_ent + 4 > sizeof(g_dsk_fat32_disk)` → 循环中断 → 文件未找到或数据截断。
|
|
|
|
|
|
- 串口/日志证据: 安全审查Agent报告(bd89e1b9),2.1节;计算表:2GB分区/32KB簇=256KB FAT(溢出),32GB分区/4KB簇=32MB FAT(严重溢出)。
|
|
|
|
|
|
- 根因分析: FAT 读取策略为"一次性预读 256 扇区",在 QEMU 4MB 测试镜像上够用,但实机磁盘分区远大于此。当文件起始簇在缓冲区内但后续簇不在时,ELF 数据不完整 → 加载后必然崩溃。
|
|
|
|
|
|
- 修复方案: 实现"按需 FAT 扇区读取":仅读取包含目标条目的单个 FAT 扇区(512字节),而非预读整个 FAT 表。需新增 `fat32_get_next_cluster()` 函数。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/UTSM/kernel/dsk_loader.c + CODE/dsk/main.c + CODE/shell/main.c)
|
|
|
|
|
|
- 验证: 三端均实现 fat32_get_next_cluster() 按需 FAT 扇区读取:条目在缓冲区内直接读取,超出则按需读单扇区(512B)。写入路径保留缓冲区内修改+回写逻辑不变。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260729-018 [P1] [DSK/loader] g_fdata 仅 1MB,与 UTSM 端 2MB 不一致
|
|
|
|
|
|
- 现象: DSK 端文件数据缓冲区 `g_fdata[1048576]` 仅 1MB,而 UTSM 端 `g_dsk_fat32_filedata[2097152]` 为 2MB。当前 desktop.elf 约 150KB 暂时够用,但增长后将突破 1MB 限制。
|
|
|
|
|
|
- 复现步骤: desktop.elf 增长至 >1MB → `fat32_read_root_file` 因 `found_size > sizeof(g_fdata)` 返回 -6 → desktop 无法加载。
|
|
|
|
|
|
- 串口/日志证据: 安全审查Agent报告(bd89e1b9),2.2节。
|
|
|
|
|
|
- 根因分析: UTSM 和 DSK 两端缓冲区大小定义不一致,DSK 端未与 UTSM 对齐。
|
|
|
|
|
|
- 修复方案: `g_fdata[1048576]` → `g_fdata[2097152]`,与 UTSM 端对齐。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/dsk/main.c L66)
|
|
|
|
|
|
- 验证: 编译通过,镜像生成成功。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260729-017 [P1] [UTSM/dsk_loader] FAT32 加载器 11 个返回点无日志
|
|
|
|
|
|
- 现象: `dsk_load_from_block_fat32()` 有 11 个 `return -1` 出口但无任何日志输出。实机 SATA 盘 FAT32 结构与 QEMU 不同时,函数静默失败回退 Limine boot module,用户无法从日志得知失败原因。
|
|
|
|
|
|
- 复现步骤: 实机启动 → FAT32 解析任意步骤失败 → 串口无相关日志 → 回退 Limine 或 halt。
|
|
|
|
|
|
- 串口/日志证据: 系统日志Agent报告(aa2d3f5a),缺口1分析。
|
|
|
|
|
|
- 根因分析: 函数编写时为早期最小实现,未添加错误路径日志。
|
|
|
|
|
|
- 修复方案: 在全部 11 个 `return -1` 前添加 `log_error` + 诊断 `log_hex64`,输出失败条件和关键参数值。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/UTSM/kernel/dsk_loader.c L182-317)
|
|
|
|
|
|
- 验证: 编译通过,日志覆盖完整。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260729-016 [P0] [DSK/loader] kernel_api / framebuffer 解引用无 NULL 验证
|
|
|
|
|
|
- 现象: DSK `dsk_spinner_and_check()` 直接解引用 `ctx->dkm_kernel_api` 和 `ctx->framebuffer_address`,无 NULL 检查。若 `api` 为 0 → `*(u64*)(0 + 0xA8)` 解引用地址 0xA8 → 页错误 → 三重故障重启。framebuffer 为 NULL 同理。
|
|
|
|
|
|
- 复现步骤: boot_context 传递错误(kernel_api=0 或 fb=0)→ DSK entry → 立即页错误。
|
|
|
|
|
|
- 串口/日志证据: 系统日志Agent报告(aa2d3f5a),缺口3/4分析。
|
|
|
|
|
|
- 根因分析: 早期实现假设 boot_context 始终有效,未添加防御性检查。
|
|
|
|
|
|
- 修复方案: ① `kernel_api` NULL 检查 + 诊断日志;② `framebuffer_address` NULL 检查;③ 输出 `block_api` / `block_read` / `block_write` 函数指针地址便于调试。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/dsk/main.c L866-878)
|
|
|
|
|
|
- 验证: 编译通过。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260729-015 [P0] [DKM/ahci] AHCI 写入超时使用固定循环 + PxCMD.W 违规写入
|
|
|
|
|
|
- 现象: `ahci_write_blocks_internal()` 使用 `for(i=0;i<5000000;i++)` 固定循环超时。实机 CPU 频率差异导致超时时间不可预测(快 CPU 可能过早超时,慢 CPU 可能等待过久)。同时代码写入 `PxCMD.W` 位(AHCI 规范中为只读位),违反 AHCI 1.3 规范。
|
|
|
|
|
|
- 复现步骤: 实机启动 → DSK 通过 AHCI 写入 FAT32 → 固定循环超时不足 → 写入超时失败 → FAT32 写操作失败 → 系统异常。
|
|
|
|
|
|
- 串口/日志证据: 驱动开发Agent报告;原代码 L356-358(PxCMD.W 写入)、L363-371(固定循环)。
|
|
|
|
|
|
- 根因分析: ① 写入路径复制了早期读取路径的固定循环模式,未跟随读取路径升级为 TSC deadline;② `AHCI_CMD_W` (bit 6) 在 AHCI 规范中为只读,硬件根据命令头 `flags.W` 自动设置。
|
|
|
|
|
|
- 修复方案: ① 写入超时替换为 TSC 5 秒 deadline(与读取路径一致);② 移除所有 PxCMD.W 读/写操作。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/DKM/ahci/ahci.c L355-371)
|
|
|
|
|
|
- 验证: 编译通过;QEMU 读取路径已验证 TSC 超时有效。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260729-014 [P0] [DSK/loader] dsk_load_elf 完全忽略 size 参数 + PIE 重定位无边界检查
|
|
|
|
|
|
- 现象: DSK 端 `dsk_load_elf()` 显式 `(void)size` 忽略文件大小参数,程序头、PT_LOAD 段、PT_DYNAMIC 段的读取均无边界检查。PIE 重定位中 `rela_off - min_vaddr` 和 `rel->offset - min_vaddr` 可能无符号整数下溢(若 < min_vaddr),导致从 `image` 基址偏移到巨大地址 → 随机内存写入 → 三重故障重启。UTSM 端有完整的 `range_ok` 检查,DSK 端完全缺失。
|
|
|
|
|
|
- 复现步骤: 加载损坏/恶意的 ELF → `rela_off < min_vaddr` → `rela_off - min_vaddr` 下溢为 ~0xFFFFFFFFFFFFFFFF → 读取/写入随机内存 → 崩溃。
|
|
|
|
|
|
- 串口/日志证据: 安全审查Agent报告(bd89e1b9),1.1/1.2/3.1节。
|
|
|
|
|
|
- 根因分析: DSK ELF 加载器为简化实现,省略了 UTSM 端已实现的安全检查。两端 ELF 加载逻辑不一致(UTSM 有 `range_ok`,DSK 忽略 `size`)。
|
|
|
|
|
|
- 修复方案: ① 移除 `(void)size`,添加 `size < sizeof(elf64_ehdr)` 检查;② 程序头范围验证 `phoff + phnum*phentsize <= size`;③ PT_LOAD `offset + filesz <= size` 检查;④ PT_DYNAMIC vaddr 范围检查;⑤ PIE `rela_off >= min_vaddr && rela_off < min_vaddr + isize` 边界检查;⑥ `rel->offset >= min_vaddr && rel->offset < min_vaddr + isize` 边界检查;⑦ entry 范围验证。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/dsk/main.c L721-824)
|
|
|
|
|
|
- 验证: 编译通过;边界检查逻辑与 UTSM 端 `dsk_load_elf_image` 一致。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260729-013 [P0] [UTSM/dsk_loader] UTSM→DSK 跳转前 cli 缺失 + IDT 未重置导致实机三重故障
|
|
|
|
|
|
- 现象: 实机从 UTSM 加载 DSK 后崩溃重启。`dsk_load_and_jump()` 中 PIC mask 操作前未执行 `cli`,两条 `outb`(mask PIC2 和 PIC1)之间存在中断竞争窗口。实机在此窗口内可能触发 spurious IRQ7/15 或 IOAPIC 中断 → 跳转到 UTSM 过期 IDT handler → 若 handler 内调用的内存被 DSK 覆盖 → 双重异常 → 三重故障 → 重启。同时,跳转后 IDT 仍指向 UTSM 的 ISR stub,DSK 运行期间任何 CPU 异常(PF/GP)会执行 UTSM 的 `idt_handler`(含 log_error + for(;;)cli;hlt),若发生双重异常则重启。
|
|
|
|
|
|
- 复现步骤: 实机启动 → UTSM 完成 DKM 加载 → `dsk_load_and_jump()` → PIC mask 两步操作之间中断到达 → 三重故障重启。或在 DSK 运行期间发生 CPU 异常 → UTSM handler → 可能双重异常 → 重启。
|
|
|
|
|
|
- 串口/日志证据: 系统日志Agent报告(aa2d3f5a),崩溃点A/B分析;安全审查Agent报告确认。QEMU 不复现(无 spurious IRQ、无 SMI/NMI)。
|
|
|
|
|
|
- 根因分析: ① `outb(0xA1,0xFF)` 和 `outb(0x21,0xFF)` 之间 IF=1,PIC2 IRQ 可通过 cascade 到 PIC1 触发中断;② IDT 未重置,DSK 阶段异常仍路由到 UTSM handler,handler 依赖的代码/数据可能已被覆盖。
|
|
|
|
|
|
- 修复方案: ① PIC mask 前添加 `__asm__ volatile("cli")` 消除中断窗口;② 新增 `idt_halt_all()` 函数将全部 256 个 IDT 条目替换为安全 halt stub(`cli; hlt` 循环),防止 DSK 运行期间过期 handler 被触发;③ DSK entry 前输出 context 关键字段诊断日志(magic/api/fb)。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/UTSM/kernel/dsk_loader.c L613-650, CODE/UTSM/arch/x86_64/idt.c L440-460, CODE/UTSM/include/utsm/idt.h L8-11)
|
|
|
|
|
|
- 验证: 编译通过;QEMU 启动正常;实机验证待用户执行。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260729-012 [P3] [tools/fileman] go_up 缺少前向声明导致编译错误
|
|
|
|
|
|
- 现象: fileman 编译失败,`open_selected()` 调用 `go_up()` 时函数尚未定义(隐式声明/未定义引用)。
|
|
|
|
|
|
- 复现步骤: 编译 `CODE/tools/fileman/`。
|
|
|
|
|
|
- 串口/日志证据: 编译器报错(implicit declaration of function 'go_up')。
|
|
|
|
|
|
- 根因分析: C 文件内函数定义顺序——`open_selected`(L259)在 `go_up`(L298)之前,缺少前向声明。
|
|
|
|
|
|
- 修复方案: `CODE/tools/fileman/main.c` L258 添加 `static void go_up(void); /* 前向声明:open_selected 调用 go_up */`。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 待提交(工作区已修复)
|
|
|
|
|
|
- 验证: 代码核查——main.c L258 前向声明存在,编译通过。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260729-011 [P1] [build/linker] 全项目 linker.ld 未将 .bss 分离为 NOBITS 段导致 ELF 膨胀
|
|
|
|
|
|
- 现象: 多个用户态 ELF 体积异常膨胀:shell 773KB、cmd 499KB、fileman ~470KB,远超代码实际大小;fileman 因超出桌面宿主加载缓冲区而崩溃(见 BUG-20260728-009)。
|
|
|
|
|
|
- 复现步骤: 构建 shell/cmd/fileman 等 .elf,观察文件体积;反查 program header 的 filesz/memsz。
|
|
|
|
|
|
- 串口/日志证据: 无运行期日志;构建产物体积异常即为证据。
|
|
|
|
|
|
- 根因分析: linker.ld 将 `.bss` 与 `.data` 合并且未分离为独立 NOBITS 段,零初始化 BSS 数据(f32_disk/f32_data 等大缓冲)被计入 ELF 文件体积。
|
|
|
|
|
|
- 修复方案: 全项目 linker.ld 将 `.bss` 分离为独立段置于 `.dynamic` 之后(仍归 `:data` PT_LOAD,phdr filesz<memsz,NOBITS 不占文件空间)。修复后 shell 773KB→92KB、cmd 499KB→92KB、fileman ~470KB→46KB。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 待提交(工作区已修复)
|
|
|
|
|
|
- 验证: 代码核查——`CODE/tools/fileman/linker.ld` L23–28 含分离注释与独立 .bss 段;shell/cmd 等 linker.ld 同构。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260729-010 [P1] [firstInit] FirstInit 设置向导按键崩溃(策划 B6)
|
|
|
|
|
|
- 现象: FirstInit 账户设置卡片中按键导致崩溃。原记录:"fb_text -O2 optimization issue"。
|
|
|
|
|
|
- 复现步骤: firstInit.txt=0 → 首次启动 → 进入 FirstInit 账户设置卡片 → 按任意键。
|
|
|
|
|
|
- 串口/日志证据: 调试会话 `debug-firstinit-key-crash.md`(状态 OPEN)记录 H1–H5 假设:① -O2 下 clang 生成 memset/memcpy 隐式调用或对齐 SSE 指令(freestanding 环境出错);② fb_text/fb_char 路径数组越界(g_ascii 95 项索引边界 / 18px 中文字模尺寸);③ 栈溢出(DSK 直接 call 入口共享同一栈,-O2 内联帧膨胀);④ 扫描码状态机(shift/release)越界写;⑤ linker.ld BSS NOBITS 分离后 rela 覆盖遗漏(指针数组未重定位)。已确认:所有模块 -O2 编译、无 -fno-strict-aliasing;DSK loader 已 memset 整个 image(BSS 安全)。
|
|
|
|
|
|
- 根因分析: 未定,待 QEMU 复现(monitor sendkey + 串口捕获异常向量/RIP)后 addr2line 定位。M1 里程碑确认 QEMU 未复现。
|
|
|
|
|
|
- 修复方案: 添加防御性边界检查:scan_to_ascii 调用前 sc>=58 提前跳过(防止越界);已确认 -fno-builtin 编译标志存在。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/firstInit/main.c read_field 防御性边界检查)
|
|
|
|
|
|
- 验证: M1 里程碑 QEMU 验证未复现;已添加 sc>=58 防御性跳过;-fno-builtin 已存在于编译标志。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260728-009 [P1] [desktop/fileman] fileman.elf 启动触发 QEMU exit(策划 B5)
|
|
|
|
|
|
- 现象: 桌面中打开 Files 应用(外部 .elf 全屏宿主)时 QEMU 进程直接退出,文件管理器不可用。
|
|
|
|
|
|
- 复现步骤: 构建含 fileman.elf 的镜像 → 启动至 desktop → 打开 fileman → QEMU exit。
|
|
|
|
|
|
- 串口/日志证据: fileman 启动后串口输出中断(当时未留存完整日志,退出码待补录)。
|
|
|
|
|
|
- 根因分析: fileman 的 linker.ld 未将 .bss 分离为 NOBITS 段(见 BUG-20260729-011),ELF 膨胀至 ~470KB,超出 desktop `dt_load_elf` 的 `g_elf_image` 256KB 静态缓冲区,加载越界/校验失败。
|
|
|
|
|
|
- 修复方案: ① 全项目 linker.ld .bss 分离 NOBITS(fileman ~470KB→46KB);② desktop `g_elf_image` 由 256KB 扩至 1MB(`CODE/desktop/main.c` L1802)。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 待提交(工作区已修复)
|
|
|
|
|
|
- 验证: 代码核查——linker.ld NOBITS 分离 + g_elf_image=1048576 已确认;fileman 现可打开/浏览/关闭(QEMU 实机回归建议补做)。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260728-008 [P2] [desktop/fileman] Files 缺少 ".." 返回上级目录
|
|
|
|
|
|
- 现象: Files 进入子目录后没有 ".." 条目,用户无法返回上一级文件夹。
|
|
|
|
|
|
- 复现步骤: desktop 打开 Files → 进入任意子目录 → 列表中无返回入口(仅键盘 Backspace)。
|
|
|
|
|
|
- 串口/日志证据: 无(UI 行为问题)。
|
|
|
|
|
|
- 根因分析: `load_current_dir()` 未在非根目录时合成 ".." 伪条目。
|
|
|
|
|
|
- 修复方案: `CODE/tools/fileman/main.c` `load_current_dir()` 在 path_depth>0 时于列表开头插入 ".." 条目(clus=0 特殊标记),`open_selected()` 特判调用 `go_up()`;同时补充 `go_up()` 前向声明(见 BUG-20260729-012)。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 待提交(工作区已修复)
|
|
|
|
|
|
- 验证: 代码核查——main.c L67–82 插入 ".." 条目、L264–267 特判、L298–303 go_up 实现均存在。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260728-007 [P2] [desktop/fileman] Files 未显示文件夹条目(直接显示文件夹下文件)
|
|
|
|
|
|
- 现象: Files 列表中不显示文件夹条目,直接展开了文件夹下的文件,目录层级丢失。
|
|
|
|
|
|
- 复现步骤: desktop 打开 Files → 根目录列表中看不到 SYSTEM 等目录条目。
|
|
|
|
|
|
- 串口/日志证据: 无(UI 行为问题)。
|
|
|
|
|
|
- 根因分析: 目录列举/过滤逻辑未正确区分 `is_dir` 条目(attr 0x10)。
|
|
|
|
|
|
- 修复方案: 修复后 `fm_entry.is_dir` 正确填充,目录以黄色图标 + "DIR" 类型 + "--" 大小显示,Enter 进入子目录(`CODE/tools/fileman/main.c`)。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 待提交(工作区已修复)
|
|
|
|
|
|
- 验证: 代码核查——main.c 列表绘制含 is_dir 分支(图标颜色/类型列),`open_selected()` 目录进入逻辑存在。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260728-006 [P2] [desktop/fileman] Files 默认未显示 SYSTEM/user 目录内容
|
|
|
|
|
|
- 现象: 桌面第一页 Files 面板/Files 应用默认显示根目录,而非用户期望的 SYSTEM/user 内容。
|
|
|
|
|
|
- 复现步骤: 启动至 desktop → 打开 Files → 默认路径为根目录。
|
|
|
|
|
|
- 串口/日志证据: 无(UI 行为问题)。
|
|
|
|
|
|
- 根因分析: fileman 启动时 path_depth=0(根目录),未定位到 SYSTEM/user。
|
|
|
|
|
|
- 修复方案: `CODE/tools/fileman/main.c` `find_user_dir()`:启动时先枚举根目录找 SYSTEM,再在其中找 USER,命中则预设路径栈(path_depth=2)后 `load_current_dir()`。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 待提交(工作区已修复)
|
|
|
|
|
|
- 验证: 代码核查——main.c L306–339 find_user_dir 实现存在,dsk_entry 中调用。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260728-005 [P2] [desktop] DASHBOARD shell 回车后上一条命令文字跑到下一行
|
|
|
|
|
|
- 现象: 桌面第一页(DASHBOARD)的 shell 面板中输入命令回车后,上一条命令的输入文字异常出现在下一行。
|
|
|
|
|
|
- 复现步骤: desktop DASHBOARD → TERM 面板输入任意命令 → 回车 → 观察回显错位。
|
|
|
|
|
|
- 串口/日志证据: 无(UI 行为问题)。
|
|
|
|
|
|
- 根因分析: `redraw_input_line()` 只更新 framebuffer 视觉渲染,不同步终端缓冲区 `term_ch[]`。当 `term_redraw_all()` 从缓冲区重新渲染时,旧输入文字残留在缓冲区导致错位。
|
|
|
|
|
|
- 修复方案: `redraw_input_line()` 中同步更新终端缓冲区 term_ch[]/term_fg[](提示符+输入+空白填充),确保 term_redraw_all() 渲染与视觉一致。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/shell/main.c redraw_input_line)
|
|
|
|
|
|
- 验证: 编译通过;redraw_input_line 现在同步 term_ch/term_fg 缓冲区。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260728-004 [P3] [desktop] Boot 打字机效果速度过慢(期望提速 3 倍)
|
|
|
|
|
|
- 现象: 桌面启动时的打字机 Boot 屏逐字输出节奏过慢,影响开机体验。
|
|
|
|
|
|
- 复现步骤: 启动至 desktop → 观察 Boot 屏打字速度。
|
|
|
|
|
|
- 串口/日志证据: 无(体验问题)。
|
|
|
|
|
|
- 根因分析: 打字机帧间隔常量偏大。
|
|
|
|
|
|
- 修复方案: 缩小打字机每字符间隔(约 3 倍提速)。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 待提交(工作区已修复)
|
|
|
|
|
|
- 验证: ROADMAP 近期进展已记录"Boot 打字机提速";QEMU 观感验证。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260728-003 [P2] [shell] 开发者模式 shell 回车后文字消失无反应
|
|
|
|
|
|
- 现象: 开发者模式(dev_mode)中 shell 输入命令回车,输入文字消失且无任何响应/输出。
|
|
|
|
|
|
- 复现步骤: firstInit.txt 第二行=1 或 FUCK dev_mode=1 → DSK 加载 shell.elf → 手动输入命令 → 回车。
|
|
|
|
|
|
- 串口/日志证据: 无(当时未留存)。
|
|
|
|
|
|
- 根因分析: 与 BUG-005 同根因:`redraw_input_line()` 不同步终端缓冲区,`term_redraw_all()` 从旧缓冲区渲染覆盖当前输入行,导致视觉上输入文字"消失"。
|
|
|
|
|
|
- 修复方案: BUG-005 修复(redraw_input_line 同步 term_ch/term_fg 缓冲区)同时解决此问题。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 工作区已修复(CODE/shell/main.c redraw_input_line — 与 BUG-005 同修复)
|
|
|
|
|
|
- 验证: 编译通过;BUG-005 修复确保终端缓冲区与视觉渲染一致。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260728-002 [P3] [desktop] DESKTOP 页冗余显示终端/CMD 图标
|
|
|
|
|
|
- 现象: 第一页(DASHBOARD)已有 TERM-01/TERM-02 终端面板,第三页 DESKTOP 图标网格仍显示终端和 CMD 图标,入口冗余。
|
|
|
|
|
|
- 复现步骤: desktop → 切到 DESKTOP 页 → 可见终端/CMD 图标。
|
|
|
|
|
|
- 串口/日志证据: 无(UI 设计问题)。
|
|
|
|
|
|
- 根因分析: DESKTOP 页快捷方式列表未排除已在 DASHBOARD 常驻的终端类应用。
|
|
|
|
|
|
- 修复方案: 从 DESKTOP 页图标列表移除终端与 CMD 冗余项。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 待提交(工作区已修复)
|
|
|
|
|
|
- 验证: ROADMAP 近期进展已记录"DESKTOP 页冗余图标移除";代码核查——desktop 图标过滤逻辑已生效(当前 DESKTOP 页无终端/CMD 图标)。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260728-001 [P2] [desktop/fileman] Files 窗口点击关闭按钮(叉)无法关闭
|
|
|
|
|
|
- 现象: Files 应用窗口右上角关闭按钮(叉)点击无反应,无法退出应用。
|
|
|
|
|
|
- 复现步骤: desktop 打开 Files → 点击右上角关闭区域 → 应用未退出。
|
|
|
|
|
|
- 串口/日志证据: 无(UI 行为问题)。
|
|
|
|
|
|
- 根因分析: 鼠标点击处理未命中关闭按钮热区(右上角 w-28..w-4, y 4..24)。
|
|
|
|
|
|
- 修复方案: `CODE/tools/fileman/main.c` 鼠标轮询中检测关闭按钮热区命中后 `da_slog("fileman","close button clicked")` 并 return 退出。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复提交: 待提交(工作区已修复)
|
|
|
|
|
|
- 验证: 代码核查——main.c L372–377 关闭热区判定与退出存在。
|
|
|
|
|
|
|
2026-08-04 18:36:09 +08:00
|
|
|
|
### BUG-20260803-010 [P1] [DKM/nvme] QEMU 在 MSI-X unmask 边界向 IO CQ 补投 CID=0 幽灵 CQE:无 CID 校验时被静默当当前命令完成 → 数据面偶发 MISMATCH
|
|
|
|
|
|
- 现象: B7 阶段3 NVMe MSI-X 中断驱动化后,apic_route=0 回归首次运行 stress 校验失败 (readback MISMATCH, first bad idx=0x9000 页边界,DMA 半途特征),第二次运行不复现;route=1 未观测。命令对账 (slot+poll=命令总数) 与 timeout=0 表明无命令丢失,疑似 CQE 被"提前消费"。
|
|
|
|
|
|
- 复现步骤: QEMU q35 + nvme 测试盘 + FUCK nvme_msi=1 + apic_route=0,驱动 init 内 stress (128 扇区×50 W+R)。
|
|
|
|
|
|
- 串口/日志证据: `.build_tmp/w5b_nvme_msi.log`: `[ERR ] [nvme] stress readback MISMATCH` / `first bad idx= 0x0000000000009000`;加固 CID 校验后每次启动稳定抓到 `[ERR ] [nvme] CID mismatch (slot)` + `expect cid= 0x5` (首个 IO 命令 LBA0 READ) + `got cid= 0x0`,时机恒在 `INTMC unmask IV0` 之后、LBA0 READ 完成之前。
|
|
|
|
|
|
- 根因分析: QEMU nvme 设备模型在 INTMC 解除 IV0 屏蔽 (MSI-X unmask) 边界向 IO CQ entry0 写入一枚 CID=0/phase 正确/status 成功的幽灵 CQE 并补投 MSI。g_cid 从 1 起始,CID=0 不属于任何已提交命令;MSI handler 无差别摘取填槽后,提交侧统一等待不校验 CID,把幽灵 CQE 当 LBA0 READ 的完成消费——若此刻 READ 的 DMA 尚未落盘 (128 扇区 PRP list 多页传输),memcpy 读到半新半旧数据即 MISMATCH。route=0 下 PIC 活跃 (PIT 200Hz) 改变中断/轮询竞速窗口故更易命中,属时序竞态非确定性路径。
|
|
|
|
|
|
- 修复方案: 三层防御 (nvme.c):
|
|
|
|
|
|
1. nvme_iocq_harvest 返回 CQE dw3 低 16 位 CID;统一等待两条路径 (slot 消费 / irqsave poll) 均与提交 cid 比对,不匹配则计数 (g_msi_cid_mismatch) + 报错 + 丢弃继续等真 CQE,绝不静默当成功;
|
|
|
|
|
|
2. g_cid 回绕跳过 0 (if (g_cid == 0) g_cid = 1),CID=0 永久保留,幽灵 CQE 在数学上不可能被误判合法;
|
|
|
|
|
|
3. stress 校验失败时追加 expect/actual/cq head/phase/slot valid 打点。
|
|
|
|
|
|
顺带加固: nvme_msi_handler 改为自写 LAPIC EOI (0xFEE000B0) 并返回 1 抑制钩子——MSI 直投 LAPIC 与 apic_route 开关无关,route=0 下钩子未注册会导致 ISR 位残留、MSI 退化为 one-shot。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复文件: CODE/DKM/nvme/nvme.c (harvest CID 返回 / handler 自 EOI / 统一等待 CID 校验 / g_cid 跳 0 / stress 诊断)
|
|
|
|
|
|
- 验证: route=0 连跑 4+3 次:幽灵 CQE 每次恰好捕获 1 次并安全丢弃,stress verify 全 OK,对账自洽 (slot+poll=159 真命令+1 幽灵);route=1 生产配置复验 PASS;nvme_msi=0 纯轮询回归 PASS;tests/qemu/driver-matrix.ps1 全 PASS (32.1s)。真机无 QEMU 该模型怪癖,CID 校验作为零成本常驻防御保留。
|
|
|
|
|
|
|
2026-07-31 13:53:49 +08:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 附:遗留条目对照
|
|
|
|
|
|
|
|
|
|
|
|
2026-07-29 结构化前的 8 条纯文本遗留 bug 与新编号对照:
|
|
|
|
|
|
|
|
|
|
|
|
| 遗留原文 | 新编号 | 状态 |
|
|
|
|
|
|
|---------|--------|------|
|
|
|
|
|
|
| 软件Files的窗口点击叉无法关闭 | BUG-20260728-001 | FIXED |
|
|
|
|
|
|
| 第一页已有终端,第四页桌面不用显示终端和CMD | BUG-20260728-002 | FIXED |
|
|
|
|
|
|
| 开发者模式 shell 回车文字消失没有反应 | BUG-20260728-003 | FIXED |
|
|
|
|
|
|
| 启动时打字机效果再快3倍 | BUG-20260728-004 | FIXED |
|
|
|
|
|
|
| 第一页 shell 回车后上一条命令文字跑到下一行 | BUG-20260728-005 | FIXED |
|
|
|
|
|
|
| 第一页 Files 显示的不是 SYSTEM/user 中的文件夹内容 | BUG-20260728-006 | FIXED |
|
|
|
|
|
|
| Files 中没有显示文件夹,直接显示文件夹下的文件 | BUG-20260728-007 | FIXED |
|
|
|
|
|
|
| Files 没有提供 ".." 返回上一级文件夹 | BUG-20260728-008 | FIXED |
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260730-P12 [P0] [DSK/Shell] fat32_write_root_file 不遍历 FAT 链,根目录首簇满时报告 "no free dir entry"
|
|
|
|
|
|
- 现象: DSK 里程碑标记和 Shell 测试日志无法写入磁盘,QEMU 串口日志显示 4 次 [DSK] fat32 write: no free dir entry。
|
|
|
|
|
|
- 复现步骤: 使用 SATA FAT32 测试镜像启动(根目录首簇 16 条目全部占用),任何需要创建新文件的写入操作均失败。
|
|
|
|
|
|
- 串口/日志证据: QEMU serial.log 中 4 次 [DSK] fat32 write: no free dir entry。
|
|
|
|
|
|
- 根因分析: at32_write_root_file 只扫描根目录的第一个簇(spc=1 时仅 16 条目),不跟随 FAT 链检查后续簇。SATA 测试镜像根目录 FAT 链为 2→3→EOF,首簇满但第二簇有 10 个空闲条目,代码未到达第二簇。
|
|
|
|
|
|
- 修复方案: 修改 DSK 和 Shell 的 at32_write_root_file,用 while 循环遍历完整 FAT 链搜索空闲条目,记录 ree_clus/ound_clus,写回时使用活动簇而非硬编码
|
|
|
|
|
|
oot_clus。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复文件: CODE/dsk/main.c (L589-655), CODE/shell/main.c (L437-490)
|
|
|
|
|
|
- 验证: QEMU 测试显示 4 次 [DSK] fat32 write: success,4 个里程碑标记文件成功写入 SATA 镜像。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260730-P13 [P0] [Shell] fat32_write_root_file 不遍历 FAT 链 (同 P12)
|
|
|
|
|
|
- 现象/根因/修复: 与 P12 相同,影响 Shell 模块。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复文件: CODE/shell/main.c (L437-490, L553-606, L682-684)
|
|
|
|
|
|
- 额外修复: 当整条 FAT 链都无空闲条目时,自动扩展根目录(分配新簇并链接到 FAT 链尾部)。
|
|
|
|
|
|
- 验证: 同 P12。
|
|
|
|
|
|
|
|
|
|
|
|
### BUG-20260730-P14 [P0] [DKM/ahci] AHCI 写入 TFD 错误检查误判正常状态为错误
|
|
|
|
|
|
- 现象: QEMU 测试中 AHCI 写入报 write error: TFD ERR,导致 FAT32 写入函数返回错误码。实际写入可能成功但因错误检查提前返回,后续 FLUSH CACHE 被跳过。
|
|
|
|
|
|
- 复现步骤: QEMU q35 + SATA 驱动,任何 AHCI 写入操作。
|
|
|
|
|
|
- 串口/日志证据: [WARN] [ahci] write error: TFD ERR,TFD 值为 0x50(DRDY|DRQ,正常状态)。
|
|
|
|
|
|
- 根因分析: hci.c L376 的错误检查 if (tfd & 0xFF) 检查的是 STS 低字节是否非零。但 STS=0x50 (DRDY=1, DRQ=1) 是 DMA 完成后的正常状态,不是错误。正确的检查应只看 STS bit0 (ERR) 和 ERR 寄存器 (bits15:8)。
|
|
|
|
|
|
- 修复方案: 改为 u8 sts = (u8)(tfd & 0xFF); u8 err_reg = (u8)((tfd >> 8) & 0xFF); if ((sts & 0x01) || err_reg)。
|
|
|
|
|
|
- 状态: [FIXED]
|
|
|
|
|
|
- 修复文件: CODE/DKM/ahci/ahci.c (L372-386)
|