Files
Deshab-OS/docs/RE/万物互联与服务总线设计.md
LinehuandCursor 8554a82677 feat(panic): FUCK [panic] mode=strict|fallback + realtest image variant
- UTSM panic_full returns in fallback mode (logs [PANIC:FALLBACK] + code + hit
  count); panic_halt keeps always-halt sites (CPU exception, VMM-E11 LA57,
  VMM-E15 DSK jump, UTSM-E42 test hook). Call sites given safe continuations.
- Mode passed to DSK/FirstInit/login/desktop via DSK_BOOT_FLAG_PANIC_FALLBACK;
  DKM kernel_api.panic / kern.log.panic return to driver; ext4 fatal aborts the
  op via setjmp/longjmp and DSK falls back to FAT32 ESP.
- build.ps1/Makefile: dev=strict, release=fallback, new realtest (release
  options + strict); default -Variant all; serialized iso packing under -j.
- Fix '*/' inside comments (dkm.h, kernel_api.h, bus.c) that broke the build.
- Includes pending work: dkm_bus service bus, mt7920/wlan drivers, desktop
  files/startmenu/prank, pe-tools, diskinfo, docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-12 23:57:19 +08:00

282 lines
18 KiB
Markdown
Raw Permalink 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.
# 万物互联与服务总线设计(DKM-BUS)
> 系列代号:**万物互联(Deshab Interconnect)**
> 路线:P0-P6,六阶段全量改造
> 状态源:[STATUS.md](../STATUS.md);任务板:[TASKBOARD.md](../TASKBOARD.md)(D6/D7 条目)
> 设计定稿:2026-10-10
---
## 0. 一句话
**没有主内核。utsm.elf 只剩"机制"(中断/内存/调度/恢复/封缄/panic/加载器),其余一切——驱动、文件系统、向导、登录、桌面、shell——都是平等的 DKM 内核模块,彼此只通过按名服务总线(kern.\* / srv.\*)互联。**
这是 library OS / 万物互联形态:程序即内核,模块间没有 syscall 边界,没有第二次内核交接。性能不是本设计的目标——按名查找、间接调用、注册-消费模式到处用,是刻意的(自由 > 快)。
```text
Limine → utsm.elf(唯一内核:IDT/IRQ、DMA、分页、arena、UTSM/UTRW、DRR、
PCQ 调度器、panic 莲花屏、DKM loader、服务总线宿主)
│ manifest.json 4+1 stage,全部 .drv(ET_REL),加载后常驻、永不被覆盖
stage0 platform: timer apic acpi pci
stage1 boot: console_fb ahci nvme ehci xhci bootfs
stage2 fs: vfs fat32(实装 R/W) ext4(新) devfs
stage3 optional: e1000 virtio_net ath9k wlan ps2kbd
stage4 session: ps2mouse session(协调器) netman firstinit login shell desktop cmd
↑ driver_init=注册服务;运行= srv.*.run 被调用 / 调度任务
│ 模块间唯一通信方式:服务总线(kern.* / srv.* 按名注册-消费)
终态:PCQ 调度器常驻(bootstrap 变 idle),desktop 等长期模块为任务,
输入走真 IRQ(IRQ1/12),无 DSK、无第二次内核交接、无 IF=0 时代
```
### 0.1 与 RTOS / 微内核的区别(定界)
- 这**不是** RTOS:不承诺调度延迟上界(O(1) 调度器结构上接近,但那是副产品)。
- 这也**不是**微内核:模块不在用户态,没有 IPC 权限检查,一切 Ring0——SAS-R0 约束不变。
- 最近亲缘:exokernel/library OS(程序即内核)+ multikernel 的"OS 即分布式系统"世界观(去中心服务表)。
---
## 1. 服务总线(dkm_bus)
### 1.1 从 kapi 到 bus
现有 `dkm_kapi_table`(`CODE/UTSM/dkm/kernel_api.c:95-136`)是静态只读表:只有内核能导出(14 项),驱动不能注册。总线把它双向化:
- **kern.\***:仅 UTSM 注册(内核本体 + 内核托管注册表的前端)。
- **srv.\***:任何 .drv 模块在 driver_init 里注册,任何模块消费。
- 旧 14 条无前缀 kapi 名(`log.info` 等)冻结不动(兼容层);总线播种时同时注册带 `kern.` 前缀的新名。终态(P6 收尾)kapi 静态表退役,总线成为唯一注册源。
### 1.2 数据结构与 API
新增 `CODE/UTSM/dkm/bus.c`;`include/utsm/dkm.h` **尾部追加**(不改任何既有字段,`kernel_api+0xA8` block 槽偏移不受影响):
```c
#define DKM_BUS_MAGIC 0x53425553u /* "SBUS" */
#define DKM_BUS_VERSION 1u
#define DKM_BUS_MAX_SERVICES 128
#define DKM_BUS_MAX_NAME 48
#define DKM_BUS_F_KERNEL 1u /* 内核注册,不可注销 */
#define DKM_BUS_F_NO_UNLOAD 2u /* 模块声明:注销即非法 */
typedef struct dkm_bus_service {
char name[DKM_BUS_MAX_NAME]; /* NUL 终止,必须带命名空间前缀 */
u32 version; /* 服务契约版本,消费方校验 */
u32 flags;
void *fn; /* 服务入口,签名由各服务契约定义 */
const struct dkm_driver_handle *provider; /* NULL = 内核 */
} dkm_bus_service;
typedef struct dkm_bus_api {
u32 magic, version;
int (*register_service)(const char *name, u32 version, void *fn);
int (*unregister_service)(const char *name);
int (*lookup)(const char *name, void **out_fn, u32 *out_version);
int (*probe)(const char *name, void **out_fn, u32 *out_version);
u32 (*count)(void);
const dkm_bus_service *(*at)(u32 index);
} dkm_bus_api;
/* dkm_kernel_api 尾部追加(kapi 之后):const dkm_bus_api *bus; */
/* 内核直连(kernel 不经函数指针调自己):
* const dkm_bus_api *dkm_bus_get_api(void);
* void dkm_bus_set_current_provider(struct dkm_driver_handle *h);
* loader 在 driver_init 前后设/清 current provider 上下文
* (仿 D4 dkm_log_set_driver 的位置与模式)。 */
```
### 1.3 失败策略(铁律映射)
| 操作 | miss / 违规时 | 语义 |
|---|---|---|
| `register_service` 名字非法(无命名空间前缀 / 非 srv.\* 却是模块) | `BUS-E01` panic | 编程错误 |
| `register_service` 重名 | `BUS-E02` panic | 编程错误 |
| `register_service` 表满 | `BUS-E03` panic | 容量规划错误 |
| `lookup` 未命中 | `BUS-E04 <名字>` panic | **硬依赖未满足 = 编程错误,绝不返回 NULL 伪装成功** |
| `probe` 未命中 | 返回 -1 | **能力缺席 = 设计内双路径**,调用方必须显式处理缺席,且该回退须登记 CLAUDE.md 白名单 |
| `unregister` 非 provider 本人 / F_NO_UNLOAD | panic | 生命周期违规 |
两级语义正好映射插桩铁律:该响的地方响(lookup),该静的地方显式静(probe + 白名单)。
### 1.4 命名空间
| 前缀 | 谁能注册 | 已规划服务 |
|---|---|---|
| `kern.*` | 仅 UTSM | `kern.log.info/warn/error/panic`、`kern.dma.alloc_pages`、`kern.irq.register`、`kern.irq.vector_alloc/free`、`kern.irq.unmask/mask`、`kern.mm.map_mmio/unmap_mmio`、`kern.apic.register_eoi`、`kern.drr.snapshot_dirty/rollback_pages`、`kern.utrw.debug_dump`、`kern.block.read/write`、`kern.config.get`、`kern.pe.service`、`kern.lxc.service`、`kern.probe.info`、`kern.dkm.load_by_name`、`kern.bootlog.milestone` |
| `srv.*` | 任何 .drv | `srv.input.mouse.poll`、`srv.input.kbd.poll`、`srv.fs.fat32.read_path/write_file/bootlog`、`srv.fs.ext4.*`、`srv.net.lease`、`srv.user.config`、`srv.auth.result`、`srv.session.dev_mode`、`srv.firstinit.run`、`srv.login.run`、`srv.desktop.run`、`srv.netman.run`、`srv.shell.run` |
规则:模块注册不带命名空间前缀或带 `kern.` → `BUS-E01`。名字长度 ≥ DKM_BUS_MAX_NAME → `BUS-E01`。
### 1.5 与 manifest depends/provides 的两层机制
manifest 的 depends/provides 今天是纯元数据(`dsm_load_stage_range` 只按数组顺序加载,不做校验)。总线设计引入两层强制:
**第一层:加载时序保证(P0)**
- DSM loader 维护 capability 集合(已加载驱动的 provides token 并集)。
- 每个驱动加载前校验其 depends 全部满足,miss → `DKM-E44 DEPENDENCY NOT SATISFIED` panic。
- 同 stage 内按依赖**不动点迭代**排序(多趟扫描直到无进展;环/死锁 → panic)。性能无所谓,正确性第一。
- driver_init 返回 0 后,登记该驱动 desc->provides 的 token。
**第二层:服务可发现性校验(P1)**
- loader 在 driver_init 成功返回后校验:**stage≥4 模块的每个 provides token `T` 必须对应至少一个已注册的 `srv.T` 或 `srv.T.*` 服务**,否则 `DKM-E45 PROVIDES NOT REGISTERED` panic。
- stage0-3 老 14 驱动豁免:它们的 provides 由内核侧注册表兑现(如 ahci → block registry),不经总线。豁免清单 = manifest.json 现有 stage0-3 全部条目,写死在 `dsm_verify_provides` 的注释里。
为什么 provides 不自动注册:loader 拿不到服务 fn 指针(注册哪些函数、什么签名是模块的自由)。所以是"模块主动注册 + loader 事后校验契约"——自由也要有地图,但地图由填图人自己画,loader 只查漏。
### 1.6 生命周期模型("程序变内核任务")
```text
load(ET_REL 重定位,kmem_alloc 永久内存——镜像覆盖问题就此灭绝)
→ driver_init(handle, api):只做 注册服务 + (长期模块)api->sched->task_create
(快、非交互;此时抢占未启用,满足 task_create 前置条件)
→ 控制权回到 DSM loader → stage4 全部完成 → 回 kernel_main
→ 排序者(P4 期间=残留 DSK,P5 起=session.drv)bus 调 srv.*.run 依次拉起
(一次性模块 call-and-return;交互式模块 run 内阻塞交互——与今天 DSK 阻塞在
login 上的行为一致,无回归)
→ P6 终态:utsm_sched_enable 常驻 + bootstrap park 成 idle;desktop 的 run 即
它创建的任务入口,由 PCQ 驱动;输入 IRQ 解屏蔽(IRQ1/12)
```
关键设计:**"运行"也是总线服务**(`srv.<mod>.run`)。这回答了"desktop 什么时候 driver_init"——在 UTSM 阶段、任何 UI 出现之前;init 只注册不运行;运行由排序者按总线调用发起。
loader 单线程不变式:session.drv 的 `kern.dkm.load_by_name` 在 stage 循环外被调(顺序执行 + loaded 标志防重入),总线无锁。任何未来并发加载都是契约违规。
---
## 2. 跨模块状态迁移表
现状真正跨模块耦合只有 `dsk_boot_context`(desktop.h 的 extern 全局是 desktop 单模块内多 TU 链接,`ld -r` 后原样工作)。逐槽消灭:
| 现状耦合通道 | 总线化后 | 提供方 |
|---|---|---|
| desktop `*(u64*)(api+0xA8)` 裸偏移读 block | `api->block` 字段直读(driver_init 拿到真 api 指针) | UTSM |
| `reserved[4]` pe_service | `kern.pe.service` | UTSM pe.c |
| `reserved[5]` lxc service | `kern.lxc.service` | UTSM linux_compat.c |
| `reserved[6]` probe_info | `kern.probe.info` | UTSM probe.c |
| `reserved[7]` net_lease | `srv.net.lease`(fn 返回 const net_lease_info*) | netman.drv |
| `reserved[0/1]` userconf 缓冲 | `srv.user.config`(ptr/size/状态打包结构) | firstinit.drv |
| `reserved[2]` login 成功标志 | `srv.auth.result` | login.drv |
| `reserved[3]` dev_mode | `srv.session.dev_mode` | session.drv |
| `g_mouse_state` / `mouse_poll_state()` | `srv.input.mouse.poll`(沿用 mouse_state_t magic/version 契约) | ps2mouse.drv |
| DSK 自带 FAT32 只读解析 + 写路径 | `srv.fs.fat32.read_path` / `srv.fs.fat32.write_file` / `srv.fs.fat32.bootlog` | fat32.drv(实装) |
| DSK 自带 ext4.c | `srv.fs.ext4.*` | ext4.drv(新) |
| DSK PIE ELF loader | (消灭)app 全变 .drv,统一走 UTSM DKM ET_REL loader | UTSM |
| dsk_fatal 莲花屏 | `api->log->panic`(内核 F1 莲花屏,视觉本就同源) | UTSM |
| dsk_boot_context 整体 | (消灭)P5 删除 dsk.h 中的定义 | — |
---
## 3. DSK 的命运:溶解
终态**完全消灭** deshab.elf。不保留"会话协调器特权模块"——会话排序逻辑移植为 session.drv,一个普通的 stage4 .drv,无任何特殊待遇。
迁移期(P2-P4)DSK 先降格为纯总线客户端(调度调用从"自带 FAT32 + PIE loader"改成 bus 调用),P5 删除二进制、dsk_loader.c 交接代码与 dsk_boot_context。
职责归位地图:
| DSK 职责 | 归宿 |
|---|---|
| FAT32 只读解析 + 写路径 + bootlog | fat32.drv 实装(母本:dsk_loader.c 的 fat32_read_path/write_file_in_dir 全套) |
| ext4.c 读写 | ext4.drv(整文件移植,dsk_fatal → g_log->panic) |
| PIE ELF loader + 8MB ibuf | 消灭(app 全变 .drv ET_REL;DKM-E70 ibuf 雷区整体绕开) |
| 静态 Logo / splash | session.drv |
| FUCK INI 读取 | 单一事实源 = Limine boot module(cmdline="fuck:config")+ session.drv 自带 INI 解析副本 |
| firstInit.txt 检测 | session.drv(经 srv.fs.fat32.read_path) |
| 模块调度(mouseInit/FirstInit/netman/login/shell/desktop/cmd) | 各自变 stage4 .drv;session.drv 用 kern.dkm.load_by_name 按需拉起 + bus 调 srv.*.run |
| BOOT01-07.TXT 里程碑 | `kern.bootlog.milestone` / srv.fs.fat32.bootlog |
| 会话选择(native/kde/cmd)+ 登录强制 | session.drv(登录失败 → SESSION-E02 panic,沿用 FS-E06 语义) |
| dsk_boot_context | 消灭 |
**P2-P5 之间的双 FAT32 实现是受控临时债**:deshab.elf 自身装载仍走内核侧 FAT32(`dsk_load_from_block_fat32`),直到 P5 删除。窗口期内禁止"顺手"修两边分叉逻辑。
---
## 4. 落地路线(P0-P6)
每 phase QEMU 可启动(build.bat -Variant dev → run_qemu.bat,ahci0 SATA + TCG + 串口 stdio),证据日志落 `.build_tmp/`。
### P0 — DSM 依赖图强制
`dkm/manifest.c`:capability 集合 + 不动点排序 + depends 校验(`DKM-E44`)。
验收:正常启动串口与基线逐行一致;负向测试(假 depends 条目)→ DKM-E44 莲花屏。
### P1 — 服务总线落地
`dkm/bus.c`(新)+ dkm.h 尾部追加 + provider 上下文 + `dsm_verify_provides`(DKM-E45)+ attest 翻绿 + selftest 用例(TST-E25..E28)+ devfs `/dev/services`。
验收:`[BUS] ready services=N`;`[TST] bus selftest PASS`;老 14 驱动不变。
### P2 — 文件系统归位
fat32.drv 实装(srv.fs.fat32.*)+ ext4.drv(srv.fs.ext4.*)+ DSK/UTSM 消费侧切总线。
验收:`[fat32] srv.fs.fat32.read_path registered`、`[ext4] selftest PASS`、首次启动全流程不回归。
### P3 — 加载器 FS 化 + stage4 + ps2mouse.drv 试点
DSM_MAX_STAGES 4→6 / PER_STAGE 8→12;`dsm_read_module_fs`(boot module 优先 / FS 回退 / `DKM-E46`);`kern.dkm.load_by_name` 接通;ps2mouse.drv(srv.input.mouse.poll);manifest 新增 stage4 "session";DSK 删 mouseInit 调度块。
验收:`[DSM] stage 4 session begin` → `[ps2mouse] driver ready`。
### P4 — 应用模块 DKM 化(4a-4f)
统一配方:① `dsk_entry(ctx)` → `driver_init(api, handle)` + driver_desc(stage=4、NO_UNLOAD);② 原 entry 主体改 `static <mod>_run(void)` 注册 `srv.<mod>.run`;③ ctx 消费点按 §2 迁移表替换;④ 自带 fatal → `api->log->panic`;⑤ 构建:PIE linker.ld 弃用,`clang -c + lld -r` 产出到 `SYSTEM/driver/session/`,**每模块必跑 `llvm-readobj --relocations` 核对 ∈ {R_X86_64_64/32/32S/PC32/PLT32}**;⑥ DSK 同 commit 删对应调度块改 bus 调 run。
子步:4a netman → 4b shell → 4c firstInit(user.conf 写盘收编进模块,reserved[0/1] 往返删除)→ 4d login → 4e desktop(~20 TU,最大风险点;host SDL 构建 #ifdef 隔离)→ 4f cmd + 收尾。
### P5 — DSK 退役 + session.drv
session.drv(排序骨架移植)+ 删 dsk_loader.c / dsk_boot_context / CODE/dsk/ + main.c 交接改 `dsm_load_by_manifest_upto(cfg, 4)`(quiesce 保留——运行时行为与 DSK 时代逐字节对齐,无回归)+ CLAUDE.md 全面更新。
验收:串口无 `[DSK] boot`;`[session] stage4 sequencing begin` → 全流程正常;dev/release 双过。
### P6 — 常驻调度 + 事件循环 + 真 IRQ 输入
sched_enable 常驻 + bootstrap park;desktop 任务化(task_create + 每帧 srv.input.*.poll + sleep_ms);ps2kbd 事件环形缓冲 + srv.input.kbd.poll;ps2mouse IRQ12 解屏蔽(kern.irq.unmask);firstInit/login 键盘轮询 → kbd.poll(强制:IRQ 驱动后 handler 读走 0x60,轮询端口会饿死)。
验收:`[SCHED] enable` 常驻;QEMU QMP sendkey/鼠标事件到达 desktop;`[desktop] task slot=N`。
### 收尾(并入 P6)
kapi 静态表退役(总线唯一注册源);block/net 注册表前端化(消费者切 `kern.block.*`);STUB grep 基线不抬升;desktop 任务 DRR 看门狗 register/kick(可选)。
---
## 5. 错误码登记
| 码 | 含义 | 触发点 |
|---|---|---|
| BUS-E01 | 服务名非法(无命名空间 / 模块注册 kern.* / 超长) | register_service |
| BUS-E02 | 服务重名 | register_service |
| BUS-E03 | 服务表满(DKM_BUS_MAX_SERVICES) | register_service |
| BUS-E04 | lookup 未命中(硬依赖未满足) | lookup |
| BUS-E05 | 注销违规(非 provider / F_NO_UNLOAD) | unregister_service |
| DKM-E44 | manifest depends 未满足 | dsm_load_stage_range / dsm_load_named |
| DKM-E45 | stage≥4 provides 未注册到总线 | dsm_verify_provides |
| DKM-E46 | 模块 boot module 与 FS 双源皆无 | dsm_load_stage_range |
| DKM-E47 | 依赖图成环 | 不动点排序 |
| DKM-E48 | capability 表满(DSM_MAX_CAPS) | dsm_capability_add |
| SESSION-E01 | session.drv 初始化失败(FUCK 缺失等) | session.drv |
| SESSION-E02 | 登录强制失败(沿用 FS-E06 语义) | session.drv |
| SESSION-E03 | 会话类型非法/加载失败 | session.drv |
| TST-E34..E38 | 总线 selftest 用例(注册/命中/probe/重名/注销违规;TST-E01..E33 已被既有用例占用) | utsm_selftest.c |
全部零降级:panic 莲花屏。
## 6. 设计内白名单(probe 型缺席 + 顺序豁免,CLAUDE.md 同步登记)
1. 无块设备时 `srv.fs.fat32.*` 缺席 → PE/会话路径 warn 跳过(环境能力缺失,与既有"块设备缺失回 boot module"白名单同源)。
2. FUCK `[drivers]` 关掉的模块 → 其 srv.* 服务缺席,消费方必须用 probe 并显式处理。
3. QEMU 无 ath9k / 无 wlan → 既有白名单不变。
4. **P0 顺序豁免**:`dsm_load_named_boot(cfg, "pci"/"ahci")`(kernel/main.c VMM 路径)跳过 depends 校验——pci+ahci 必须先于 apic/stage0 加载,否则 Linux guest 陷入 IDTR=0 VM-exit 风暴(历史验证的行为边界)。这是**顺序**豁免不是降级:模块照常 ELF 校验/driver_init/provides 登记,只是不卡依赖时序。`kern.dkm.load_by_name`(P3)一律走严格版 `dsm_load_named`。
## 7. 风险点
1. **desktop 多 TU 重定位集合**(最大技术风险):lld -r 产物可能带出新 relocation 类型 → DKM-E37 开机即炸(至少响亮)。每模块迁移必跑 readobj 并在 phase 记录贴清单。
2. **DSK-E70(ibuf 尾部写零,未解)**:DKM 化整体绕开 8MB ibuf,但若根因是 AHCI DMA PRDT 越界,会跟到 fat32.drv 缓冲。fat32/ext4 保留写后回读校验,持续观察 STATUS.md 该条目。
3. **交互式模块阻塞 bootstrap**:与今天行为等价无回归;DRR 看门狗默认关(FUCK),接 P6 时给 desktop 任务显式 register/kick。
4. **加载器重入**:loader 单线程不变式(§1.6),违反即契约违规。
5. **attest/FUCK 双面性**:app 模块进 manifest 后受 `[drivers]` 开关与 `require_*` 影响;build/configs/{dev,release}/FUCK 的 attest 豁免行同步增删(release 要求 desktop 必在,QEMU 无 ath9k 等继续豁免)。
6. **DSM/manifest 容量**:stage4 一期约 8 条 → P3 把上限提到 12/6;name[32]/path[64]/depends 4/provides 4,desktop 的 provides token 控制在 4 内。
---
> "没有主内核,每个模块都是内核——总线就是万物的神经。疯但互联。" 🪷