From 1c99c77b3f6b04d0c9f53a62d66bff15deeac200 Mon Sep 17 00:00:00 2001 From: boonxiong2 <16048561@qq.com> Date: Mon, 5 Oct 2026 14:03:39 +0800 Subject: [PATCH 1/4] fix(build): make the packed image actually bootable There were three independent reasons a fresh build produced an image that OVMF would not boot. All three are fixed here; verified by booting the resulting ISO/deshab-dev.img under QEMU/OVMF through to FirstInit. 1. ESP rejected by OVMF (CODE/linux/pack_system_image.sh) The vfat formatter was invoked with an explicit -s 8, forcing 4KiB clusters. On the 256MiB ESP that yields exactly 65535 clusters - the FAT32 0xFFF5 boundary - and OVMF's FatPkg refuses to mount the volume. Symptom: BdsDxe logs "failed to load ... Not Found", the ESP shows up as BLKn with no FS in the UEFI Shell, and the firmware falls through to the internal shell. The sidecar FAT32 image (make_sata_sidecar.sh) mounts fine because it calls the formatter without -s. Drop -s here too and let the tool pick geometry. Do NOT add -f 1: OVMF mounts nfat=1 and nfat=2 alike, it was not the cause. 2. Limine dropped into a panic (CODE/linux/pack_system_image.sh) limine.conf declares the Linux-compat guest modules. build.sh uncomments them once Linux has been built, but nothing ever comments them back, so the file says "load boot():/boot/linux-initrd.img" while only linux-bzImage exists on disk - Limine panics on the missing module and never reaches the kernel. Filter the guest module_path lines against SYSTEM/boot/ at pack time and write the result to the ESP. Both the root /limine.conf and /limine/limine.conf are written, since Limine 10 prefers the latter. The tracked source file is left untouched. 3. Nine drivers were never compiled (build.ps1) Commit 055c521 untracked the .drv binaries on the grounds that they are regenerable, but build.ps1 only ever invoked Build-DkmDriver for 8 of the 17 drivers listed in manifest.json. timer/acpi/pci/ahci/bootfs/vfs/fat32/ devfs/ps2kbd had sources under CODE/DKM/ and no build step, so the image shipped without them and Limine failed on the first one. Add the missing compile steps, grouped by load stage. All 17 now match manifest.json. Also in this commit (environment/tooling hygiene): - check_env.sh: stop hardcoding /mnt/d/Code/Deshab (the original author's machine); derive the repo root from the script's own location. It was reporting a bogus "wsl_mount" failure on every other checkout and sending people to install packages that were already present. Also check and advertise the image-packing tools (dosfstools/e2fsprogs/fdisk/rsync), which were missing from the dependency list even though pack_system_image.sh hard-requires them. - build_initrd.sh: same hardcoded-path fix. - README.md: relative path instead of the stale absolute one. Verified: ./build.bat -Variant dev under WSL2/Ubuntu, then QEMU/OVMF boots through BdsDxe -> Limine -> UTSM -> DKM (17/17) -> DSK -> FirstInit, with the PS/2 mouse initialising cleanly. --- CODE/linux/README.md | 4 +- CODE/linux/build_initrd.sh | 5 ++- CODE/linux/check_env.sh | 33 ++++++++++++---- CODE/linux/pack_system_image.sh | 67 +++++++++++++++++++++++++++++---- build.ps1 | 20 ++++++++++ 5 files changed, 109 insertions(+), 20 deletions(-) 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/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" From 845a8f0203cdba75c88301e8be158c0bd95ccdb7 Mon Sep 17 00:00:00 2001 From: boonxiong2 <16048561@qq.com> Date: Mon, 5 Oct 2026 14:05:27 +0800 Subject: [PATCH 2/4] chore(git): pin *.sh to LF via .gitattributes Shell scripts are run by bash (WSL/Linux/CI). With core.autocrlf=true the working tree gets CRLF, and bash then fails on the stray CR: the packing step of build.bat died with pack_system_image.sh: line 13: $'\r': command not found pack_system_image.sh: line 14: set: pipefail\r: invalid option name core.autocrlf is a per-clone setting and is not shared, so the only reliable fix is a repository-level attribute. Pin *.sh to LF for every checkout. --- .gitattributes | 7 +++++++ 1 file changed, 7 insertions(+) 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 From cf395474bf42aaf0220c7f945de87efaa543c1f1 Mon Sep 17 00:00:00 2001 From: boonxiong2 <16048561@qq.com> Date: Mon, 5 Oct 2026 14:09:19 +0800 Subject: [PATCH 3/4] docs(status): correct stale subsystem states against the source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit STATUS.md/TASKBOARD.md under-reported several subsystems that are in fact implemented. Corrected against the code and against a clean QEMU boot log (.build_tmp/qemu_final.log, this branch). - 页表映射接口 was ⬜ "mmio 通用映射待做". It exists and is in use: kernel_api.mm_map_mmio / mm_unmap_mmio (PCD|PWT independent window), called by apic, ehci, xhci and nvme, including BARs above 4G. -> ✅ - NVMe was 🔶 "PCI discovery only, BAR0>4G 待映射". CODE/DKM/nvme/nvme.c is 1641 lines: admin SQ/CQ with phase bit, IDENTIFY, IO queue (qid=1), read/ write/flush, cross-page PRP lists, MSI and MSI-X (vector allocator, IDT pool 0x40-0xDF), block provider registration, NVME-E01..E03 zero-fallback instrumentation. -> ✅ - virtio_net was 🔶 "PCI/capability 枚举, 无 virtqueue". It has a legacy split-ring virtqueue (desc/avail/used), vq_setup, 32x2048B RX buffers, TX/RX rings and a DHCP DISCOVER->OFFER selftest. -> ✅ - ELF64 .drv loading said 14/14. build.ps1 now compiles all 17 drivers listed in manifest.json (fixed on this branch; nine were never built since 055c521 untracked the .drv binaries). -> 17/17 - FAT32 (DKM side) stays 🔶 but the boundary was wrong. It is read-only BPB/FAT/dirent parsing plus a root-directory walk, with no filesystem API layer (no open/read/stat) - not "子目录路径待完善". The large-disk read/write path lives in the DSK-side FAT32 implementation. - TASKBOARD 遗留工程债: vector allocator/MSI-X, NVMe high BAR MMIO and virtio-net virtqueue RX/TX are done. The remaining FAT32 item is reworded to what is actually missing (the FS API layer). Evidence for the driver/NVMe/virtio rows is the boot log on this branch: 14x "[] driver ready", and with no NVMe controller / virtio-net device attached the drivers correctly log a warning and still reach "driver ready" (designed fallback, both listed in the CLAUDE.md whitelist). --- docs/STATUS.md | 10 +++++----- docs/TASKBOARD.md | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) 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 头 From 240daa34095aec18758bac51186b72d4bfa018b2 Mon Sep 17 00:00:00 2001 From: boonxiong2 <16048561@qq.com> Date: Mon, 5 Oct 2026 14:54:25 +0800 Subject: [PATCH 4/4] docs(lessons): record the three causes of "build succeeds, image won't boot" Covers the ESP FAT geometry vs OVMF FatPkg, the limine.conf guest module drift, and the nine drivers that 055c521 untracked without a build step that could regenerate them. Also the autocrlf/.gitattributes conclusion and the check_env.sh hardcoded-path trap. --- LESSONS_LEARNED.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) 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` 读入即可绕开。