Files
Deshab-OS/CODE/dsk
boonxiong2 780230599d fix(dsk,firstInit,build): let the system boot all the way to the desktop
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"
2026-10-05 18:32:24 +08:00
..
2026-07-28 12:00:02 +08:00
2026-07-31 13:53:49 +08:00
2026-07-31 13:53:49 +08:00

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DSK 主内核说明



`CODE/dsk` 是 Deshab 的主内核工程目录,目标产物为:



```text

CODE/dsk -> SYSTEM/system/deshab64/deshab.elf

```



当前启动链路分为两层:



```text

bootloader

  -> SYSTEM/boot/utsm.elf

       UTSM 首阶段内核 / DKM 驱动加载 / 平台发现

       -> SYSTEM/system/deshab64/deshab.elf

            DSK 主内核

```



也就是说,`utsm.elf` 不是最终长期运行的完整主内核,而是当前已经具备启动、封缄内存、DKM 驱动加载、平台发现和早期系统服务能力的前置内核阶段。后续 UTSM 需要继续执行到 `deshab.elf`,把控制权交给 DSK 主内核。



---



## 1. 模块定位



DSK 是 Deshab 的主内核,负责承接 UTSM 阶段已经建立的系统基础,并进入完整内核运行期。



DSK 的职责:



```text

1. 接收 UTSM 传入的 boot context / platform context。

2. 接管主调度器、内存管理、系统服务和长期运行状态。

3. 使用 UTSM/DKM 已完成的平台发现结果。

4. 继续使用或接管 DKM 驱动状态。

5. 推进真实块设备、网络、VFS 和用户任务模型。

6. 与 DRR 恢复根协作,支持 checkpoint / recovery / rollback。

```



DSK 不应重复做已经由 UTSM 阶段完成的早期工作,例如:



```text

- Limine request 原始解析

- early serial 初始化

- 早期 arena 初始化

- DKM manifest 的首轮 stage 加载

- 纯 discovery 型平台枚举

```



DSK 应关注从“可启动实验内核”进入“可长期运行主内核”。



---



## 2. 产物路径



主内核 ELF 固定输出到:



```text

SYSTEM/system/deshab64/deshab.elf

```



建议目录语义:



```text

SYSTEM/

  boot/

    utsm.elf                 # bootloader 直接加载的首阶段内核



  system/

    deshab64/

      deshab.elf             # DSK 主内核



  driver/

    manifest.json

    ... *.drv                # DKM 驱动模块

```



`deshab64` 表示当前主内核目标架构为 x86_64 long mode。



---



## 3. UTSM 到 DSK 的执行关系



当前 UTSM 已完成:



```text

- long mode C 入口

- serial log

- UTSM/PCKC/UTRW selftest

- IDT 0-47

- PIC IRQ fallback

- irq_register

- Limine RSDP/framebuffer/module/HHDM request

- DKM/DSM 外部 .drv 加载

- 14/14 真实 DKM 驱动 discovery/加载闭环

```



下一步需要让 UTSM 在完成早期阶段后定位并加载:



```text

/system/deshab64/deshab.elf

```



推荐执行链:



```text

kernel_main()

  -> serial_init()

  -> idt_init()

  -> utsm_init()

  -> dkm_init()

  -> dsm_load_from_manifest()

  -> utsm_selftest()

  -> dsk_load_main_kernel("/system/deshab64/deshab.elf")

  -> dsk_build_boot_context()

  -> dsk_jump_entry()

```



DSK 入口不应假设自己由 bootloader 直接加载,而应假设由 UTSM 传入上下文。



---



## 4. DSK Boot Context



UTSM 跳转 DSK 时应传入一个明确版本化的上下文结构。



建议第一版结构:



```c

#define DSK_BOOT_MAGIC 0x44534B31424F4F54ULL /* "DSK1BOOT" */

#define DSK_BOOT_ABI_VERSION 1



struct dsk_boot_context {

    uint64_t magic;

    uint32_t abi_version;

    uint32_t size;



    uint64_t flags;



    uint64_t hhdm_offset;



    uint64_t rsdp_address;



    uint64_t framebuffer_address;

    uint64_t framebuffer_width;

    uint64_t framebuffer_height;

    uint64_t framebuffer_pitch;

    uint32_t framebuffer_bpp;

    uint32_t reserved_fb;



    uint64_t boot_modules_response;



    uint64_t dkm_kernel_api;

    uint64_t dkm_driver_table;

    uint64_t dkm_driver_count;



    uint64_t utsm_state;

    uint64_t drr_state;



    uint64_t memory_map;

    uint64_t memory_map_count;

    uint64_t memory_map_entry_size;



    uint64_t kernel_stack_top;

    uint64_t reserved[8];

};

```



传参建议:



```text

RDI = struct dsk_boot_context *

RSI = 0

RDX = 0

interrupt state = disabled 或明确约定

paging = UTSM 当前页表

address model = higher-half + HHDM

```



第一版可以只填必要字段:



```text

magic / abi_version / size

hhdm_offset

rsdp_address

framebuffer 信息

boot_modules_response

dkm_kernel_api

```



其余字段后续逐步补齐。



---



## 5. DSK ELF 加载要求



