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

18 KiB
Raw Permalink Blame History

万物互联与服务总线设计(DKM-BUS)

系列代号:万物互联(Deshab Interconnect) 路线:P0-P6,六阶段全量改造 状态源:STATUS.md;任务板:TASKBOARD.md(D6/D7 条目) 设计定稿:2026-10-10


0. 一句话

没有主内核。utsm.elf 只剩"机制"(中断/内存/调度/恢复/封缄/panic/加载器),其余一切——驱动、文件系统、向导、登录、桌面、shell——都是平等的 DKM 内核模块,彼此只通过按名服务总线(kern.* / srv.*)互联。

这是 library OS / 万物互联形态:程序即内核,模块间没有 syscall 边界,没有第二次内核交接。性能不是本设计的目标——按名查找、间接调用、注册-消费模式到处用,是刻意的(自由 > 快)。

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 槽偏移不受影响):

#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 生命周期模型("程序变内核任务")

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 内。

"没有主内核,每个模块都是内核——总线就是万物的神经。疯但互联。" 🪷