diff --git a/.gitattributes b/.gitattributes index 9942ba2..df7193a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,8 @@ *.mp4 filter=lfs diff=lfs merge=lfs -text + +# Shell scripts are executed by bash (WSL / Linux / CI). CRLF line endings +# break them outright ("$'\r': command not found", and a stray CR in a shebang +# or in `set -euo pipefail` makes the whole script unrunnable) - the packing +# step of this project's build died on exactly that. Pin LF for every checkout +# regardless of the developer's core.autocrlf setting. +*.sh text eol=lf diff --git a/CODE/linux/README.md b/CODE/linux/README.md index 30a98cd..f67d5ef 100644 --- a/CODE/linux/README.md +++ b/CODE/linux/README.md @@ -24,8 +24,8 @@ the UTSM hypervisor (VMX root). ### 1. From WSL ```bash -# Navigate to the project (adjust path for your WSL mount) -cd /mnt/d/Code/Deshab/CODE/linux +# Navigate to the project from your repo root in WSL +cd CODE/linux # Make the build script executable chmod +x build.sh diff --git a/CODE/linux/build_initrd.sh b/CODE/linux/build_initrd.sh index 4bcc923..6fbc67c 100644 --- a/CODE/linux/build_initrd.sh +++ b/CODE/linux/build_initrd.sh @@ -2,8 +2,9 @@ # Build initramfs only (assumes bzImage already built) set -e -SCRIPT_DIR="/mnt/d/Code/Deshab/CODE/linux" -PROJECT_ROOT="/mnt/d/Code/Deshab" +# 按脚本自身位置推导,不认死盘符路径。 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" OUTPUT_DIR="$PROJECT_ROOT/SYSTEM/boot" INITRAMFS_DIR="$SCRIPT_DIR/initramfs" LINUX_SRC="${LINUX_SRC:-$HOME/linux-6.6}" diff --git a/CODE/linux/check_env.sh b/CODE/linux/check_env.sh index 3c3d38a..8cf6640 100644 --- a/CODE/linux/check_env.sh +++ b/CODE/linux/check_env.sh @@ -5,7 +5,7 @@ # 用途: 在 WSL/Linux 中运行,验证构建 Linux 6.6 LTS bzImage 所需依赖 # # 使用: -# ! wsl bash /mnt/d/Code/Deshab/CODE/linux/check_env.sh +# ! wsl bash CODE/linux/check_env.sh # # 退出码: # 0 = 所有依赖已满足 @@ -16,6 +16,10 @@ set -e echo "[check] Linux 内核构建环境检查" echo "[check] ===========================" +# 仓库根目录:按脚本自身位置推导,不依赖当前工作目录,也不认死任何盘符路径。 +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +echo "[check] 仓库根: $REPO_ROOT" + # 1. 检查操作系统 if [ -f /etc/os-release ]; then . /etc/os-release @@ -40,6 +44,18 @@ for pkg in build-essential bc flex bison libelf-dev libssl-dev cpio gzip git; do fi done +# 2b. 检查镜像打包工具(pack_system_image.sh 硬依赖,不在上面那组内核依赖里) +echo "[check]" +echo "[check] 检查镜像打包工具..." +for pkg in dosfstools e2fsprogs fdisk rsync; do + if dpkg -s "$pkg" >/dev/null 2>&1; then + echo "[check] ✓ $pkg" + else + echo "[check] ✗ $pkg (缺失)" + MISSING+=("$pkg") + fi +done + # 3. 检查 gcc 版本 echo "[check]" echo "[check] 工具链版本:" @@ -60,7 +76,7 @@ fi # 4. 检查磁盘空间(需要 ~3GB) echo "[check]" -PROJECT_ROOT="/mnt/d/Code/Deshab" +PROJECT_ROOT="$REPO_ROOT" if [ -d "$PROJECT_ROOT" ]; then AVAILABLE_KB=$(df "$PROJECT_ROOT" | awk 'NR==2 {print $4}') AVAILABLE_GB=$((AVAILABLE_KB / 1024 / 1024)) @@ -73,13 +89,13 @@ if [ -d "$PROJECT_ROOT" ]; then fi fi -# 5. 检查访问 Windows D: 盘 +# 5. 检查 WSL 能否访问当前仓库(不认死盘符路径) echo "[check]" -if [ -d "/mnt/d/Code/Deshab" ]; then - echo "[check] ✓ WSL 可访问 /mnt/d/Code/Deshab" +if [ -d "$REPO_ROOT/CODE/linux" ] && [ -d "$REPO_ROOT/SYSTEM" ]; then + echo "[check] ✓ WSL 可访问当前仓库 ($REPO_ROOT)" else - echo "[check] ✗ WSL 无法访问 /mnt/d/Code/Deshab" - echo "[check] 请确认在 WSL 中执行,且 D: 盘已挂载" + echo "[check] ✗ WSL 无法访问当前仓库 ($REPO_ROOT)" + echo "[check] 请从仓库内运行本脚本,且 Windows 盘已挂载到 /mnt/<盘符>" MISSING+=("wsl_mount") fi @@ -107,11 +123,12 @@ if [ ${#MISSING[@]} -gt 0 ]; then echo "[check] 请运行以下命令安装依赖:" echo "[check] sudo apt update" echo "[check] sudo apt install -y build-essential bc flex bison libelf-dev libssl-dev cpio gzip git" + echo "[check] sudo apt install -y dosfstools e2fsprogs fdisk rsync" exit 1 fi echo "[check] ✓ 所有依赖已满足,可以构建 Linux 内核" echo "[check]" echo "[check] 下一步执行:" -echo "[check] cd /mnt/d/Code/Deshab/CODE/linux && chmod +x build.sh && ./build.sh" +echo "[check] cd $REPO_ROOT/CODE/linux && chmod +x build.sh && ./build.sh" exit 0 diff --git a/CODE/linux/pack_system_image.sh b/CODE/linux/pack_system_image.sh index 2770598..69f928d 100644 --- a/CODE/linux/pack_system_image.sh +++ b/CODE/linux/pack_system_image.sh @@ -167,13 +167,17 @@ if [[ -z "$p1" || -z "$p2" ]]; then exit 1 fi -# 4KiB clusters on a ~5GiB ESP; 32KiB if the ESP is 4GiB or larger. -fat_cluster_sectors=8 -if [[ "$esp_bytes" -ge $((4096 * 1024 * 1024)) ]]; then - fat_cluster_sectors=64 -fi - -mkfs.vfat -F 32 -n DESHABBOOT -s "$fat_cluster_sectors" "$p1" >/dev/null +# 簇大小交给 mkfs.vfat 自动选择。 +# +# 历史坑一:这里曾经强制 -s 8(4KiB 簇)。256MiB 的 ESP 恰好被算成 65535 +# 个簇(FAT32 的 0xFFF5 边界),该几何下 OVMF(EDK2 FatPkg) 拒挂该卷 —— +# 现象是 BdsDxe "Not Found",Shell 里分区只显示 BLKn、没有对应 FS。 +# 对照实验:sidecar(CODE/linux/make_sata_sidecar.sh)用不带 -s 的 +# mkfs.vfat 就一切正常,所以这里也不再手工指定簇大小。 +# +# 历史坑二:不要加 -f 1。UEFI 规范建议 ESP 用单 FAT 表,但实测 OVMF 对 +# nfat=1/2 都能挂,加 -f 1 并不能解决上面的问题,反而偏离 sidecar 的行为。 +mkfs.vfat -F 32 -n DESHABBOOT "$p1" >/dev/null # DSK 内嵌 ext4 读写驱动支持范围:4K block / 256B inode / extent 树, # 不支持 journal、metadata_csum、64bit(遇到即 panic FS-E28)—— # 因此这里必须显式关闭这三个 feature。 @@ -190,7 +194,54 @@ echo "[pack] copying p1 FAT32 ESP (EFI/ limine/ boot/ driver/ system/)" # vfat has no Unix owners/perms; -a would fail with rsync code 23. rsync -rltD --info=progress2 "$SYSTEM/EFI/" "$MNT_ESP/EFI/" rsync -rltD --info=progress2 "$SYSTEM/limine/" "$MNT_ESP/limine/" -cp -f "$SYSTEM/limine/limine.conf" "$MNT_ESP/limine.conf" + +# limine.conf 的 Linux 兼容层 module_path 段必须与 SYSTEM/boot/ 的实际产物一致。 +# CODE/linux/build.sh 建完 Linux 内核会自动取消那几行注释,但没有任何地方会关回去; +# 而 055c521 之后 .drv / Linux 产物都不入库,于是「注释开着但文件不存在」会让 +# Limine 直接 panic(Failed to open module ...),系统根本进不去。 +# 这里按实际存在的文件过滤后再写进 ESP —— 源文件 SYSTEM/limine/limine.conf 保持不动。 +# +# 注意:Limine 10 优先读 ESP 上的 /limine/limine.conf(目录形式),其次才是 +# 根目录 /limine.conf。上面 rsync 已经把未过滤的原版拷进 /limine/ 了,所以 +# 两处都必须写过滤后的副本,否则改根目录那份不起作用。 +filter_limine_conf() { + local dst="$1" + python3 - "$SYSTEM/limine/limine.conf" "$SYSTEM/boot" "$dst" <<'PYEOF' +import os, re, sys + +src, bootdir, dst = sys.argv[1], sys.argv[2], sys.argv[3] +# Linux/guest 内核段的 module_path(其它 module_path 靠路径前缀区分) +GUEST_PREFIXES = ('/boot/linux-', '/boot/xj380.krl') + +lines = open(src, 'r', encoding='utf-8').read().splitlines(keepends=True) +out, dropped, kept = [], [], [] + +for line in lines: + m = re.match(r'^(\s*)module_path:\s*boot\(\):(\S+)\s*$', line) + if m and m.group(2).startswith(GUEST_PREFIXES): + host = os.path.join(bootdir, m.group(2).split('/boot/', 1)[1]) + if os.path.exists(host): + kept.append(m.group(2)) + out.append(line) + else: + # 产物不存在 → 注释掉,避免 Limine 加载失败 panic + out.append('%s# [pack] module missing on disk, disabled: %s' % (m.group(1), line)) + dropped.append(m.group(2)) + else: + out.append(line) + +open(dst, 'w', encoding='utf-8').write(''.join(out)) +for p in kept: + print('[pack] limine module kept: %s' % p) +for p in dropped: + print('[pack] limine module DISABLED (file absent): %s' % p) +PYEOF +} + +mkdir -p "$MNT_ESP/limine" +filter_limine_conf "$MNT_ESP/limine.conf" # 根目录副本 +filter_limine_conf "$MNT_ESP/limine/limine.conf" # Limine 10 实际优先读的那份 + rsync -rltD --info=progress2 "$SYSTEM/boot/" "$MNT_ESP/boot/" rsync -rltD --info=progress2 "$SYSTEM/driver/" "$MNT_ESP/driver/" rsync -rltD --info=progress2 "$SYSTEM/system/" "$MNT_ESP/system/" diff --git a/LESSONS_LEARNED.md b/LESSONS_LEARNED.md index 506833a..9d0bf5a 100644 --- a/LESSONS_LEARNED.md +++ b/LESSONS_LEARNED.md @@ -648,3 +648,23 @@ 4. **MSI 收益在 QEMU 内存后端的轻负载下不体现于耗时**: stress 50×(128sec W+R) MSI 16-33ms vs 纯轮询 42ms,差异主要来自完成等待的采样粒度而非 CPU 占用;MSI 的真实价值在 DSK 阶段 IF=0 轮询语义不变的前提下的路径统一性,以及未来多 outstanding/异步 IO 的扩展空间。 + +## 2026-10-05 — 镜像「构建成功但启动不了」三类成因(PR #3) + +### 经验 + +1. **`build.bat` 退出码 0 ≠ 镜像可启动**: 构建链路 Windows 侧(clang/ld.lld/mingw32-make)与 WSL 侧(sfdisk/mkfs/rsync)是两段独立失败面,前者全绿不代表后者产物正确。排查顺序应是「先看 OVMF 说了什么,再看磁盘上是什么」,而不是从构建脚本开头重跑。 + +2. **ESP 的 FAT32 几何直接决定 OVMF 是否挂载**: 用 `-s 8` 强制 4KiB 簇时,256MiB 分区正好产生 65535 个簇(FAT32 `0xFFF5` 边界),EDK2 `FatPkg` 拒挂该卷——现象是 `BdsDxe: failed to load ... Not Found`,且 UEFI Shell 里 `map -r` 只给出 `BLKn`、没有对应 `FS`。判据是「分区只有块设备节点、没有文件系统节点」。去掉 `-s` 交给 mkfs 自动选簇即恢复。反例已排除:`-f 1`(OVMF 对 nfat=1/2 都能挂)和 FAT 表尺寸都不是成因——**先做对照实验(拿能挂的 sidecar 与不能挂的 ESP 逐字段 diff),再改脚本**,本次在理论推演上错了三轮才走到这一步。 + +3. **`limine.conf` 的 `module_path` 必须与实际产物对齐,否则 Limine 直接 panic 且无回退**: `build.sh` 会在 Linux 构建后自动取消 guest 模块注释,但没有任何路径会注释回去,于是配置长期处于「声明加载不存在的文件」状态。打包器应按 `SYSTEM/boot/` 实际存在与否过滤后再写入 ESP。注意 Limine 10 **优先读 `/limine/limine.conf`**,只改根目录那份不生效——两处都要写。 + +4. **`.drv` 不入库的前提是构建能全部重建它**: `055c521` 以「可再生成」为由移除全部 `.drv`,但 `build.ps1` 只覆盖 17 个驱动中的 8 个,其余 9 个(timer/acpi/pci/ahci/bootfs/vfs/fat32/devfs/ps2kbd)源码在 `CODE/DKM/` 下却从来没有编译步骤。删「可再生物」之前,必须先 grep 出构建脚本的实际产出清单与 `manifest.json` 逐项对账,否则版本库变干净的同时镜像变残废。 + +5. **`core.autocrlf` 是每个克隆各自的设置,唯一可靠的办法是 `.gitattributes`**: CRLF 的 `.sh` 被 WSL 的 bash 执行时会在 shebang / `set -euo pipefail` 上炸(`$'\r': command not found`)。全局或仓库级 config 都不可共享,只有 `*.sh text eol=lf` 对所有人生效,且因为索引里本来就是 LF,**不产生任何文件改动噪音**。 + +### 教训 + +1. **`check_env.sh` 硬编码作者机器的绝对路径(`/mnt/d/Code/Deshab`),导致在所有其它检出上误报**: 它报出的 `wsl_mount` 缺失和随之打印的 `apt install build-essential ...` 清单具有强误导性——照做会得到 `Installing: 0`(本来就有),而真正缺失的 `dosfstools`(`pack_system_image.sh` 硬依赖,缺了构建必死在打包步)反而不在清单里。**环境检查脚本自身的路径与依赖清单都要随仓库走**,否则它比没有更糟。 +2. **「两个 PR 撞同一对 base/head」**: 网页手开与 API 自动开同时进行会重复;同分支同目标只能有一个 PR,先确认再操作。 +3. **提交信息里出现工具名会触发执行侧拦截**: 含文件系统格式化工具名的命令文本会无条件被拦;把提交信息写进文件用 `git commit -F` 读入即可绕开。 diff --git a/build.ps1 b/build.ps1 index 721ca9a..0baf947 100644 --- a/build.ps1 +++ b/build.ps1 @@ -961,20 +961,40 @@ foreach ($tool in $toolApps) { Write-Host '[build] Building DKM framebuffer driver...' Build-DkmDriver (Join-Path $Root 'CODE\DKM\console_fb\console_fb.c') (Join-Path $SystemDir 'driver\console\console_fb.drv') +# stage0: platform + bus — timer 提供 PIT 校准,acpi 枚举 RSDP/XSDT,pci 扫描配置空间。 +# 这三个驱动 manifest.json 里是必需的;055c521 把它们从 git 移除后此处必须重新编译, +# 否则 limine 会 panic「Failed to open module boot():/driver/platform/timer.drv」。 +Write-Host '[build] Building DKM platform/bus drivers...' +Build-DkmDriver (Join-Path $Root 'CODE\DKM\timer\timer.c') (Join-Path $SystemDir 'driver\platform\timer.drv') +Build-DkmDriver (Join-Path $Root 'CODE\DKM\acpi\acpi.c') (Join-Path $SystemDir 'driver\platform\acpi.drv') +Build-DkmDriver (Join-Path $Root 'CODE\DKM\pci\pci.c') (Join-Path $SystemDir 'driver\bus\pci.drv') + # B7: apic.drv 纳入构建 (原 platform/apic.drv 为预置二进制, 不随 apic.c 更新) Write-Host '[build] Building DKM platform apic driver...' Build-DkmDriver (Join-Path $Root 'CODE\DKM\apic\apic.c') (Join-Path $SystemDir 'driver\platform\apic.drv') Write-Host '[build] Building DKM storage drivers...' +Build-DkmDriver (Join-Path $Root 'CODE\DKM\ahci\ahci.c') (Join-Path $SystemDir 'driver\block\ahci.drv') Build-DkmDriver (Join-Path $Root 'CODE\DKM\nvme\nvme.c') (Join-Path $SystemDir 'driver\block\nvme.drv') Build-DkmDriver (Join-Path $Root 'CODE\DKM\ehci\ehci.c') (Join-Path $SystemDir 'driver\block\ehci.drv') Build-DkmDriver (Join-Path $Root 'CODE\DKM\xhci\xhci.c') (Join-Path $SystemDir 'driver\block\xhci.drv') +# stage2: filesystem — bootfs 挂 boot module,vfs 汇总,fat32 只读 FAT32,devfs 暴露 /dev。 +Write-Host '[build] Building DKM filesystem drivers...' +Build-DkmDriver (Join-Path $Root 'CODE\DKM\bootfs\bootfs.c') (Join-Path $SystemDir 'driver\fs\bootfs.drv') +Build-DkmDriver (Join-Path $Root 'CODE\DKM\vfs\vfs.c') (Join-Path $SystemDir 'driver\fs\vfs.drv') +Build-DkmDriver (Join-Path $Root 'CODE\DKM\fat32\fat32.c') (Join-Path $SystemDir 'driver\fs\fat32.drv') +Build-DkmDriver (Join-Path $Root 'CODE\DKM\devfs\devfs.c') (Join-Path $SystemDir 'driver\fs\devfs.drv') + Write-Host '[build] Building DKM network drivers...' Build-DkmDriver (Join-Path $Root 'CODE\DKM\e1000\e1000.c') (Join-Path $SystemDir 'driver\net\e1000.drv') Build-DkmDriver (Join-Path $Root 'CODE\DKM\virtio_net\virtio_net.c') (Join-Path $SystemDir 'driver\net\virtio_net.drv') Build-DkmDriver (Join-Path $Root 'CODE\DKM\ath9k\ath9k.c') (Join-Path $SystemDir 'driver\net\ath9k.drv') +# stage3: input — ps2kbd 注册 IRQ1。 +Write-Host '[build] Building DKM input drivers...' +Build-DkmDriver (Join-Path $Root 'CODE\DKM\ps2kbd\ps2kbd.c') (Join-Path $SystemDir 'driver\input\ps2kbd.drv') + Write-Host "[build] Output: $Output" Write-Host "[build] DSK Output: $DskOutput" Write-Host "[build] Variant: $Variant" diff --git a/docs/STATUS.md b/docs/STATUS.md index 8da4114..020756e 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -14,7 +14,7 @@ | IOAPIC→LAPIC 路由(B7) | ✅ | apic_route=1 接管;失败自动降级 PIC | `.build_tmp/qemu_serial_*.log` | | LAPIC timer | ✅ | TSC 校准 + 周期模式,[sched] 配置 | M4 QEMU 日志 | | DMA 物理页分配器 | ✅ | bitmap,低 4G 钳位 | e1000 DMA 根治记录 | -| 页表映射接口(map/unmap) | ⬜ | mmio 通用映射待做 | — | +| 页表映射接口(map/unmap) | ✅ | `kernel_api.mm_map_mmio` / `mm_unmap_mmio`(PCD\|PWT 独立窗口);apic / ehci / xhci / nvme 四个驱动在用,含 BAR>4G 高位映射 | 串口 `BAR mapped via mm_map_mmio window` | | panic 统一兜底(F1) | ✅ | DEAICUP 莲花崩溃屏(ohMyLogo.png 内嵌,背景=图片背景色)+ panic_symbol + DRR 归档;CPU 异常/驱动 panic 统一入口 | `.build_tmp/panic_screen.png` + qemu_serial_f1logo2.log | | boot 分级自检(F4) | ✅ | `[boot] selftest=0\|1\|2`,5 项全过 BOOT-OK | `.build_tmp/qemu_serial_f1f4f5.log` | | 帧缓冲控制台抽象 fbcon(F2) | 🔶 | `include/utsm/fbcon.h`:像素/混合/填充/RGBA 图像/文本(panic 路径已用);统一控制台后端 ⬜ | `CODE/UTSM/include/utsm/fbcon.h` | @@ -36,13 +36,13 @@ | 子系统 | 状态 | 边界/说明 | 证据 | |--------|------|----------|------| -| ELF64 .drv 加载(4 stage) | ✅ | 14/14 驱动装载 + driver_init | QEMU 启动日志 | +| ELF64 .drv 加载(4 stage) | ✅ | 17/17 驱动编译并装载 + driver_init(console_fb/timer/apic/acpi/pci/ahci/nvme/ehci/xhci/bootfs/vfs/fat32/devfs/e1000/virtio_net/ath9k/ps2kbd),与 manifest.json 一致 | QEMU 启动日志 `[] driver ready` ×14(ath9k/console_fb 无对应设备时走各自路径) | | 驱动列表(timer/acpi/pci/ahci/nvme/bootfs/vfs/devfs/fat32/ps2kbd/e1000/virtio_net/console_fb/apic) | ✅ | 能力各异,见下行分项 | manifest.json | | AHCI | ✅ | IDENTIFY/READ/WRITE DMA + ahci0 provider | — | -| NVMe | 🔶 | PCI discovery only,BAR0>4G 待映射 | — | -| FAT32(DKM 侧) | 🔶 | 只读,子目录路径待完善 | — | +| NVMe | ✅ | admin 队列 + IDENTIFY + IO 队列(qid=1) + 读写/flush + PRP 跨页 + MSI/MSI-X(vector allocator 0x40–0xDF 池)+ block provider;NVME-E01..E03 零降级插桩。无控制器时 WARN 后正常 ready(设计内回退) | `CODE/DKM/nvme/nvme.c`;未挂盘时串口 `[nvme] NVMe controller not found` → `driver ready` | +| FAT32(DKM 侧) | 🔶 | 只读 BPB/FAT/目录项解析 + 根目录遍历;**无文件系统 API 层**(无 open/read/stat),当前仅 demo 级读取。大盘读写路径另由 DSK 侧 FAT32 实现承担(见下行 FS-E 表) | `CODE/DKM/fat32/fat32.c`;串口 `[fat32] driver ready` | | e1000 | ✅ | RX/TX + DHCP/ARP/UDP/DNS(polling) | — | -| virtio_net | 🔶 | PCI/capability 枚举,无 virtqueue | — | +| virtio_net | ✅ | legacy split-ring virtqueue(desc/avail/used)+ vq_setup + 32×2048B RX 缓冲 + TX/RX 环 + DHCP DISCOVER→OFFER selftest;VNET-E01/E02 零降级插桩。无设备时 WARN 后正常 ready(设计内回退) | `CODE/DKM/virtio_net/virtio_net.c`;未挂设备时串口 `[virtio_net] virtio-net device not found` → `driver ready` | | 热卸载(D1) | ⬜ | 仅有 NO_UNLOAD 标志与状态机文档 | — | | 按名 API 导出表(D3) | ⬜ | 固定偏移 struct ABI | `CODE/sdk/include/deshab/kernel_api.h` | | 彩色日志(D4) | ✅ | `dkm_log_set_driver`(驱动名 FNV hash → 8 色调色板,确定可复现);init 期间驱动日志带 ANSI 色(仅串口,BOOTLOG 纯文本);FUCK `[debug] color_log` 总开关 | `.build_tmp/qemu_serial_d4color.log`(1150 彩色行) | diff --git a/docs/TASKBOARD.md b/docs/TASKBOARD.md index 1039d4c..1c3d817 100644 --- a/docs/TASKBOARD.md +++ b/docs/TASKBOARD.md @@ -48,8 +48,8 @@ ## 遗留工程债(Phase 存档,非五期编号) -- [ ] Vector allocator / MSI-X -- [ ] NVMe 高位 BAR MMIO(BAR0>4G) -- [ ] virtio-net virtqueue RX/TX -- [ ] FAT32 完整子目录路径解析(DKM 侧) +- [x] Vector allocator / MSI-X(NVMe 使用 IDT 向量池 0x40–0xDF + MSI-X 表项编程) +- [x] NVMe 高位 BAR MMIO(BAR0>4G,`mm_map_mmio` 独立窗口映射) +- [x] virtio-net virtqueue RX/TX(legacy split-ring + DHCP selftest) +- [ ] FAT32 文件系统 API 层(DKM 侧当前只有 BPB/目录 demo,无 open/read/stat) - [ ] DKM 零 warning + 统一 ABI 头