`deshab.elf` 建议先采用 ELF64 executable 或 relocatable-friendly layout。



第一版 loader 可只支持最小集合:



```text

ELFCLASS64

ELFDATA2LSB

EM_X86_64

ET_EXEC 或 ET_DYN(二选一先固定)

PT_LOAD segment

PF_R / PF_W / PF_X

入口 e_entry

```



推荐第一版限制:



```text

1. 不支持动态链接。

2. 不支持 TLS。

3. 不支持用户态权限切换。

4. 不支持 demand paging。

5. 不支持 symbol resolution。

6. 所有 PT_LOAD 一次性复制/清零。

7. 入口地址由 e_entry 给出。

```



加载路径:



```text

1. 从 bootfs/VFS 或 Limine module 查找 /system/deshab64/deshab.elf。

2. 校验 ELF header。

3. 计算 PT_LOAD 覆盖范围。

4. 分配或确认目标虚拟地址范围。

5. 复制 file-backed bytes。

6. 清零 memsz - filesz。

7. 设置段权限(第一版可沿用当前 RWX 简化策略)。

8. 构造 dsk_boot_context。

9. 跳转 e_entry。

```



---



## 6. DSK 初始功能目标



第一阶段 DSK 不追求完整功能,先做可验证闭环。



最小启动目标:



```text

1. 接收 dsk_boot_context。

2. 校验 magic / abi_version / size。

3. 复用 serial log 或 framebuffer log。

4. 打印 DSK boot banner。

5. 打印 hhdm / rsdp / framebuffer / driver_count。

6. 执行 DSK selftest。

7. 返回或 halt。

```



成功日志建议:



```text

[DSK] boot

[DSK] context ok

[DSK] hhdm offset=...

[DSK] framebuffer=...

[DSK] dkm drivers=...

[DSK] SELFTEST PASS

```



---



## 7. 后续主内核路线



DSK 阶段建议按以下顺序推进:



```text

P0: DSK ELF loader + dsk_boot_context + 跳转入口

P1: 物理页分配器 + 页表/MMIO 映射接口

P2: DMA buffer / cache barrier / IOMMU 预留接口

P3: AHCI IDENTIFY/READ 已具备最小 DMA 验证路径;继续推进 AHCI block provider 与 NVMe admin queue/identify

P4: FAT32 接入真实 block provider,替代 test.fat32

P5: IDT 256 vectors + APIC/IOAPIC/MSI IRQ backend

P6: e1000 / virtio_net RX-TX 数据路径

P7: 主调度器 SAS-R0-PCQ 与任务模型

P8: DRR checkpoint / recovery log / A-B rollback

```



优先级原则:



```text

先让 UTSM 能加载并跳到 DSK。

再补内存/MMIO/DMA。

再做块设备真实读取。

再迁移文件系统和网络数据路径。

最后进入调度器和恢复系统深化。

```



---



## 8. 与 UTSM 的边界



UTSM 保留职责:



```text

- 封缄内存模型

- UTRW 明文读写路径

- DMP/PCKC

- DKM 首轮驱动加载

- early recovery hook

- DSK 加载前的早期平台发现

```



DSK 接管职责:



```text

- 主内核生命周期

- 完整内存管理

- 完整 IRQ backend

- 块设备与文件系统运行期

- 网络栈运行期

- 调度器和任务模型

- 系统调用或内核服务入口

```



二者关系不是互斥,而是阶段化:



```text

UTSM = boot/runtime substrate

DSK  = main kernel runtime

```



---



## 9. 当前待办



短期需要实现:



```text

1. 已完成:build.ps1 增加 CODE/dsk -> SYSTEM/system/deshab64/deshab.elf 构建目标。

2. 已完成:SYSTEM/boot/limine.conf 预加载 /system/deshab64/deshab.elf。

3. 已完成:UTSM 中实现 DSK ELF64 PT_LOAD loader,优先通过 `kernel_api.block` + 内嵌 FAT32 解析从真实块设备读取 `DESHAB.ELF`(SATA FAT32 盘已验证);无块设备时自动回退 Limine boot module 预加载。

4. 已完成:定义 dsk_boot_context 头文件,UTSM 与 DSK 共用。

5. 已完成:编写 DSK 最小入口,打印 boot banner 和 SELFTEST PASS。

6. 已完成:QEMU 验证从 UTSM 继续执行到 DSK。

7. 已完成:把 "Limine 预加载 deshab.elf" 替换为 UTSM 通过 FAT32 block provider 读取。

   后续:在 FAT32 中支持子目录路径,统一 DSK 加载与 VFS 路径语义。

8. 下一步:按“块设备优先”推进 AHCI/NVMe IDENTIFY/READ 和真实 FAT32 挂载。

```



当前验证日志:



```text

[UTSM] SELFTEST PASS

[UTSM] loading DSK

[UTSM] DSK module size=...

[UTSM] DSK image base=...

[UTSM] DSK entry=...

[UTSM] jumping to DSK

[DSK] boot

[DSK] context ok

[DSK] SELFTEST PASS

```



验证标准:



```text

[UTSM] SELFTEST PASS

[UTSM] loading DSK

[DSK] boot

[DSK] context ok

[DSK] SELFTEST PASS

```