feat: B7 APIC/IOAPIC接管 + NVMe写路径 + virtio_net virtqueue + PE兼容层修复 + QEMU测试套件全自动化
中断路由 (B7): - apic.drv: LAPIC enable + IOAPIC重定向表编程(MADT ISO感知) + apic_route/apic_route_legacy/apic_diag开关 - UTSM: LAPIC EOI钩子(register_apic_eoi, ABI尾部追加) + IDT 0-255全覆盖 + spurious 0xFF特判 - FUCK: apic_route=0默认PIC(零回归) / =1 IOAPIC->LAPIC接管(失败完整降级) / legacy放开IRQ1/12/11 存储: - nvme.drv: 写路径 + PRP list + 读回校验 + MSI/MSI-X中断驱动(nvme_msi开关, 回退纯轮询) - build.ps1: apic.drv纳入构建(原为预置二进制) 网络: - virtio_net: virtqueue RX/TX + netdev注册 + DHCP自测(slirp真实OFFER) PE兼容层: - pe_shim: guest->host指针转换(g_emu_mem_base + gp()) + shim fn32列补齐 - gen_pe.py: PE32+ RVA偏置修复(BUG-004) + cmd.exe生成 - desktop_app.h: da_mouse_poll先判AUX位 + da_mouse_init冲刷残留(BUG-003/008) - shell: Ctrl修饰键跟踪(BUG-001) + g_run_image扩至1MB(BUG-002) QEMU测试套件: - 9用例全自动化(Run-All.ps1): boot-regression/driver-matrix/linux-compat/pe-compat/deaicup-e2e/userapps-matrix/network-e2e/performance-baseline/x86emu32-coverage - QemuTest.ps1公共库: 串口断言/monitor sendkey/screendump/HTTP服务器/并发隔离 文档: - CLAUDE.md: APIC/IOAPIC能力 + kernel_api暴露 + IRQ后端升级状态 - LESSONS_LEARNED.md: B7 LAPIC/IOAPIC经验教训(2条) - Bug记录.txt: BUG-20260801-001~008 + BUG-20260803-009(9条) - test-cases/*.md: 全部补充自动化脚本小节 - 桌面设计.md: .lnk快捷方式 + LINUXAPP.CNF Linux应用图标 - 系统开发策划.md: NVMe/virtio_net标完成 + B2/B7标已解决 + M2进度列
This commit is contained in:
+163
-38
@@ -1,15 +1,23 @@
|
||||
#requires -Version 5.1
|
||||
#requires -Version 5.1
|
||||
<#
|
||||
.SYNOPSIS
|
||||
pe-compat — PE/EXE 兼容层测试(docs/RE/test-cases/pe-compat.md)
|
||||
|
||||
.DESCRIPTION
|
||||
正常启动到 cmd.elf,用 AUTOEXEC.BAT 自动执行 PE 命令序列:
|
||||
正常启动到 cmd.elf,用 AUTOEXEC.BAT 自动执行 PE 命令序列。
|
||||
因两个已登记系统 bug(详见 docs/RE/Bug记录.txt),拆三个独立会话:
|
||||
|
||||
pe HELLO64.EXE → PE32+ 原生 Ring0 执行,shim_WriteFile 输出串口
|
||||
pe HELLO32.EXE → PE32 x86emu32 解释执行,shim32 输出串口
|
||||
pe NONEXIST.EXE → 错误路径:不产生 [cmd] PE run begin
|
||||
exit → 返回 DSK → desktop
|
||||
会话 A (pe64):pe HELLO64.EXE → PE32+ 原生 Ring0 执行,shim_WriteFile 输出串口。
|
||||
BUG-20260801-006 已修复(setjmp 下沉 pe_service_run 本体):
|
||||
ExitProcess longjmp 干净返回,"[cmd] PE run end" 稳定出现。
|
||||
会话 B (pe32):pe HELLO32.EXE → PE32 x86emu32 解释执行。
|
||||
BUG-20260801-007 已修复(gp() guest→host 指针转换 +
|
||||
fn64 调用 typedef 显式 ms_abi):"Hello from PE32!" 稳定输出。
|
||||
会话 D (fault64):pe FAULT64.EXE → BUG-20260801-005 验收:DSK 阶段故意
|
||||
#PF 必须打出 [IDT] exception 完整现场(vector=0xe, err=0x2,
|
||||
cr2=0x40000000000)。修复前 halt_all 静默吞异常零日志。
|
||||
会话 C (peerr):pe NONEXIST.EXE + exit → 错误路径:不产生 [cmd] PE run begin;
|
||||
exit 正常返回 DSK("[DSK] cmd.elf returned")。
|
||||
|
||||
串口可断言锚点:
|
||||
[cmd] PE run begin / [cmd] cmdline: ... / [cmd] PE run end (logl/swrite, 始终上串口)
|
||||
@@ -17,66 +25,183 @@
|
||||
[PE] running PE32 via x86emu32 (pe_service)
|
||||
Hello from PE32+! / Hello from PE32! (shim WriteFile → 串口)
|
||||
|
||||
注意:cmd_pe 传 full_cmdline=args(不含 "pe " 前缀),
|
||||
所以串口回显为 "[cmd] cmdline: HELLO64.EXE" 而不是 "pe HELLO64.EXE"。
|
||||
|
||||
WHPX 已知问题:pe_service 为原生 PE32+ 执行写 CR4 启用 SSE 后,
|
||||
WHPX 可能以 "Unexpected VP exit code 4" 提前终止 QEMU(WHPX 平台限制,
|
||||
非 guest 崩溃)。任一会话在 WHPX 下未命中锚点时自动以 -Accel tcg 重跑
|
||||
(可用 -Accel tcg 直接指定跳过 WHPX)。
|
||||
|
||||
peinfo / 无参用法提示只写帧缓冲(cmd 非 dev_mode 无串口镜像),标 MANUAL。
|
||||
|
||||
退出码:全部通过 0,任一 FAIL 1。
|
||||
#>
|
||||
param([switch]$Build)
|
||||
param(
|
||||
[switch]$Build,
|
||||
[string]$Accel = 'whpx'
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
. (Join-Path $PSScriptRoot 'lib\QemuTest.ps1')
|
||||
|
||||
Initialize-QemuTest -Build:$Build
|
||||
$result = New-TestCaseResult 'pe-compat'
|
||||
|
||||
Set-DeshabFirstInit -First 1 -DevMode 0
|
||||
Set-DeshabAutoexec -Lines @('pe HELLO64.EXE', 'pe HELLO32.EXE', 'pe NONEXIST.EXE', 'exit')
|
||||
# ----------------------------------------------------------------
|
||||
# 单会话执行一轮 AUTOEXEC:正常启动 → cmd → 命令序列 → 等锚点/会话结束
|
||||
# 填充 $script:RunLog / RunLogPath;返回命中的锚点或 $null。
|
||||
# ----------------------------------------------------------------
|
||||
$script:RunLog = ''
|
||||
$script:RunLogPath = ''
|
||||
function Invoke-PeSession {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$Name,
|
||||
[Parameter(Mandatory)][string]$AccelMode,
|
||||
[Parameter(Mandatory)][string[]]$Autoexec,
|
||||
[Parameter(Mandatory)][string[]]$Anchors
|
||||
)
|
||||
Set-DeshabFirstInit -First 1 -DevMode 0
|
||||
Set-DeshabAutoexec -Lines $Autoexec
|
||||
|
||||
$s = Start-QemuSession -Name 'pe-compat'
|
||||
$timeout = 150
|
||||
if ($AccelMode -eq 'tcg') { $timeout = 360 } # TCG 全模拟显著更慢
|
||||
$s = Start-QemuSession -Name "$Name-$AccelMode" -Accel $AccelMode -MonitorPort 45504
|
||||
try {
|
||||
$hit = Wait-QemuLog -Session $s -Patterns $Anchors -TimeoutSeconds $timeout
|
||||
Start-Sleep -Seconds 2
|
||||
$script:RunLog = Read-QemuLogText $s.LogPath
|
||||
$script:RunLogPath = $s.LogPath
|
||||
return $hit
|
||||
} finally {
|
||||
Stop-QemuSession $s
|
||||
}
|
||||
}
|
||||
|
||||
# WHPX 未命中锚点 → TCG 兜底重跑一轮
|
||||
function Invoke-PeSessionWithFallback {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$Name,
|
||||
[Parameter(Mandatory)][string[]]$Autoexec,
|
||||
[Parameter(Mandatory)][string[]]$Anchors
|
||||
)
|
||||
$hit = Invoke-PeSession -Name $Name -AccelMode $Accel -Autoexec $Autoexec -Anchors $Anchors
|
||||
if (-not $hit -and $Accel -eq 'whpx') {
|
||||
$why = 'WHPX 下未命中锚点'
|
||||
if ($script:RunLog.Contains('WHPX: Unexpected VP exit')) { $why = 'WHPX 在 PE 执行处终止 QEMU(Unexpected VP exit,WHPX 平台限制)' }
|
||||
Add-TestNote $result "${Name}: $why,自动以 TCG 重跑"
|
||||
$script:UsedAccel = 'tcg'
|
||||
$hit = Invoke-PeSession -Name $Name -AccelMode 'tcg' -Autoexec $Autoexec -Anchors $Anchors
|
||||
}
|
||||
return $hit
|
||||
}
|
||||
|
||||
$script:UsedAccel = $Accel
|
||||
try {
|
||||
$hit = Wait-QemuLog -Session $s -Patterns @('[DSK] cmd.elf returned') -TimeoutSeconds 180
|
||||
Start-Sleep -Seconds 2
|
||||
$log = Read-QemuLogText $s.LogPath
|
||||
$result.LogPath = $s.LogPath
|
||||
# ================================================================
|
||||
# 会话 A:B2.1 PE32+ 原生加载执行(BUG-006 已修复,ExitProcess 干净返航)
|
||||
# ================================================================
|
||||
$hitA = Invoke-PeSessionWithFallback -Name 'pe64' -Autoexec @('pe HELLO64.EXE') -Anchors @('Hello from PE32+!', '[PANIC]')
|
||||
$logA = $script:RunLog
|
||||
$result.LogPath = $script:RunLogPath
|
||||
|
||||
# ---- B2.1 PE32+ 加载执行 ----
|
||||
Assert-QemuLog $result $log -Ordered @(
|
||||
Assert-QemuLog $result $logA -Ordered @(
|
||||
'[cmd] running AUTOEXEC.BAT',
|
||||
'[cmd] PE run begin',
|
||||
'[cmd] cmdline: pe HELLO64.EXE',
|
||||
'[cmd] cmdline: HELLO64.EXE',
|
||||
'[PE] PE32+ (64-bit)',
|
||||
'[PE] running PE32+ natively',
|
||||
'Hello from PE32+!',
|
||||
'[cmd] PE run end'
|
||||
'Hello from PE32+!'
|
||||
) -MustNotContain @('[PANIC]')
|
||||
|
||||
# ---- ABI 验证:cmd 启动时 ctx->reserved[4] + PE_SERVICE_MAGIC 校验 ----
|
||||
Assert-QemuLog $result $logA -MustContain @('[cmd] PE service ok')
|
||||
|
||||
# ---- B2.6 ExitProcess 返回链:BUG-006 已修复,转硬断言(回归守护) ----
|
||||
if ($logA.Contains('[cmd] PE run end')) {
|
||||
Add-TestCheck $result 'B2.6: ExitProcess 后 cmd 继续(PE32+ 返回链)' 'PASS'
|
||||
} else {
|
||||
Add-TestCheck $result 'B2.6: ExitProcess 后 cmd 继续(PE32+ 返回链)' 'FAIL' 'missing [cmd] PE run end(BUG-20260801-006 回归?)'
|
||||
}
|
||||
|
||||
# ================================================================
|
||||
# 会话 B:B2.2 PE32 x86emu32 解释执行(BUG-007 已修复,shim 指针转换)
|
||||
# ================================================================
|
||||
$hitB = Invoke-PeSessionWithFallback -Name 'pe32' -Autoexec @('pe HELLO32.EXE') -Anchors @('Hello from PE32!', '[PANIC]', '[PE32] emulator error')
|
||||
$logB = $script:RunLog
|
||||
|
||||
Assert-QemuLog $result $logB -Ordered @(
|
||||
'[cmd] PE run begin',
|
||||
'[cmd] cmdline: HELLO32.EXE',
|
||||
'[PE] running PE32 via x86emu32'
|
||||
) -MustNotContain @(
|
||||
'[PANIC]',
|
||||
'[PE32] emulator error',
|
||||
'[PE32] emu init failed',
|
||||
'[PE] unimplemented import',
|
||||
'[PE32] unimplemented import',
|
||||
'[PE] unimplemented API called'
|
||||
)
|
||||
|
||||
# ---- B2.2 PE32 解释器执行 ----
|
||||
Assert-QemuLog $result $log -Ordered @(
|
||||
'Hello from PE32+!',
|
||||
'[cmd] cmdline: pe HELLO32.EXE',
|
||||
'[PE] running PE32 via x86emu32',
|
||||
'Hello from PE32!',
|
||||
'[cmd] PE run end'
|
||||
# ---- B2.2 shim 输出:BUG-007 已修复,转硬断言(回归守护) ----
|
||||
if ($logB.Contains('Hello from PE32!')) {
|
||||
Add-TestCheck $result 'B2.2: PE32 解释执行 shim 输出' 'PASS'
|
||||
} else {
|
||||
Add-TestCheck $result 'B2.2: PE32 解释执行 shim 输出' 'FAIL' 'missing Hello from PE32!(BUG-20260801-007 回归?)'
|
||||
}
|
||||
|
||||
# ================================================================
|
||||
# 会话 D:BUG-20260801-005 验收 — DSK 阶段故意 #PF 必须打出完整异常现场
|
||||
# FAULT64.EXE: movabs rax,0x400000000000 ; mov [rax],1 ; jmp $
|
||||
# 预期 vector=0xe / err=0x2(supervisor write non-present) /
|
||||
# cr2=0x0000400000000000;修复前 halt_all 静默吞掉零日志。
|
||||
# 异常后 idt_handler 安全停机(hlt 循环),QEMU 存活 → 锚点命中即返回。
|
||||
# 若异常投递失效则三重故障 → -no-reboot QEMU 退出 → hit=$null → FAIL。
|
||||
# ================================================================
|
||||
$hitD = Invoke-PeSessionWithFallback -Name 'fault64' -Autoexec @('pe FAULT64.EXE') -Anchors @('[IDT] exception', '[PANIC]')
|
||||
$logD = $script:RunLog
|
||||
|
||||
if (-not $hitD) {
|
||||
Add-TestCheck $result 'BUG-005: DSK 阶段 #PF 异常投递' 'FAIL' 'session exited without [IDT] exception(异常被吞/三重故障)'
|
||||
} else {
|
||||
Add-TestCheck $result 'BUG-005: DSK 阶段 #PF 异常投递' 'PASS'
|
||||
}
|
||||
Assert-QemuLog $result $logD -Ordered @(
|
||||
'[cmd] cmdline: FAULT64.EXE',
|
||||
'[PE] running PE32+ natively',
|
||||
'[IDT] exception',
|
||||
'[IDT] vector=0x000000000000000e',
|
||||
'[IDT] err=0x0000000000000002',
|
||||
'[IDT] cr2=0x0000400000000000'
|
||||
)
|
||||
|
||||
# ---- B2.4 文件不存在错误路径:NONEXIST 不得产生 PE run begin ----
|
||||
Assert-QemuLog $result $log -MustNotContain @('[cmd] cmdline: pe NONEXIST.EXE')
|
||||
# 恰好两次 PE 执行(HELLO64 + HELLO32)
|
||||
Assert-QemuLog $result $log -CountPattern '[cmd] PE run begin' -MinCount 2
|
||||
# ================================================================
|
||||
# 会话 C:B2.4 文件不存在错误路径 + cmd exit 正常返回 DSK
|
||||
# ================================================================
|
||||
$hitC = Invoke-PeSessionWithFallback -Name 'peerr' -Autoexec @('pe NONEXIST.EXE', 'exit') -Anchors @('[DSK] cmd.elf returned', '[PANIC]')
|
||||
$logC = $script:RunLog
|
||||
|
||||
# ---- B2.6 ExitProcess 返回:cmd 接管继续执行后续命令并最终返回 DSK ----
|
||||
if ($hit) { Add-TestCheck $result 'B2.6: ExitProcess 后 cmd 返回 DSK' 'PASS' }
|
||||
else { Add-TestCheck $result 'B2.6: ExitProcess 后 cmd 返回 DSK' 'FAIL' 'missing [DSK] cmd.elf returned' }
|
||||
# NONEXIST 不得进入 PE 执行路径
|
||||
if ($logC.Contains('[cmd] cmdline: NONEXIST.EXE') -or $logC.Contains('[cmd] PE run begin')) {
|
||||
Add-TestCheck $result 'B2.4: NONEXIST.EXE 不进入 PE 执行路径' 'FAIL' 'unexpected PE run begin / cmdline echo'
|
||||
} else {
|
||||
Add-TestCheck $result 'B2.4: NONEXIST.EXE 不进入 PE 执行路径' 'PASS'
|
||||
}
|
||||
Assert-QemuLog $result $logC -MustNotContain @('[PANIC]')
|
||||
|
||||
# ---- ABI 验证(源码级,日志侧证) ----
|
||||
Assert-QemuLog $result $log -MustContain @('[cmd] PE service ok') # ctx->reserved[4] + PE_SERVICE_MAGIC 校验通过
|
||||
if ($hitC -eq '[DSK] cmd.elf returned') {
|
||||
Add-TestCheck $result '链路: cmd exit 正常返回 DSK' 'PASS'
|
||||
} else {
|
||||
Add-TestCheck $result '链路: cmd exit 正常返回 DSK' 'FAIL' "hit=$hitC(missing [DSK] cmd.elf returned)"
|
||||
}
|
||||
|
||||
Add-TestNote $result "加速方案: $script:UsedAccel"
|
||||
Add-TestNote $result 'BUG-006/007 已修复,返回链断言已转硬断言;会话仍按故障域拆分(单会话全序列合并留作后续优化)'
|
||||
|
||||
# ---- 帧缓冲限定项(无串口输出,标 MANUAL) ----
|
||||
Add-TestCheck $result 'B2.3: peinfo HELLO64.EXE 头解析' 'MANUAL' 'peinfo 输出仅帧缓冲(cmd 非 dev_mode 无串口镜像),手动验证 Machine: 0x8664'
|
||||
Add-TestCheck $result 'B2.7: peinfo HELLO32.EXE 头解析' 'MANUAL' '同上,预期 Machine: 0x14c / image_base=0x400000'
|
||||
Add-TestCheck $result 'B2.5: pe 无参用法提示' 'MANUAL' '用法提示仅帧缓冲输出'
|
||||
|
||||
Assert-QemuLog $result $log -MustNotContain @('[PANIC]')
|
||||
} finally {
|
||||
Stop-QemuSession $s
|
||||
Restore-DeshabScenario
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user