Four independent blockers sat between "the image boots UTSM" and "the desktop
comes up". Each one wedged the boot on its own; all four are fixed here and the
tree now reaches "[desktop] desktop ready" under QEMU/OVMF
(evidence: .build_tmp/d2.log).
1. FirstInit made networking a hard gate (CODE/firstInit/main.c)
The setup wizard always showed the network page, and on a machine with no
wireless device the only exit was Save - pressing Connect raised NET-E01.
Networking is not a precondition for entering the system, so a wizard that
cannot be completed without it is a plain design defect.
- No wireless device detected -> skip the network page entirely (the
g_no_wireless_device flag already existed but was only logged).
- With a device present, add a Skip button (draw + mouse hit-box + keyboard
Enter), mirroring "I don't have internet" on Windows.
- Connect keeps its zero-fallback NET-E01 panic: the unimplemented path is
still honest, it just no longer holds the user hostage.
2. ESP cluster size left no room in the root directory
(CODE/linux/pack_system_image.sh)
With the cluster size left to mkfs it chose 1 sector, i.e. 16 directory
entries per cluster. The ESP root ends up holding exactly 16 entries
(DESHABBOOT/EFI/LIMINE/BOOT/DRIVER/SYSTEM/USER/NVVARS plus one long-name
entry each), and the root chain is a single cluster - so on first boot the
DSK could never write USER.CONF.
Pin -s 4 (2KiB, 64 entries): it clears the FAT32 65525 lower bound and the
0xFFF5 boundary that -s 8 lands on at this 256MiB size, and leaves 48 free
entries. The alternatives were measured, not guessed (see the comment).
3. DSK could not grow the root directory (CODE/dsk/main.c)
fat32_write_root_file returned -4 "no free dir entry" whenever the scan of
the root chain came up empty. A FAT filesystem is supposed to extend the
directory chain, so allocate a cluster, link it at the current tail, write
the entry there and commit the FAT. Fixing only (2) would have papered over
this: any real disk whose root fills up would still fail the same way.
4. Nothing generated the CJK bitmap font packs (build.ps1)
The desktop loads system/font/simhei_16.dbf and panics DESK-E04 FONT PACK
MISSING without it. The .dbf files are generated from simhei.ttf by
CODE/font/mkfont.py and are gitignored, but no build step ever invoked it -
same class of bug as the previously untracked .drv binaries. Generate
simhei_16.dbf / simhei_24.dbf in build.ps1 (with the existing WSL python3
fallback for Pillow), rebuilding only when the TTF is newer than the pack.
docs/STATUS.md updated to match: FirstInit wizard and the D3 named API export
table move to done, and the FAT32 / ESP cluster size / CJK font pack entries
are added or corrected. D3 was already fully implemented (table, lookup,
selftest with positive and negative cases, TST-E21..E24 instrumentation) -
only the status row was stale.
Verified boot chain (QEMU/OVMF, dev variant):
BdsDxe -> Limine -> UTSM -> DKM 17/17 -> DSK -> FirstInit (network page
skipped) -> USER.CONF written -> login (password accepted) -> desktop:
"[zhfont] dbf loaded (16px ok)" ... "[desktop] desktop ready"
Linux 6.6 LTS for UTSM Dual-Kernel Architecture
Overview
This directory contains the Linux 6.6 LTS configuration and build scripts for the UTSM + Linux dual-kernel architecture. Linux runs as a VMX non-root guest under the UTSM hypervisor (VMX root).
Prerequisites
- WSL (Windows Subsystem for Linux) with Ubuntu 22.04+ installed
wsl --install -d Ubuntu-22.04 - Build dependencies (inside WSL):
sudo apt update sudo apt install -y build-essential bc flex bison libelf-dev libssl-dev cpio gzip git - ~3GB free disk space
Building Linux
1. From WSL
# Navigate to the project from your repo root in WSL
cd CODE/linux
# Make the build script executable
chmod +x build.sh
# Run the build (clones Linux 6.6 LTS, configures, builds)
./build.sh
The build will:
- Clone Linux 6.6 LTS source to
CODE/linux/src/ - Apply UTSM patches from
CODE/linux/patches/(if any) - Configure with
configs/utsm_x86_64_defconfig - Build
bzImage - Copy to
SYSTEM/boot/linux-bzImage - Build initramfs if
CODE/linux/initramfs/exists
2. Enable in Limine
After building, uncomment the Linux module entries in SYSTEM/limine/limine.conf:
module_path: boot():/boot/linux-bzImage
module_cmdline: linux:bzImage
module_path: boot():/boot/linux-initrd.img
module_cmdline: linux:initrd
3. Rebuild the disk image
cd d:\Code\Deshab
.\build.bat
4. Test with QEMU
Note: VMX requires hardware virtualization support. QEMU's TCG (software emulation) does NOT support VMX instructions. To test the VMX path:
- Real hardware: Boot on an Intel machine with VT-x enabled in BIOS
- QEMU with WHPX:
qemu-system-x86_64 -accel whpx -cpu max(may not expose nested VMX to the guest) - QEMU with KVM (Linux host only):
qemu-system-x86_64 -enable-kvm -cpu host
Without VMX, UTSM gracefully falls back to the normal DSK boot flow.
Configuration Details
The utsm_x86_64_defconfig enables:
- 64-bit kernel with SMP support
- Serial console (8250/16550 at 0x3F8, 115200 baud)
- virtio: console, block, net, fs (for UTSM host backends)
- ext4, FAT, tmpfs, proc, sysfs filesystems
- No module loading (all drivers built-in for Phase 1)
- No EFI stub (UTSM uses custom VMX boot protocol)
- Debug info and printk timestamps
File Structure
CODE/linux/
├── configs/
│ └── utsm_x86_64_defconfig # Kernel configuration
├── patches/ # UTSM-specific kernel patches
│ ├── utsm-hcall.patch # /dev/utsm hypercall driver (Phase 1.3)
│ ├── utsm-ipc.patch # Shared memory IPC driver (Phase 1.3)
│ └── utsm-virtio.patch # virtio enhancements (Phase 1.4+)
├── initramfs/ # Minimal initramfs contents (optional)
├── build.sh # Build script (run in WSL/Linux)
└── README.md # This file
Boot Flow
Limine (UEFI)
→ utsm.elf (VMX root)
→ vmm_init() + vmm_self_test()
→ linux_loader_init() (parse bzImage, set up boot_params, EPT)
→ linux_launch() (VMCS config + vmlaunch)
→ Linux 6.6 startup_64 (VMX non-root)
→ Serial console output
→ virtio-console ↔ UTSM
→ virtio-fs mount /utsm
→ User space (init/shell)
Guest Networking (virtio-net)
UTSM vmm 侧模拟一块 virtio-net 网卡(virtio-mmio 模型,GPA 0xF4001000,
guest ISA IRQ6),数据路径桥接到 host 真实网卡(e1000/virtio-net DKM 驱动,
经 kernel_api.net 的 tx/rx_poll 收发帧)。guest 内核 cmdline 已自动注入:
virtio_mmio.device=4K@0xF4001000:6
utsm_x86_64_defconfig 已启用 CONFIG_VIRTIO_NET=y(内置,非模块),
内核启动后应出现 eth0(virtio-mmio 无 PCI 拓扑,网卡名固定为 eth0):
# 确认网卡已识别(dmesg 应能看到 virtio_net probe 日志)
ip link show
# 拉起接口
ip link set eth0 up
# 方式一:DHCP(QEMU user-net/slirp 环境,网关 10.0.2.2,DNS 10.0.2.3)
dhcpcd eth0
# 或:dhclient eth0
# 方式二:静态地址(无 DHCP 服务器时)
ip addr add 10.0.2.15/24 dev eth0
ip route add default via 10.0.2.2
echo "nameserver 10.0.2.3" > /etc/resolv.conf
# 验证连通性
ping -c3 10.0.2.2 # QEMU slirp 网关(永远在线,适合冒烟测试)
ping -c3 10.0.2.3 # slirp 内建 DNS
pacman -Sy # 联网同步包数据库
注意事项:
- MAC 共用:guest virtio-net 的 MAC 与 host e1000 相同(UTSM 桥接模型,
config 空间直接回填 host 网卡 MAC)。QEMU user-net 下 slirp 按 MAC 分配
10.0.2.15;若 host Deshab 原生网络栈同时用该网卡联网,两者会抢同一 DHCP 租约,实测时请只让一侧做 DHCP(或 host 完全不用网络)。 - MTU:后端按标准 1500 MTU 转发,不支持 GSO/TSO(feature 未协商, guest 自动走软件分片/checksum 路径)。
- 无中断收包:RX 走 UTSM 周期轮询(VMX preemption timer,~1kHz)
填充 guest RX ring 并注入 IRQ6;大流量下串口统计日志每 512 帧打印一行
[VNET] stat ...(rx_filled / rx_drop_nobuf / tx_sent / tx_drop), 可用于判断包在哪一段丢失。 - 若
ip link看不到 eth0:检查 dmesg 中virtio_mmioprobe 是否成功, 以及 host 串口日志是否有[VNET] bound to UTSM net device 0(host 侧 e1000/virtio-net DKM 驱动需先注册 netdev)。