Files
Deshab-OS/docs/BOOT_SEQUENCE.md
T
xyou 129175a5d8 docs: 添加项目文档体系(架构/启动路线/路线图/贡献规范)
- docs/ARCHITECTURE.md: 架构设计文档,覆盖五大核心子系统
  (SAS-R0-PCQ/UTSM/UTRW/DRR/DKM)、内存模型、驱动/文件/网络/图形子系统、
  开放设计点
- docs/BOOT_SEQUENCE.md: 启动路线设计,原创 DBS 五阶段命名体系
  (B0 Ignis/B1 Sigillum/B2 Transitus/B3 Origo/B4 Excitas),
  启动契约/锚点/回退链机制
- docs/ROADMAP.md: 分阶段开发路线图,9 个 Phase + 5 个里程碑
- CONTRIBUTING.md: 贡献与协作规范,含代码规范/Git 工作流/PR 流程
- .github/: PR 模板 + Bug/Feature Issue 模板
- README.md: 更新为项目介绍 + 文档索引 + 构建说明

所有文档基于项目真实源码与设计文档编写,62 个交叉链接全部有效。
2026-07-02 16:56:38 +08:00

597 lines
24 KiB
Markdown
Raw Blame History

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.
# Deshab 启动路线设计
> 本文档定义 Deshab-OS 从上电到用户可交互的完整启动序列。
> 它是 [架构设计文档](./ARCHITECTURE.md) 中启动链路的深度展开,基于真实源码实现。
---
## 0. 设计理念
Deshab 的启动不是一条简单的"引导→内核"直线,而是一个**带契约的分阶段唤醒过程**。每个阶段都有明确的入口条件、出口契约和失败语义,失败时可沿**启动回退链**降级到上一个稳定点,而非直接 panic。
### 0.1 原创命名体系
延续 Deshab 的工程化缩写风格(SAS-R0-PCQ / UTSM / DRR / DKM),启动序列命名为 **DBS(Deshab Boot Sequence)**,划分为五个阶段:
| 阶段 | 代号 | 名称 | 含义 | 产物 |
|------|------|------|------|------|
| B0 | **Ignis** | 火种 | 固件点燃,引导器接管 | `utsm.elf` 入内存 |
| B1 | **Sigillum** | 封缄解封 | UTSM 首阶段内核建立封缄内存与驱动底座 | 14 个 DKM 驱动 ACTIVE |
| B2 | **Transitus** | 交接 | UTSM 向 DSK 版本化传递控制权 | `dsk_boot_context` 就绪 |
| B3 | **Origo** | 溯源 | DSK 判定首次/正常启动,调度系统初始化器 | `firstInit` 标志判定 |
| B4 | **Excitas** | 唤醒 | 用户设置向导或正常启动路径 | 用户可交互 |
> 命名取自拉丁语,呼应 Deshab "封缄内存"(Sealed Memory)的意象:系统从封缄中逐层苏醒。
### 0.2 三个核心概念
**启动契约(Boot Contract)**——每个阶段 B(n) 对下一阶段 B(n+1) 做出明确承诺。契约包含:
- **Entry**:进入本阶段时 CPU/内存/设备必须处于什么状态
- **Exit**:离开本阶段时必须完成什么、向下一阶段传递什么
- **Fail**:本阶段失败时的降级策略(回退 / DRR 接管 / panic)
**启动锚点(Boot Anchor)**——每个阶段结束时的可验证检查点,输出稳定的串口日志标记。锚点是"已知稳定点",回退只能退到锚点,不能退到阶段中间。例如 `[UTSM] SELFTEST PASS` 是 B1 的锚点。
**启动回退链(Boot Fallback Chain)**——失败时的降级路径,每级回退对应一个锚点:
```text
B2 DSK 块设备加载失败
└─ 回退 B1 锚点:改用 Limine boot module 加载 deshab.elf
B1 某驱动 init 失败
├─ required 驱动 → DRR recovery 或 panic
└─ optional 驱动 → 标记 FAILED,继续启动
B0 BCB 校验失败
└─ 切换 last_good_slot(未来 DRR 实现)
```
---
## 1. 启动总览
```mermaid
graph TD
PWR["上电 Power-on"] --> B0
subgraph B0["B0 Ignis 火种"]
B0A["UEFI/BIOS 固件"] --> B0B["Limine bootloader<br/>读 limine.conf"]
B0B --> B0C["加载 utsm.elf<br/>预加载 17 个 boot module"]
end
B0 --> B1
subgraph B1["B1 Sigillum 封缄解封"]
B1A["早期启动<br/>serial/IDT/arena/DMA"] --> B1B["UTSM init<br/>封缄内存+PCKC"]
B1B --> B1C["DKM 4-stage<br/>14 驱动加载"] --> B1D["selftest 锚点"]
end
B1 --> B2
subgraph B2["B2 Transitus 交接"]
B2A["FAT32 block provider<br/>读取 deshab.elf"] -.失败.-> B2F["回退 Limine module"]
B2F --> B2B
B2A --> B2B["ELF 校验+PT_LOAD"]
B2B --> B2C["填充 dsk_boot_context<br/>跳转 DSK"]
end
B2 --> B3
subgraph B3["B3 Origo 溯源"]
B3A["渐变背景+旋转环"] --> B3B["FAT32 读 firstInit.txt"]
B3B --> B3C{"firstInit==0?"}
end
B3 -->|首次| B4F
B3 -->|正常| B4N
subgraph B4F["B4 Excitas 唤醒(首次)"]
B4F1["mouseInit"] --> B4F2["netman"] --> B4F3["FirstInit 向导"]
end
subgraph B4N["B4 Excitas 唤醒(正常)"]
B4N1["正常启动路径<br/>待实现"]
end
```
---
## 2. B0 Ignis — 火种
### 2.1 契约
| 项 | 内容 |
|----|------|
| **Entry** | CPU 上电,执行固件(UEFI 优先),内存可用,PCI 设备已枚举 |
| **Exit** | `utsm.elf` 已加载到内存,boot module table 已构建,`limine.conf` 已解析,控制权交给 `_start` |
| **Fail** | 固件失败 → 硬件级复位;Limine 找不到 `utsm.elf` → 引导失败停在固件错误界面 |
### 2.2 执行细节
**固件阶段**:UEFI 固件加载 `SYSTEM/EFI/BOOT/BOOTX64.EFI`(即 Limine)。QEMU 场景需显式指定 UEFI 固件(`edk2-x86_64-code.fd` / `OVMF_CODE.fd`)。
**Limine 阶段**(源自 [`SYSTEM/boot/limine.conf`](../SYSTEM/boot/limine.conf)):
```text
timeout: 0
serial: yes
verbose: yes
/UTSM boot
protocol: limine
kernel_path: boot():/boot/utsm.elf
module_path: boot():/driver/manifest.json # dkm:manifest
module_path: boot():/driver/platform/timer.drv # 14 个 .drv
... (apic/acpi/pci/console_fb/ahci/nvme/bootfs/vfs/fat32/devfs/e1000/virtio_net/ps2kbd)
module_path: boot():/system/deshab64/deshab.elf # dsk:main
module_path: boot():/driver/test.fat32 # dkm:test_fat32
```
Limine 从 FAT32 ESP 读取 `utsm.elf` 作为内核,并预加载 **17 个 boot module**:1 个 manifest + 14 个 `.drv` + 1 个 `deshab.elf` + 1 个 `test.fat32`。这些 module 通过 Limine module response 暴露给内核。
### 2.3 未来扩展(DRR 接入后)
B0 未来将引入 **BCB(Boot Control Block)** 校验:
```text
1. 读取 Boot Control Block
2. 校验 BCB CRC
3. 选择 active_slot
4. 若 active_slot 失败次数超限 → 切换 last_good_slot
5. 加载对应 slot 的 utsm.elf
6. 传入 memory map、BCB 地址、DRR reserved region 信息
```
当前 BCB 尚未实现,B0 直接加载单一 `utsm.elf`。
### 2.4 B0 锚点
无串口输出(serial 尚未初始化)。锚点为 Limine 成功跳转到 `_start`,由 B1 的 `[UTSM] boot` 间接验证。
---
## 3. B1 Sigillum — 封缄解封
### 3.1 契约
| 项 | 内容 |
|----|------|
| **Entry** | Long mode 已启用,`_start` 获得控制,RDI/RSI 含 Limine bootloader 信息,中断禁用 |
| **Exit** | UTSM 封缄内存初始化完成,14 个 DKM 驱动 ACTIVE,selftest 通过,平台发现完成 |
| **Fail** | required 驱动失败 → DRR recovery 或 panic;optional 驱动失败 → 标记 FAILED 继续 |
### 3.2 入口约定(源自 [`boot.S`](../CODE/UTSM/arch/x86_64/boot.S))
```asm
_start:
cli # 进入 C 前必须关中断(IDT 未建)
cld # 清方向标志(避免 rep movs 反向)
lea kernel_stack_top(%rip), %rsp
andq $-16, %rsp # 16 字节栈对齐
call kernel_main
```
**强制约束**:
1. `cli` / `cld` 必须在最前——未建 IDT 前被中断或方向标志异常会导致三重故障。
2. 早期设置 `IA32_GS_BASE`——防止栈保护 prologue 访问 GS 段时页错误(真机三重故障的根因之一)。
3. 未启用 FPU/SSE 前编译必须 `-mno-sse -mno-sse2 -mno-mmx -msoft-float`——Clang 在 freestanding 下也可能生成 `xorps/movups`。
### 3.3 执行序列(源自 [`kernel/main.c`](../CODE/UTSM/kernel/main.c))
```text
kernel_main()
① serial_init() 早期串口(不无限等待 ready 位,超时降级)
② idt_init() IDT 0–47 stub + PIC remap 到 0x20–0x2f
③ arena_init() 内核 arena(16MB bump 分配区)
④ dma_init() 物理页 bitmap(Limine USABLE → bitmap,低 4G 钳位)
⑤ net_init() netdev registry(8 槽固定表)
⑥ drr_stub_init() DRR 占位(真实 DRR 待实现)
⑦ utsm_init() 封缄内存:segment table + PCKC
⑧ dkm_init() + dkm_fill_platform_info()
⑨ dsm_load_by_manifest() 按 manifest.json 分 4 stage 加载 14 个 .drv
⑩ utsm_selftest_run() UTSM/PCKC/UTRW 自检
⑪ dsk_load_and_jump() → 进入 B2
```
### 3.4 DKM 分阶段加载(源自 [`manifest.json`](../SYSTEM/driver/manifest.json))
| Stage | 名称 | 驱动 | 失败策略 |
|-------|------|------|---------|
| 0 | platform | timer → apic → acpi → pci | required 失败 → DRR recovery / panic |
| 1 | boot | console_fb / ahci / nvme / bootfs | required 失败 → DRR recovery |
| 2 | filesystem | vfs → fat32 / devfs | required 失败 → fallback bootfs / 只读 |
| 3 | optional | e1000 / virtio_net / ps2kbd | 失败只标记 FAILED,继续启动 |
**加载状态机**:`DISCOVERED → QUEUED → DEP_WAIT → LOADING → ELF_CHECKED → MEMORY_ALLOCATED → RELOCATED → ABI_CHECKED → INITING → ACTIVE`
**ELF 重定位**:必须 `R_X86_64_64/RELATIVE/GLOB_DAT/JUMP_SLOT`,建议 `PC32/PLT32/32/32S`,禁止 TLS/IFUNC/lazy binding。
**boot module 查找**(stage0/stage1 不依赖 VFS):path 在 boot module table → 内存加载;否则 VFS 可用则从 SYSTEM/path 加载;否则 `BOOT_MODULE_NOT_FOUND`。
### 3.5 kernel_api 平台直通
B1 完成后,`dkm_kernel_api` 已暴露:`log / rsdp_address / fb_* / boot_modules_response / irq_register / hhdm_offset / dma.alloc_pages / block / net`。
### 3.6 B1 锚点
```text
[UTSM] boot
... (各初始化阶段日志)
[UTSM] SELFTEST PASS ← B1 锚点(稳定点 1)
```
**锚点语义**:到达此日志表示封缄内存、DKM 驱动、平台发现全部就绪,可安全进入 B2。若未到达此锚点,DRR(未来)应能从 B0 重新引导。
---
## 4. B2 Transitus — 交接
### 4.1 契约
| 项 | 内容 |
|----|------|
| **Entry** | B1 锚点达成,`dkm_kernel_api` 就绪,boot module response 可用 |
| **Exit** | `deshab.elf` 已加载并重定位,`dsk_boot_context` 已填充,控制权交给 `dsk_entry(ctx)` |
| **Fail** | FAT32 block provider 失败 → 回退 Limine module;两者皆失败 → panic |
### 4.2 两阶段 DSK 加载(源自 [`dsk_loader.c`](../CODE/UTSM/kernel/dsk_loader.c))
```text
dsk_load_and_jump()
① 优先:FAT32 block provider
kernel_api.block.read(0, lba, count, buf)
→ 解析 BPB → 遍历 root cluster → 找 "DESHAB ELF"
→ 沿 FAT 链读取文件到 arena
② 回退:Limine boot module
遍历 module response 找 path=="/system/deshab64/deshab.elf"
或 cmdline=="dsk:main"
③ ELF 校验:ELFCLASS64 / ELFDATA2LSB / EM_X86_64 / ET_DYN|ET_EXEC
④ PT_LOAD 加载:计算 min/max vaddr → arena 分配 → 清零 → 复制 filesz
⑤ 填充 dsk_boot_context
⑥ 跳转 entry(ctx)
```
**关键约束**:
- `data_start_sec = rsvd + fat_count * spf`——漏掉第二份 FAT 会导致 root cluster 错位。
- arena 容量需足够(已从 4MB 扩到 16MB,后续应迁移到物理页分配器)。
- 批量读 256 扇区稳定,单扇区连续读偶尔超时——DSK loader 全部用 cluster 级批量读取。
### 4.3 dsk_boot_context 版本化传递
源自 [`dsk.h`](../CODE/UTSM/include/utsm/dsk.h),magic = `0x44534B31424F4F54`("DSK1BOOT"):
```c
struct dsk_boot_context {
u64 magic; // DSK_BOOT_MAGIC,DSK 入口必须校验
u32 abi_version; // DSK_BOOT_ABI_VERSION = 1
u32 size;
u64 flags; // FROM_UTSM | DKM_READY | FAT32_PATH
u64 hhdm_offset; // physical → virtual direct map
u64 rsdp_address; // ACPI RSDP
u64 framebuffer_address/width/height/pitch/bpp;
u64 boot_modules_response;
u64 dkm_kernel_api; // DSK 通过此指针访问所有内核服务
u64 dkm_driver_table / driver_count;
u64 utsm_state / drr_state; // 当前为占位
u64 memory_map / count / entry_size;
u64 kernel_stack_top;
u64 reserved[8]; // 未来扩展(只能追加,不能插入)
};
```
**跳转约定**:
```text
RDI = dsk_boot_context *
RSI = RDX = 0
中断状态 = disabled
paging = UTSM 当前页表(higher-half + HHDM)
```
> **ABI 约束**:`dsk_boot_context` 字段只能追加到 `reserved` 区,不能在中间插入,否则 DSK 入口偏移错位。DSK 通过硬偏移读取 `block_read`(`api + 0xA8`),偏移错误会导致 NULL 解引用。
### 4.4 B2 锚点
```text
[UTSM] loading DSK
[UTSM] DSK loaded from FAT32 block provider ← 或 "trying Limine module"
[UTSM] DSK image base=0x...
[UTSM] DSK entry=0x...
[UTSM] jumping to DSK
[DSK] boot ← B2 锚点(稳定点 2)
[DSK] context ok
```
**锚点语义**:`[DSK] context ok` 表示 magic 校验通过,DSK 已接管控制权。若 `[DSK] bad context` 则 magic 不匹配,DSK 直接 halt。
---
## 5. B3 Origo — 溯源
### 5.1 契约
| 项 | 内容 |
|----|------|
| **Entry** | B2 锚点达成,`dsk_boot_context` 校验通过,framebuffer 可用 |
| **Exit** | `firstInit` 标志已判定,系统初始化器已调度(首次启动时) |
| **Fail** | 无 block device → 跳过 firstInit 检查,进入正常启动;FAT32 读取失败 → 视为首次启动 |
### 5.2 执行序列(源自 [`dsk/main.c`](../CODE/dsk/main.c))
```text
dsk_entry(ctx)
① cli # 禁用 IRQ——ps2kbd/IRQ1 和 mouse/IRQ12 handler 在 spinner 期间会崩
② 校验 ctx->magic == DSK_BOOT_MAGIC,失败则 halt
③ 从 ctx->dkm_kernel_api + 0xA8 取 block_read 函数指针
④ 绘制渐变背景(BG_TOP 淡蓝 → BG_BOTTOM 深紫,按 y 插值)
⑤ 旋转加载环动画循环:
- 双缓冲精灵(128×128 离屏 sprite)
- 四色圆弧(顺时针旋转,comet-tail 渐变)
- 每帧按行重算 sprite 背景以匹配渐变
- base -= 2(顺时针),frame++
⑥ frame >= 100 后触发首次启动检测:
- 有 block_read → FAT32 读 "FIRSTINTXT"
- firstInit == '0' → 首次启动
- firstInit != '0' 或文件不存在 → 正常启动
⑦ 首次启动时调度系统初始化器(见 §6)
⑧ frame > 150 后跳转 FirstInit.elf
```
### 5.3 视觉体验设计
**渐变背景**:`BG_TOP = 0xFFC8E0F0`(淡蓝)→ `BG_BOTTOM = 0xFF49306F`(深紫),按屏幕 y 坐标线性插值。FirstInit 复用相同背景语义,保证转场连续。
**旋转加载环**:
- 中心 `(cx, cy) = (fb_w/2, fb_h/2)`,半径 `r=48`,厚度 `thk=4`。
- 四色弧:`arcs = {0xFF4488CC, 0xFF2266AA, 0xFF66AAEE, 0xFF88CCFF}`,每段 90°,宽 82°。
- comet-tail:弧两端 6° 范围内 alpha 渐变(fade 0→255→0),形成拖尾。
- 内圆高光:`r-8` 范围内用背景色与白色 `(0xD0,0xF0,0xFF)` 混合,营造光晕。
- 纯整数运算(无浮点依赖),`isqrt_int` 用牛顿迭代。
**帧率控制**:`for(volatile u32 d=0; d<72000; d++) __asm__("pause")`——约 60fps(QEMU 下)。
### 5.4 B3 锚点
```text
[DSK] block_read ptr=0x...
[DSK] entering spinner loop
[DSK] checking firstInit...
[DSK] fat32 reading 256 sectors from LBA 0
[DSK] firstInit=0 ← 首次启动判定
[DSK] first init detected; running system initializers
```
---
## 6. 系统初始化器调度协议
### 6.1 设计原则
DSK **独占系统组件初始化职责**。FirstInit 只负责用户级设置(计算机名/用户名/密码),不接管系统初始化。这一边界避免"用户向导"与"系统初始化"逻辑耦合。
### 6.2 调度顺序(首次启动)
```text
DSK (firstInit == 0)
→ ① mouseInit.elf 系统输入初始化(PS/2 鼠标安全 stub)
DSK 调用 → mouseInit 执行 → 返回 DSK
→ ② netman.elf 网络管理器(配置加载 + netdev 枚举 + DHCP)
DSK 调用 → netman 执行 → 返回 DSK
→ ③ FirstInit.elf 用户设置向导
DSK 调用 → FirstInit 接管 UI → 不返回(halt)
```
### 6.3 初始化器 ELF 加载
DSK 用内嵌 FAT32 解析器 + PIE ELF loader 加载每个初始化器:
```text
fat32_read_root_file("MOUSE ELF", &data, &size)
→ dsk_load_elf(data, size, &entry)
→ 校验 ELF64 / EM_X86_64
→ PT_LOAD 复制到静态 image buffer
→ PT_DYNAMIC → DT_RELA/DT_RELASZ → R_X86_64_RELATIVE 重定位
(*slot = load_bias + addend)
→ entry = image + (e_entry - min_vaddr)
→ entry(ctx) # 传入同一 dsk_boot_context
```
**关键约束**:
- PIE ELF 必须处理 `R_X86_64_RELATIVE`——否则解引用全局指针/数组会 page fault。
- 指针数组改用栈上 `char[]` 逐字节赋值——避免 UTSM loader 不处理 `.rela.dyn` 的问题。
- ELF 文件大小不能超过静态缓冲区(`g_fdata[262144]` = 256KB),`dsk_load_elf` 必须校验 `found_size <= sizeof(g_fdata)`。
- 8.3 文件名必须用栈上字符数组构造,避免 PIE 重定位(`char name[12]; name[0]='F'; ...`)。
### 6.4 各初始化器职责
| 初始化器 | 产物 | 当前状态 | 职责 |
|---------|------|---------|------|
| **mouseInit** | `mouse/mouseInit.elf` | 安全 stub | 只读 PS/2 状态,不写控制器(避免 QEMU 早期阶段阻塞) |
| **netman** | `network/netman.elf` | 配置闭环 | 读 `conf.conf`/`NETCONF.CNF`,枚举 netdev,e1000 最小 DHCP |
| **FirstInit** | `user/use/FirstInit.elf` | UI + 输入 | 环淡出 → "欢迎使用 Deshab" → 账户设置卡片 → 键盘输入 → SHA256 密码 |
---
## 7. B4 Excitas — 唤醒
### 7.1 首次启动路径
```text
FirstInit.elf (dsk_entry → entry(ctx))
① 接收 dsk_boot_context,复用 framebuffer
② 加载环淡出动画(~1秒渐变)
③ 屏幕中央:"欢迎使用 Deshab"(预渲染 24px 中文位图,180×30)
④ 等待 5 秒
⑤ 渐隐切换为:"接下来让我们来引导你设置你的系统"
⑥ 账户设置卡片:
- 圆角矩形(draw_card,isqrt_int 边界检查)
- 白色输入框(INPUT_BG = 0xFFF0F5FA)
- 18px 中文(text_bitmaps.c 预渲染嵌入 ELF)
⑦ PS/2 键盘轮询输入:计算机名 → 用户名 → 密码
⑧ SHA256 密码摘要 + XOR 加密配置缓冲(user.conf 格式)
⑨ "设置完成"提示
⑩ for(;;) hlt # 当前不返回,待写盘后跳转正常启动
```
**字体方案**:
- 预渲染中文位图:`CODE/font/render_embedded.py` 用 Pillow 从 `simhei.ttf` 渲染指定字符串为 8bpp 灰度 C 数组,嵌入 ELF,避免运行时 TTF 解析。
- 运行时字体:DBF 格式(`simhei_16/24/32.dbf`),GB2312 全部 6763 汉字 + ASCII,索引按 codepoint 升序二分查找。
### 7.2 正常启动路径(待实现)
```text
firstInit != 0(或文件不存在)
→ B3 检测到非首次启动
→ 跳过系统初始化器调度
→ frame > 800 后 break 退出 spinner
→ [DSK] SELFTEST PASS
→ for(;;) hlt
```
当前正常启动路径仅 halt。未来将进入:
- 桌面环境 / Shell
- 用户登录验证(读取 user.conf,校验密码)
- 后台服务启动
### 7.3 首次→正常的转换条件
首次启动完成后,需写 `firstInit.txt = '1'` 以标记已完成。当前**写盘待实现**(依赖 `dkm_block_api.write` + AHCI WRITE DMA + FAT32 文件覆写,见 [路线图](./ROADMAP.md) Phase 5)。
### 7.4 B4 锚点
```text
[DSK] jumping to mouseInit
[mouse] init done
[DSK] mouseInit returned
[DSK] jumping to netman
[netman] ...
[DSK] netman returned
[DSK] loading FirstInit.elf
[DSK] FirstInit.elf loaded
[DSK] jumping to FirstInit ← B4 锚点(稳定点 3)
```
---
## 8. 启动错误恢复
### 8.1 当前回退链
| 失败点 | 回退策略 | 日志 |
|--------|---------|------|
| B2 FAT32 block provider 不可用 | 回退 Limine module | `[UTSM] FAT32 block path unavailable; trying Limine module` |
| B2 DSK module 两路径都找不到 | panic | `[UTSM] DSK module not found (neither FAT32 nor Limine)` |
| B2 ELF 校验失败 | panic | `[UTSM] DSK ELF rejected` |
| B3 无 block device | 跳过 firstInit,正常启动 | `[DSK] no block device, skipping firstInit` |
| B3 firstInit.txt 不存在 | 视为首次启动 | `[DSK] firstInit.txt not found` |
| B3 FirstInit.elf 加载失败 | 继续正常启动 | `[DSK] firstInit not found, continuing normal boot` |
| B4 mouseInit.elf 加载失败 | 跳过,继续 netman | (日志无,静默跳过) |
| B1 required 驱动失败 | DRR recovery / panic | (DKM 标记 FAILED_REQUIRED) |
| B1 optional 驱动失败 | 标记 FAILED,继续 | (DKM 标记 FAILED_*) |
### 8.2 DRR 接管路径(未来)
DRR(专用恢复根)实现后,启动错误恢复将升级为三级:
```text
Page Rollback 单页损坏,从 checkpoint slot 恢复密文页
Segment Rollback 整段损坏,恢复 segment desc / DMP / key_epoch
System Rollback 控制面严重损坏,写 crash reason → reboot → bootloader 切 last_good_slot
```
DRR Emergency Pool 独立于普通 allocator,recovery 路径禁止依赖普通堆。详见 [架构设计文档 §3.4](./ARCHITECTURE.md#34-drr--专用恢复根)。
### 8.3 真机调试特殊处理
QEMU 不严格检查 NX,真机 Limine page table 会强制 NX。以下问题只在真机暴露,需特殊处理:
- `kernel_panic` 应直接通过 COM1 串口输出,**不依赖 console/heap**。
- 添加分步 `screen_info()` 便于真机调试。
- 早期 `IA32_GS_BASE` 必须设置,否则栈保护 prologue 页错误。
---
## 9. 启动状态传递链
启动过程中,系统状态通过三级指针链传递给 DSK 及其初始化器:
```mermaid
graph LR
L["Limine response<br/>memmap/RSDP/fb/module/HHDM"] -->|"kernel_main 读取"| UTSM["UTSM 内核"]
UTSM -->|"dkm_fill_platform_info<br/>填充 kernel_api"| API["dkm_kernel_api<br/>log/irq/dma/block/net/..."]
API -->|"dsk_fill_boot_context<br/>ctx->dkm_kernel_api"| CTX["dsk_boot_context"]
CTX -->|"dsk_entry(ctx)<br/>RDI"| DSK["DSK 主内核"]
DSK -->|"同一 ctx 传递"| INIT["mouseInit / netman / FirstInit"]
INIT -->|"ctx->dkm_kernel_api<br/>+ 0xA8 取 block_read"| BLK["block provider<br/>(ahci0)"]
INIT -->|"ctx->dkm_kernel_api<br/>+ net 偏移"| NET["netdev registry<br/>(e1000/virtio_net)"]
```
**关键约束**:
- DSK 及所有初始化器共享同一个 `dsk_boot_context`,通过它访问所有内核服务。
- `block_read` 通过硬偏移 `api + 0xA8` 读取——偏移错误会导致 NULL 解引用(曾因误用 `0x60` 导致 `g_block_read` 永远为 NULL)。
- 所有初始化器都是 PIE ELF,DSK loader 必须处理 `R_X86_64_RELATIVE`。
---
## 10. 启动阶段与架构映射
| 启动阶段 | 架构子系统 | 涉及源码 |
|---------|-----------|---------|
| B0 Ignis | Limine bootloader | `SYSTEM/EFI/BOOT/` `SYSTEM/boot/limine.conf` |
| B1 Sigillum | UTSM + DKM + DMA + IDT | `CODE/UTSM/` `CODE/DKM/` |
| B2 Transitus | DSK loader + FAT32 + block provider | `CODE/UTSM/kernel/dsk_loader.c` `CODE/UTSM/kernel/block.c` |
| B3 Origo | DSK 主内核 + FAT32 内嵌解析 | `CODE/dsk/main.c` |
| B4 Excitas | FirstInit + mouseInit + netman + 字体 | `CODE/firstInit/` `CODE/mouse/` `CODE/netman/` `CODE/font/` |
---
## 11. 启动验证标准
### 11.1 最小启动验证(QEMU 默认场景)
```text
[UTSM] boot ← B1 开始
[UTSM] SELFTEST PASS ← B1 锚点
[UTSM] loading DSK
[UTSM] DSK loaded from FAT32 block provider ← 或 Limine module
[UTSM] jumping to DSK
[DSK] boot ← B2 锚点
[DSK] context ok
[DSK] SELFTEST PASS ← B3 正常启动锚点
```
### 11.2 首次启动完整验证(带 SATA FAT32 测试盘)
```text
[UTSM] boot
[UTSM] SELFTEST PASS
[UTSM] loading DSK
[DSK] boot
[DSK] context ok
[DSK] block_read ptr=0x...
[DSK] entering spinner loop
[DSK] checking firstInit...
[DSK] fat32 reading 256 sectors from LBA 0
[DSK] firstInit=0
[DSK] first init detected; running system initializers
[DSK] jumping to mouseInit
[mouse] init done
[DSK] mouseInit returned
[DSK] jumping to netman
[DSK] netman returned
[DSK] loading FirstInit.elf
[DSK] FirstInit.elf loaded
[DSK] jumping to FirstInit ← B4 锚点
(屏幕显示:渐变背景 → 旋转环 → "欢迎使用 Deshab" → 账户设置卡片)
```
### 11.3 设备测试场景
| 场景 | QEMU 参数 | 验证锚点 |
|------|----------|---------|
| SATA 块设备 | 临时 SATA FAT32 测试盘 | `block_read ptr` 非 NULL,FAT32 读取成功 |
| NVMe | `-device nvme` | 探测 `1b36:0010`(register 读取依赖高位 MMIO) |
| e1000 网络 | `-device e1000e` | netdev `tx=ready rx=ready` |
| virtio-net | `-netdev user` + `-device virtio-net-pci` | 探测 `1af4:1001` |
---
## 12. 相关文档
| 文档 | 内容 |
|------|------|
| [架构设计文档](./ARCHITECTURE.md) | 五大核心子系统、内存模型、驱动系统 |
| [开发路线图](./ROADMAP.md) | 分阶段开发路线(Phase 0-9) |
| [DSK 主内核说明](../CODE/dsk/README) | DSK boot context 与加载要求 |
| [UTSM 模块设计](../CODE/UTSM/README.md) | 封缄内存与启动流程 §16 |
| [DKM 驱动系统](../CODE/DKM/README.md) | 驱动分阶段加载与状态机 |
| [CLAUDE.md](../CLAUDE.md) | 项目当前状态与下一阶段路线 |