# novus文档手册

# 设备管理器（M12，devmgmt）

Novus OS 的 Windows 11 设备管理器复刻：主窗口是菜单栏 + 工具栏 + 左侧可折叠
设备树 + 状态栏；双击/右键"属性"打开一个独立的**模态**属性子窗口（常规 / 驱动程序 /
详细信息 / 事件 / 资源），版式完全对齐 Win11。所有信息来自内核在启动期归一化的
设备表，应用本身不扫硬件。

> 状态：随 M12 生效
> 适用范围：内核 `kernel/devtab.{h,c}`、`kernel/sysinfo.{h,c}`、`kernel/usb.{h,c}`
> 窗口管理器 `wm/novus-wm/nwm.c` 与 `apps/src/wm.rs`
> 应用 `apps/src/devmgr/{mod,tree,props,fields}.rs`、`apps/src/bin/devmgmt.rs`

## 1. 入口

设备管理器可从四个入口启动，全部走 `apps_launch()` 按名字解析（`devmgmt`）：

1. 桌面右侧磁贴（与文件管理器/任务管理器/设置/网络/终端/安装并列，常驻）；
2. 底部任务栏固定图标（含运行时强调色指示圆点）；
3. 开始菜单"设备管理器"按钮；
4. `nsh` 终端直接输入 `devmgmt`。

`kernel/session.c` 的 `desktop_app()` 白名单与 `apps.c` 应用表都已登记，未登录时
`apps_launch()` 同样拒绝普通桌面应用。设置面板的"应用"页也把它列入"可启动"
（固定顺序：文件管理器/任务管理器/设置/设备管理器）。

## 2. 架构

```
kernel/devtab.c  ── 启动期建表（PCI 缓存 + blkdev/net/display/CPU/ACPI/USB/IOAPIC/PS2）
        │  devtab_count / devtab_at / devtab_field_count / devtab_field_at
kernel/sysinfo.c ── REQ_DEVLIST(0x031B) / REQ_DEVFIELD(0x031D)，128 B 分页
        │  IPC
apps/src/sinfo.rs ── devices() / dev_fields()
apps/src/devmgr/*  ── 主窗 + 设备树 + 模态属性窗
        │  wm::Win::create_ex(..., NWM_F_CREATE_MODAL) / next_event_any()
wm/novus-wm/nwm.c ── 120/160 显示列表预算、10 窗口、模态输入隔离
```

设计要点：

- **设备表固化**：`devtab_init()` 放在 `ide_init()` 之后、`net_init()` 之前
  （此时存储已就绪但无 DMA 在途）；网卡在 `net_init()` 之后用 `devtab_refresh()`
  追加。`devtab` 规模 `DEV_MAX 48`、`PCI_MAX_DEVICES 32`，约 2.3 KB + 4 KB，零运行期
  BAR 探测副作用。
- **字段分页**：设备详情（实例路径、硬件 ID、资源范围）长度远超 128 B，改为
  `(dev, tab, index)` 逐条取字段，客户端缓存当前页（2 条/包，值 56 字节，长文本截断）。
- **模态子窗口**：属性窗是独立窗口 + `NWM_F_CREATE_MODAL`；WM 在模态窗存在时把指针
  与键盘只路由给它，其它应用零改动。

## 3. 协议契约

设备树节点（`sysinfo_dev_t`，40 B，3 条/包 = 4 + 120）：

| 字段 | 类型 | 说明 |
|------|------|------|
| `parent` | u16 | 父类别节点下标，`0xFFFF` 表示根 |
| `class_id` | u8 | `DEV_CAT_*`（计算机/处理器/固件/显示/磁盘/存储控制器/网络/USB/输入/系统设备/未知）|
| `status` | u8 | `DEV_STATUS_OK` / `DEV_STATUS_WARN`（无驱动或未知设备）|
| `kind` | u8 | `DEV_KIND_*`（CPU/PCI/显卡/监视器/磁盘/网卡/USB 控制器/USB 设备/输入/系统/固件…）|
| `idx` | u8 | 在所属子系统表中的下标（取 BAR/事件/扇区用）|
| `flags` | u8 | `DEV_FLAG_REMOVABLE` / `DEV_FLAG_NODRV` 等 |
| `name` | char[32] | UTF-8 名称 |

属性字段（`sysinfo_devfield_t`，60 B，2 条/包 = 4 + 120）：

| 字段 | 类型 | 说明 |
|------|------|------|
| `key` | u8 | `DEV_F_*`（制造商/位置/容量/MAC/链路/硬件 ID/状态/问题代码/内存范围/I/O 范围/IRQ/…）|
| `group` | u8 | 事件行号或 BAR 序号（同一键多值时区分）|
| `value` | char[56] | UTF-8 值，过长截断 |

分页范式沿用 `sysinfo_list_t`：`total` 是整表/整 tab 数量，`index` 是起始项，
`n` 是本次实际返回；客户端 `index += n` 直到到顶。

## 4. 主窗口

客户区 820×540，标题"设备管理器"，10 px 圆角 + 柔影，浅色主体。

- **菜单栏**（22 px）：文件(F) / 操作(A) / 查看(V) / 帮助(H)，点击展开浅色浮层。
- **工具栏**（36 px）：图标按钮组（刷新 / 属性 / 展开全部 / 折叠全部 / 显示隐藏的
  设备等），悬停圆角底色、禁用态浅灰线条。
- **设备树**（20 px 行高，缩进 14 px/层）：可折叠类别 + 设备行；展开箭头 `v`/`>` 字形；
  类别/设备前 12×12 圆角色块（显示蓝、网络青、磁盘灰、USB 紫、未知黄）；异常设备行尾
  黄色 `!` 徽标；选中行为浅蓝底 + 3 px 强调色竖条；悬停高亮。
- **状态栏**（24 px）：左侧提示"选择设备后按 Enter 查看属性"，右侧设备计数；超出时
  以 `scroll` 平滑翻页，选中项 `ensure_visible` 始终可见。

键盘：`↑/↓` 移动选中、`Enter` 打开属性、`F5` 刷新（重建设备表并关闭已开属性窗）、
`Esc` 取消菜单/浮层。

## 5. 模态属性窗口

客户区 520×600，标题"设备属性"，比主窗更高层级，打开时主窗不收输入。

- **选项卡条**（44 px）：常规 / 驱动程序 / 详细信息 / 事件 / 资源，选中项下划线强调色。
- **常规**：24×24 类别图标 + 设备全名；三行键值对（设备类型/制造商/位置）；下方
  "设备状态"边框圆角文本框（多行状态文字，如"该设备的驱动程序未被安装。(代码 28)"）。
- **驱动程序**：四行键值对（提供商/日期/版本/数字签名）；五个 220×30 竖排操作按钮
  （更新/回退/禁用/卸载/属性），禁用项降灰；右侧说明文字。
- **详细信息**：属性(P) 下拉框（展开为白色高亮列表，键盘/滚轮可选）+ 值框。
- **事件**：时间戳/描述表头 + 3 行表格 + 等宽信息块 + "查看所有事件(V)…"次要按钮。
- **资源**：资源类型/设置表格（内存范围 ×2、I/O 范围、IRQ）+ "使用自动设置"勾选 +
  "更改设置(C)…"禁用按钮 + "冲突设备列表：没有冲突。"。
- **底部**：右对齐"确定 / 取消"，确定为主按钮（强调色）。

**只读边界**：更新/回退/禁用/卸载等破坏性操作不做真实驱动变更，点击后仅在对话框内
显示说明行，界面完整、系统不损坏。

## 6. 窗口管理器支撑

- `nwm_proto.h`：每窗显示列表 `NWM_MAX_SHAPES 120`、`NWM_MAX_TEXTS 160`
  （主窗 ≈35/30、属性窗 ≈60/70 图元，只在交互时重绘）；`NWM_MAX_WINDOWS 10`。
- `NWM_F_CREATE_MODAL`：模态窗存在时命中测试/键盘只服务该窗、`raise` 不能盖过它、
  标题栏只画关闭按钮。
- `apps/src/wm.rs`：`create_ex(..., flags)` 与 `next_event_any() -> (win, Ev)` 把事件
  按窗口 id 路由到主窗或属性窗；其它应用的事件循环不变。

## 7. 主题与双语

全部界面由 WM 图元（圆角填充/描边/文本）绘制，图标为程序化色块字形，不使用位图。
颜色随系统浅/深色与强调色联动（`ui::init` / `ui::poll` 监听主题版本）；标签中英双语
（`ui::l(zh, en)` 内联，未走 lang 字典）。

## 8. 构建与验证

- `make` 一并产出 `out/NOVUS.EFI` 与 `out/apps/devmgmt.bin`。
- 启动日志 `[DEVTAB] n nodes, m pci devices` 确认设备表建立；WM 运行期若单帧图元超预算
  会打印 `[APP] display list over shape/text budget`（正常情况下不应出现）。
- 注册链路：`Makefile` `APPS_NAMES` → `kernel/apps.c` 应用表 → `kernel/session.c`
  白名单 → `graphics/nd_demo.c`（桌面/任务栏/开始菜单/图标 `NG_ICON_DEVICES`）→
  `apps/src/shell/cmds.rs` `KNOWN_APPS` → `apps/Cargo.toml` `[[bin]]`。

# NKM 内核模块二进制格式规范 V1.0

# NKM 内核模块二进制格式规范
> 文档版本：V1.0（对应 Novus OS V1.6-FinalSpec）
> 适用对象：NKM 加载器开发者、驱动开发者、模块签名工具链开发者
> 平台：x86_64 UEFI
> 状态：**格式冻结**；哈希/签名规则已修复并固化，不得变更

---

## 1. 概述

NKM（Novus Kernel Module）是 Novus OS 的内核动态模块格式，扩展名 `.nkm`。
用途：驱动、文件系统扩展、Win32 兼容层、GPU DRM 驱动等可加载组件。

与 NUC（用户态程序）的本质区别：

| 维度 | NUC（用户态） | NKM（内核模块） |
|---|---|---|
| 加载位置 | 用户虚拟地址空间 | 内核地址空间 |
| 权限 | 用户态页表，Ring3 | 内核页表，Ring0 |
| 签名 | 无要求 | **必须 Ed25519 签名** |
| 入口 | `entry_point` 用户函数 | `nkm_init()` + `nkm_exit()` 双入口 |
| 卸载 | 进程退出自动回收 | 需 `nkm_unload` 显式调用 |
| 访问范围 | 仅自己地址空间 | 可访问全部内核符号 |

---

## 2. 文件整体布局

```
偏移 0x0000 ┌──────────────────────────────┐
            │  NKM Header (nkm_hdr_t)      │   固定 208 字节
偏移 0x00D0 ├──────────────────────────────┤
            │  Module Dependencies         │   dep_count × nkm_dep_t (16B/条)
偏移 ...    ├──────────────────────────────┤
            │  Segment Table               │   seg_count × nkm_segment_t (32B/条)
偏移 ...    ├──────────────────────────────┤
            │  Symbol Table                │   sym_count × nkm_sym_t (24B/条)
偏移 ...    ├──────────────────────────────┤
            │  Relocation Table           │   rel_count × nkm_rel_t (16B/条)
偏移 ...    ├──────────────────────────────┤
            │  String Table               │
偏移 ...    ├──────────────────────────────┤
            │  段数据（.text/.data/.rodata）│   4KiB 对齐
            └──────────────────────────────┘
```

---

## 3. NKM Header（文件头）

固定长度 **208 字节**（`0x00D0`），位于文件偏移 `0x0000`，packed。

> 修订说明：本节原文写作「128 字节」，与 3.2 的字段偏移表矛盾——表中
> `reserved[32]` 位于 `0xB0`，加 32 字节后头部实际结束于 `0xD0`；6.3 的
> 摘要规则（清零 `0x50..0xB0`）也只在 208 字节布局下成立。现按**偏移表**
> 统一为 208 字节，3.2 字段定义与 3.3 类型编号均未改动。

### 3.1 结构体定义

```c
#define NKM_MAGIC 0x4E4B4D21   // "NKM!"

typedef struct __attribute__((packed)) {
    uint8_t  magic[4];           // 0x00  "NKM!" = 4E 4B 4D 21
    uint16_t abi_version;        // 0x04  bit[0..7]=minor, bit[8..15]=major
    uint16_t header_size;        // 0x06  = 208 (0xD0)，便于扩展
    uint64_t min_kernel_ver;     // 0x08  最低兼容内核版本
    uint32_t module_type;        // 0x10  模块类型（驱动/FS/兼容层...）
    uint16_t seg_count;           // 0x14  段数量
    uint16_t dep_count;           // 0x16  依赖模块数量
    uint32_t symtab_count;        // 0x18  符号数量
    uint32_t rel_count;           // 0x1C  重定位数量
    uint32_t strtab_offset;       // 0x20  字符串表偏移
    uint32_t rel_offset;          // 0x24  重定位表偏移
    uint32_t init_offset;         // 0x28  nkm_init() 在 .text 内偏移
    uint32_t exit_offset;         // 0x2C  nkm_exit() 在 .text 内偏移
    uint8_t  module_name[32];     // 0x30  模块名（'\0' 结尾）
    uint8_t  module_hash[32];     // 0x50  模块本体 SHA256（签名校验字段）
    uint8_t  module_sig[64];     // 0x70  Ed25519 签名
    uint8_t  reserved[0x20];      // 0xB0  预留 32 字节
} nkm_hdr_t;                        // 总大小 208 字节 (0xD0)
```

### 3.2 字段逐字节定义

| 偏移 | 大小 | 字段 | 取值规则 |
|---|---|---|---|
| 0x00 | 4 | magic | 固定 `NKM!`，不匹配拒绝加载 |
| 0x04 | 2 | abi_version | 高字节=major，低字节=minor。当前 `0x0100` |
| 0x06 | 2 | header_size | 固定 208（0xD0），未来扩展用 |
| 0x08 | 8 | min_kernel_ver | 加载时校验 `内核版本 >= min_kernel_ver` |
| 0x10 | 4 | module_type | 见 §3.3 |
| 0x14 | 2 | seg_count | 段数，1~16 |
| 0x16 | 2 | dep_count | 依赖模块数，0=无依赖 |
| 0x18 | 4 | symtab_count | 符号数量 |
| 0x1C | 4 | rel_count | 重定位数量 |
| 0x20 | 4 | strtab_offset | 字符串表文件偏移 |
| 0x24 | 4 | rel_offset | 重定位表文件偏移 |
| 0x28 | 4 | init_offset | `nkm_init()` 在 .text 段内字节偏移 |
| 0x2C | 4 | exit_offset | `nkm_exit()` 在 .text 段内字节偏移 |
| 0x30 | 32 | module_name | 模块名，`\0` 结尾，最长 31 字符 |
| 0x50 | 32 | module_hash | 模块本体 SHA256（见 §6） |
| 0x70 | 64 | module_sig | Ed25519 签名（见 §6） |
| 0xB0 | 32 | reserved | 必须全 0 |

### 3.3 module_type 取值

| 值 | 名称 | 说明 |
|---|---|---|
| 0 | `NKM_TYPE_DRIVER` | 硬件驱动（VGA/DP/存储/PCI） |
| 1 | `NKM_TYPE_FS` | 文件系统驱动 |
| 2 | `NKM_TYPE_COMPAT` | 兼容层（Win32） |
| 3 | `NKM_TYPE_CRYPTO` | 加密模块 |
| 4 | `NKM_TYPE_OTHER` | 其他扩展 |

---

## 4. 模块依赖表

紧接 Header 之后，共 `dep_count` 条，每条 **16 字节**。

```c
typedef struct __attribute__((packed)) {
    uint32_t dep_name_off;      // 0x00  依赖模块名在 String Table 的偏移
    uint64_t min_dep_ver;       // 0x04  依赖模块最低版本
    uint32_t reserved;           // 0x0C  必须为 0
} nkm_dep_t;                     // 16 字节
```

加载规则：
1. 加载器按依赖表顺序，**先加载被依赖的模块**；
2. 依赖模块未加载 → 自动递归加载；
3. 依赖模块版本不满足 `min_dep_ver` → 拒绝加载本模块；
4. 依赖表出现循环依赖 → 拒绝加载，返回 `NOVUS_EDEP`。

---

## 5. 段表 / 符号表 / 重定位表

格式与 NUC 完全一致（见《NUC 二进制格式规范》第 4/5/7 节），差异点：

| 项 | NKM 差异 |
|---|---|
| 段 vaddr | 加载到**内核地址空间**（高地址区，非用户区） |
| 段权限 | 全部 Ring0，不要求 `VM_USER`；TEXT 可执行，DATA 可写 |
| 外部符号 | 解析到**内核导出符号表**（`nksym`），而非系统 SDK |
| 重定位类型 | 仅 `R_X86_64_64`（64 位绝对地址），内核模块不使用 PC32 |

内核导出符号示例（`nksym` 表，由内核 vmlinux 提供）：
```
mm_alloc, mm_free, vm_map, vm_unmap
sched_spawn, sched_exit
vfs_register_fs, vfs_read, vfs_write
hal_display_probe, hal_display_flush
cap_check, log_print, err_report
pci_enumerate, blk_read, blk_write
```

---

## 6. Ed25519 签名与哈希（核心，已冻结）

### 6.1 密码套件

- 哈希：SHA256
- 签名：Ed25519（RFC 8032）
- 公钥：32 字节
- 签名：64 字节

### 6.2 内核公钥池

```c
// 编译时固化在内核镜像中，运行时不可写、不可改
static const ed25519_pubkey_t kernel_trusted_keys[4] = {
    /* 公钥1 */, /* 公钥2 */, /* 公钥3 */, /* 公钥4 */
};
static const uint8_t trusted_key_count = 1; // 初始仅1把，后续版本追加
```

- 最多支持 **4 把**公钥；
- 仅编译时可更新（密钥轮换 = 发新版内核）；
- **运行时不接受用户导入公钥**；
- 验证时轮询所有公钥，任一通过即合法。

### 6.3 哈希计算范围（已修复冲突，冻结）

> **关键规则**：SHA256 计算范围 = 整个模块文件，**但跳过 `module_hash[32]` 和 `module_sig[64]` 两个字段**。

具体操作（签名工具与加载器必须一致）：

```
1. 拷贝整个模块文件到内存 temp_buf
2. 将 temp_buf 中偏移 0x50 起共 96 字节（32+64）置 0
   —— 即把 module_hash 和 module_sig 两个字段清零
3. computed_hash = SHA256(temp_buf, 文件总长度)
4. 比对 computed_hash 与头部原始 module_hash：
     不一致 → 哈希校验失败，拒绝加载
```

### 6.4 签名验证流程

```
1. 计算出 computed_hash（同 §6.3）
2. 比对 computed_hash == nkm_hdr.module_hash
3. 取头部 module_sig（64 字节）作为 Ed25519 签名
4. 取 nkm_hdr.module_hash（32 字节）作为签名原文
5. 遍历 kernel_trusted_keys[]：
     if ed25519_verify(module_hash, module_sig, pubkey[i]):
         → 校验通过，跳出
6. 全部公钥校验失败 → 拒绝加载
```

### 6.5 为什么跳过 hash+sig 字段

如果哈希包含自身签名，会造成"鸡生蛋"问题：签名依赖哈希，哈希依赖签名字节。
置零后计算哈希，使哈希与签名解耦：哈希覆盖"除自描述字段外的全部内容"，签名再对这个哈希做签名。

---

## 7. 模块入口函数约定

每个 NKM 模块必须导出两个函数，通过 `init_offset` / `exit_offset` 指向：

```c
// 模块初始化（加载时调用一次）
// 返回 0 成功，负数错误码
int nkm_init(void);

// 模块卸载（卸载时调用一次）
// 返回 0 成功
int nkm_exit(void);
```

调用约定：
- 与系统调用 ABI 一致（x86_64 SysV）；
- `nkm_init` 返回非 0 → 加载失败，已分配资源自动回滚；
- `nkm_exit` 必须释放所有申请的内核资源（内存、IRQ、设备注册），否则卸载后系统状态不一致。

---

## 8. 加载完整流程（冻结）

```
1. nkm_load(path) 被调用
2. 校验调用者 cap_check(mod.load)，无权限 → NOVUS_EPERM
3. VFS 打开文件，读取前 208 字节（Header）
4. 校验 magic == "NKM!"
5. 校验 abi_version 主版本号
6. 校验 min_kernel_ver <= 当前内核版本
7. 拷贝整个文件到内核内存
8. 执行哈希校验：
   a. 临时副本中 0x50..0xB0 置 0
   b. 计算 SHA256
   c. 与 module_hash 比对
   失败 → NOVUS_ECORRUPT
9. 执行 Ed25519 签名校验（轮询公钥池）
   失败 → NOVUS_EMODULE
   （管理员单次临时放行：跳过第 9 步，打警告日志）
10. 按依赖表递归加载依赖模块
11. 映射段到内核地址空间
12. 解析重定位（外部符号查内核 nksym 表）
13. 调用 nkm_init()
14. init 返回 0 → 注册到模块列表，返回成功
15. init 失败 → 回滚段映射，返回错误
```

---

## 9. 卸载流程

```
1. nkm_unload(name) 被调用
2. 校验 cap_check(mod.unload)
3. 检查模块是否被其他模块依赖（dep_count 反向引用）
   被依赖 → 拒绝卸载，NOVUS_EBUSY
4. 调用 nkm_exit()
5. 解除段映射
6. 从模块列表移除
7. 释放模块内存
```

---

## 10. 管理员临时放行策略

- 普通用户：未签名模块**一律拒绝加载**；
- 管理员（拥有 `mod.load` CAP）：可加载未签名模块，但：
  - 必须在加载时显式传入 `NKM_FLAG_ALLOW_UNSIGNED`；
  - 内核打印 WARNING 日志，记录模块名、PID、时间；
  - **仅本次会话有效**，不持久保存信任；
  - 重启后该模块不会自动加载。

---

## 11. 错误码

| 错误码 | 含义 |
|---|---|
| `NOVUS_OK (0)` | 加载成功 |
| `NOVUS_EPERM (-4)` | 无 `mod.load` / `mod.unload` CAP |
| `NOVUS_EINVAL (-1)` | 头部字段非法 |
| `NOVUS_ECORRUPT (-7)` | SHA256 哈希不匹配 |
| `NOVUS_EMODULE (-8)` | Ed25519 签名验证失败 |
| `NOVUS_EBUSY (-5)` | 模块被依赖，无法卸载 |
| `NOVUS_ENOTFOUND (-3)` | 依赖模块缺失 |
| `NOVUS_EDEP (-12)` | 循环依赖 |
| `NOVUS_EIO (-6)` | 文件读取失败 |
| `NOVUS_ENOMEM (-2)` | 内核内存不足 |

---

## 12. 完整示例：一个最小驱动模块

### 12.1 Header 关键字段

```
magic:          4E 4B 4D 21  ("NKM!")
abi_version:    00 01        (major=1, minor=0)
header_size:    D0 00        (208)
min_kernel_ver: 00 00 00 00 00 00 00 01   (要求内核 >= 1.0)
module_type:    00 00 00 00  (DRIVER)
seg_count:      02 00         (2段)
dep_count:      00 00         (无依赖)
symtab_count:   01 00 00 00
rel_count:      02 00 00 00
strtab_offset:  00 02 00 00   (0x200)
rel_offset:     C0 01 00 00   (0x1C0)
init_offset:    10 00 00 00   (.text+0x10)
exit_offset:    30 00 00 00   (.text+0x30)
module_name:    "nvme.ko" 00 00...
module_hash:    <32字节SHA256>
module_sig:     <64字节Ed25519签名>
```

### 12.2 模块源码骨架（C）

```c
#include <novus/nkm.h>
#include <novus/mm.h>
#include <novus/log.h>

static void* buf = NULL;

int nkm_init(void)
{
    log_print(LOG_INFO, "nvme driver init\n");
    buf = mm_alloc(1);
    if (!buf) return NOVUS_ENOMEM;
    // 注册 NVMe 控制器
    return NOVUS_OK;
}

int nkm_exit(void)
{
    log_print(LOG_INFO, "nvme driver exit\n");
    if (buf) mm_free(buf, 1);
    return NOVUS_OK;
}
```

NUC 与 NKM 是不同格式：`cppcc` 只生成用户态 `.nuc`，不参与 NKM 目标文件编译或签名。
当前仓库的 `tools/nkmgen` 是主机端 NKM 测试镜像生成器，复用内核 Ed25519/SHA 实现生成并签名测试模块；它不是通用 C/C++ NKM 编译器。通用驱动目标文件到 NKM 的生产工具链不属于 cppcc。

---

## 13. 文档冻结声明

本规范为 NKM 内核模块格式唯一基准文档。约束：

- Header 208 字节布局（0x00D0），含 reserved[32]；
- 哈希跳过 0x50..0xB0（hash+sig 字段）后计算 SHA256；
- Ed25519 签名原文 = `module_hash`（32 字节）；
- 内核公钥池最多 4 把，编译时固化；
- 入口固定 `nkm_init` / `nkm_exit`；
- 依赖表递归加载，禁止循环依赖。

任何变更必须走 ABI 变更 RFC，升版本号。

文档状态： **可作为 M3（NKM 加载器）与 M10（驱动生态）的实现基准。**

# Novus OS Debug 级接口手册 V1.0

# Novus OS Debug 级接口手册
> 文档版本：V1.0（对应 Novus OS V1.6-FinalSpec）
> 用途：开发调试手册，每个接口展开到参数级、错误码级、前置/后置条件、调试检查点
> 配套：《全部接口总表》《NUC 格式规范》《NKM 格式规范》
> 状态：冻结

---

## 0. 阅读指南

每个接口条目包含：
1. **原型**：C 函数签名
2. **所属子系统**
3. **调用方 / 被调用方**
4. **前置条件**：调用前必须满足什么（锁、CAP、中断状态、内存）
5. **参数表**：逐字段类型、取值范围、单位、默认值、说明
6. **返回值**：逐情况说明
7. **错误码对照表**：什么情况返回什么错误码
8. **后置条件**：返回后系统状态变化
9. **调试检查点**：开发时应该打日志/断言的位置
10. **使用示例**：最小调用代码
11. **常见 Bug**：易犯错误

---

## 1. 通用错误码（全局复用）

| 值 | 宏名 | 含义 | 触发场景举例 |
|---|---|---|---|
| 0 | NOVUS_OK | 成功 | 一切正常 |
| -1 | NOVUS_EINVAL | 参数无效 | 指针为NULL、长度为0、枚举值越界 |
| -2 | NOVUS_ENOMEM | 内存不足 | 页分配失败、缓冲区不够 |
| -3 | NOVUS_ENOTFOUND | 对象不存在 | 路径不存在、符号未找到、设备不存在 |
| -4 | NOVUS_EPERM | 权限不足 | cap_check() 返回 false |
| -5 | NOVUS_EBUSY | 资源忙 | 锁超时、文件被占用、模块被依赖 |
| -6 | NOVUS_EIO | IO错误 | 磁盘读失败、PCI读写错误 |
| -7 | NOVUS_ECORRUPT | 数据损坏 | SHA256不匹配、CRC32校验失败 |
| -8 | NOVUS_EMODULE | 模块错误 | 签名校验失败、ABI不兼容 |
| -9 | NOVUS_EFULL | 队列满 | IPC队列满、WAL日志满 |
| -10 | NOVUS_EAGAIN | 重试 | 资源暂时不可用 |
| -11 | NOVUS_EOVERFLOW | 溢出 | 段大小越界、文件偏移超出文件长度 |
| -12 | NOVUS_EDEP | 循环依赖 | 模块依赖图成环 |

---

## 2. SMP / AB 双核接口

### 2.1 `smp_shmem_write`

```c
void smp_shmem_write(uint32_t offset, uint64_t val);
```

- **所属**：SMP 启动
- **调用方**：A核(BSP)
- **前置条件**：
  - 共享内存物理页已预留（A核早期分配）
  - 调用者已持有 `smp_shmem_lock()`（如多核心并发写）
  - 本地中断状态：允许开中断
- **参数**：

| 参数 | 类型 | 范围 | 说明 |
|---|---|---|---|
| offset | uint32_t | 0 ~ 4095 | 共享内存内偏移，必须 8 字节对齐 |
| val | uint64_t | 任意 | 要写入的值 |

- **返回值**：无（void）
- **后置条件**：共享内存指定偏移处值更新；CPU 缓存一致性由 `sfence` 保证
- **调试检查点**：
  - 写入后立即读回比对：`assert(smp_shmem_read(offset) == val);`
  - 打印：`log_print(DEBUG, "shmem write off=%u val=%lx\n", offset, val);`
- **常见 Bug**：offset 未对齐导致原子性破坏；忘记持锁导致竞态

### 2.2 `smp_shmem_read`

```c
uint64_t smp_shmem_read(uint32_t offset);
```

- **调用方**：B核(AP)
- **前置条件**：共享内存已映射到 AP 页表
- **参数**：offset 同上
- **返回值**：指定偏移处的值
- **调试检查点**：读取 `bsp_state` 时循环等待，超时 200ms 判定启动失败

### 2.3 `smp_shmem_lock` / `smp_shmem_unlock`

```c
int smp_shmem_lock(void);
void smp_shmem_unlock(void);
```

- **锁类型**：自旋锁
- **自旋上限**：1,000,000 次
- **超时返回**：`NOVUS_EBUSY (-5)`
- **调试检查点**：
  - 加锁前后打日志
  - 超时触发时打印当前锁持有者信息（如实现了锁调试）
- **注意**：锁内禁止调用可能睡眠的函数（此时调度器未启动）

### 2.4 `acore_enter_sleep`

```c
void acore_enter_sleep(void);
```

- **调用方**：A核自检完成后
- **前置条件**：
  - 所有硬件信息已写入共享内存
  - IPI 已发送给所有 AP
  - `bsp_state` 已置 2
- **行为**：进入 `cli; hlt;` 无限循环
- **后置条件**：BSP 不再执行任何指令
- **调试检查点**：进入前打印 "Acore entering sleep"

### 2.5 `smp_wake_ap`

```c
int smp_wake_ap(uint64_t ap_id);
```

- **前置条件**：
  - `bsp_state` 已置 2
  - 已执行 `sfence`
  - AP 启动栈地址已写入共享内存
- **参数**：ap_id = AP 核心编号
- **行为**：发送 IPI 向量 0x80
- **返回值**：0 成功；-ENOMEM 失败
- **调试检查点**：发送后等待 `ap_ready` 标志，超时 200ms → 重启

### 2.6 `smp_ap_signal_ready`

```c
void smp_ap_signal_ready(void);
```

- **调用方**：AP 完成 GDT/IDT/页表初始化后
- **后置条件**：共享内存 `ap_ready = 1`；BSP 检测到后休眠

---

## 3. 内存管理接口

### 3.1 `mm_alloc`

```c
void* mm_alloc(size_t pages);
```

- **所属**：物理内存管理
- **前置条件**：
  - 物理内存管理器已初始化（M1 之后）
  - 调用者不在中断上下文（或使用 GFP_ATOMIC 标志）
- **参数**：

| 参数 | 类型 | 单位 | 说明 |
|---|---|---|---|
| pages | size_t | 4KiB/页 | 要分配的连续物理页数 |

- **返回值**：
  - 成功：内核虚拟地址（已映射）
  - 失败：`NULL`
- **错误码**：返回 NULL 即失败（不通过返回值传错码）
- **后置条件**：
  - 物理页已保留（从空闲位图标记为已占用）
  - 已映射到内核虚拟地址空间
- **调试检查点**：
  - 分配后打印：`log_print(DEBUG, "mm_alloc %zu pages -> %p\n", pages, ptr);`
  - 检查返回值是否对齐：`assert((uint64_t)ptr % 4096 == 0);`
- **常见 Bug**：
  - pages=0 直接 panic
  - 分配后忘记 `mm_free` → 内存泄漏
  - 在中断上下文调用可睡眠版本 → 死锁

### 3.2 `mm_free`

```c
void mm_free(void* vaddr, size_t pages);
```

- **参数**：
  - vaddr：`mm_alloc` 返回的地址
  - pages：必须与分配时一致
- **后置条件**：物理页归还空闲位图；虚拟映射解除
- **调试检查点**：释放后打印地址；检查双重释放（位图标记）

### 3.3 `vm_map`

```c
int vm_map(uint64_t va, uint64_t pa, uint64_t len, uint32_t flags);
```

- **参数**：

| 参数 | 类型 | 单位 | 说明 |
|---|---|---|---|
| va | uint64_t | 字节 | 虚拟起始地址，4KiB 对齐 |
| pa | uint64_t | 字节 | 物理起始地址，4KiB 对齐 |
| len | uint64_t | 字节 | 长度，4KiB 对齐 |
| flags | uint32_t | 位掩码 | bit0=READ bit1=WRITE bit2=EXEC bit3=USER |

- **返回值**：0 成功；负数错误码
- **错误码**：
  - -EINVAL：va/pa/len 未对齐
  - -ENOMEM：页表分配失败
- **调试检查点**：映射后读 CR3 验证 TLB；打印映射范围
- **W^X 原则**：flags 同时置 WRITE 和 EXEC → 拒绝（返回 -EINVAL）

### 3.4 `vm_unmap`

```c
int vm_unmap(uint64_t va, uint64_t len);
```

- 解除映射，释放页表项
- 后置条件：访问该地址触发页错误

### 3.5 `oom_scan`

```c
int oom_scan(proc_info_t* out);
```

- **前置条件**：内存水位 < 10%
- **行为**：遍历所有进程，按评分公式计算分数
- **评分公式（冻结）**：
  ```
  score = rss_bytes * front_weight * age_weight * type_weight
  front_weight:  前台=1.8, 后台=1.0
  age_weight:    <30s=1.0, 30s~5min=0.7, >5min=0.4
  type_weight:   普通=1.0, 系统辅助=0.2
  ```
- **保护列表**（永不参与评分）：init、novus-wm、novus-settings、novus-taskmgr
- **返回值**：0 找到候选进程，写入 out；-ENOMEM 无候选进程可杀
- **调试检查点**：
  - 打印每个进程的 score
  - 打印选中的 victim
- **常见 Bug**：误杀保护列表进程 → 系统崩溃

### 3.6 `oom_reclaim`

```c
int oom_reclaim(uint32_t level);
```

- **参数**：level
  - 0 = 温和：只回收页缓存、目录项缓存
  - 1 = 紧急：回收离屏 FB、NovusFS 冗余缓存
- **回收顺序（冻结）**：文件页缓存 → 目录项缓存 → 图形离屏缓冲 → NovusFS 缓存
- **防抖**：1 秒内最多触发一次全局回收

---

## 4. 调度器接口

### 4.1 `sched_spawn`

```c
int sched_spawn(const char* path, uint64_t caps, pid_t* out_pid);
```

- **前置条件**：
  - 调用者拥有 `sys.proc.ctrl` CAP（创建系统进程）
  - path 指向的 .nuc 文件存在
- **参数**：

| 参数 | 说明 |
|---|---|
| path | .nuc 文件路径，如 "/system/bin/novus-settings" |
| caps | 进程初始 CAP 掩码（低64位） |
| out_pid | 输出参数，成功写入新 PID |

- **返回值**：0 成功；负数错误码
- **错误码**：
  - -ENOENT：文件不存在
  - -EINVAL：.nuc 头部校验失败
  - -ENOMEM：无法分配进程地址空间
- **调试检查点**：打印新进程 PID、入口地址、初始栈
- **后置条件**：进程加入就绪队列，等待调度

### 4.2 `sched_ctl`

```c
int sched_ctl(pid_t pid, uint32_t op, void* arg);
```

- **参数 op**：
  - 0 = 暂停进程（SIGSTOP）
  - 1 = 恢复进程（SIGCONT）
  - 2 = 终止进程（SIGKILL）
  - 3 = 调试 attach
- **CAP**：`sys.proc.ctrl`
- **调试检查点**：打印 pid、op、返回值

### 4.3 `sched_exception_report`

```c
int sched_exception_report(pid_t pid, exc_info_t* exc);
```

- **触发时机**：用户态进程触发页错误/非法指令/除零
- **行为**：
  1. 收集寄存器状态到 exc_info_t
  2. 不 panic，不杀进程
  3. 通过 IPC 发消息给 novus-wm
  4. WM 弹出错误对话框
- **exc_info_t 字段**：

```c
typedef struct {
    uint64_t pid;
    uint64_t rip;        // 出错指令地址
    uint64_t cr2;        // 页错误地址
    uint32_t err_code;   // 错误码
    char proc_name[64];
    uint8_t  cause;      // 0=页错误 1=非法指令 2=除零 3=断点
} exc_info_t;
```

---

## 5. 安全/CAP 接口

### 5.1 `cap_check`

```c
int cap_check(proc_cap_t* p, uint32_t bit);
```

- **参数**：
  - p：进程的 CAP 结构指针
  - bit：要检查的位号（0~31）
- **返回值**：
  - 1：拥有该权限
  - 0：没有该权限
- **实现**：
  ```c
  return (p->cap_mask_low >> bit) & 1;
  ```
- **调试检查点**：权限拒绝时打印进程名、请求的 bit 号
- **常见 Bug**：bit 号写错（off-by-one）；忘记检查导致越权

### 5.2 `cap_drop`

```c
int cap_drop(proc_cap_t* p, uint32_t bit);
```

- **行为**：清除指定位（不可逆）
- **用途**：进程初始化完成后主动降权（最小权限）
- **返回值**：0 成功；-EINVAL bit 越界

### 5.3 `nkm_load`

```c
int nkm_load(const char* path);
```

- **前置条件**：调用者拥有 `mod.load` CAP
- **执行步骤（debug 级）**：
  1. 打开文件，读前 128 字节 Header
  2. 校验 magic == "NKM!" → 失败返回 -ENOENT
  3. 校验 abi_version 主版本 == 1 → 否则 -EINVAL
  4. 校验 min_kernel_ver <= 当前内核版本 → 否则 -EMODULE
  5. 拷贝整个文件到内核内存
  6. **哈希校验**：
     - 临时副本中偏移 0x50 起 96 字节置 0
     - 计算 SHA256
     - 与头部 module_hash 比对 → 不匹配 -ECORRUPT
  7. **签名校验**：
     - 遍历 kernel_trusted_keys[0..key_count-1]
     - 对 module_hash 做 Ed25519 verify
     - 全部失败 → -EMODULE
     - （管理员放行：传 NKM_FLAG_ALLOW_UNSIGNED 跳过此步）
  8. 递归加载依赖
  9. 映射段到内核地址空间
  10. 应用重定位
  11. 调用 nkm_init() → 非0返回则回滚
- **调试检查点**：每一步打日志，失败时打印具体步骤
- **常见 Bug**：
  - 哈希计算时忘记置零 hash+sig 字段 → 永远不匹配
  - 重定位时外部符号没找到 → 内核 oops

---

## 6. VFS 接口

### 6.1 `vfs_open`

```c
int vfs_open(const char* path, uint32_t flags, uint32_t mode);
```

- **参数 flags**：
  - bit0 = O_RDONLY
  - bit1 = O_WRONLY
  - bit2 = O_RDWR
  - bit3 = O_CREAT
  - bit4 = O_TRUNC
- **路径检查**：
  - `/system` 下写操作需要 `fs.full` CAP
  - 路径解析失败 → -ENOENT
- **返回值**：文件描述符（正整数）；负数错误码
- **调试检查点**：打印 path、flags、返回的 fd

### 6.2 `vfs_read` / `vfs_write`

```c
int vfs_read(int fd, void* buf, uint64_t len);
int vfs_write(int fd, const void* buf, uint64_t len);
```

- **参数**：
  - fd：vfs_open 返回的描述符
  - buf：缓冲区指针
  - len：要读/写的字节数
- **返回值**：实际读/写字节数；负数错误码
- **调试检查点**：打印 fd、len、实际传输量
- **常见 Bug**：buf 为 NULL；fd 越界；文件指针未推进

---

## 7. NovusFS 接口

### 7.1 `novusfs_alloc_block`

```c
int novusfs_alloc_block(uint64_t* out_block);
```

- **前置条件**：持有块分配器锁
- **行为**：扫描块位图找第一个空闲位
- **返回值**：0 成功，*out_block 填入块号
- **错误码**：
  - -ENOSPC：磁盘满
  - -ECORRUPT：位图标记了坏块但块号仍被分配
- **调试检查点**：打印分配的块号；验证位图已置 1
- **锁顺序**：超级块锁 → 目录锁 → inode锁 → **块分配器锁**（最内层）

### 7.2 WAL 事务

#### `wal_begin_tx`
```c
int wal_begin_tx(uint32_t type, uint64_t block_no, wal_tx_t* out);
```
- type：0=块写 1=inode修改 2=目录修改
- 写入 PREP 记录到 WAL 区
- 返回 0 成功；-EFULL 日志区满

#### `wal_commit`
```c
int wal_commit(wal_tx_t* tx, const void* data, uint32_t len);
```
- 写数据 + COMMIT 记录
- 后置：事务持久化

#### `wal_rollback`
```c
void wal_rollback(wal_tx_t* tx);
```
- 丢弃 PREP 记录（不写 COMMIT）

#### WAL 满判定
```c
// 满条件：write_ptr == tail_ptr
if (wal_write_ptr == wal_tail_ptr) {
    // 推进 tail 到下一个完整事务边界
    wal_advance_tail();
}
```

---

## 8. Merkle 树接口

### 8.1 `merkle_verify_root`

```c
int merkle_verify_root(dev_t dev, const uint8_t expect[32]);
```

- **调用方**：A核开机自检
- **行为**：
  1. 读取超级块中的 merkle_root_primary
  2. 如果 primary 损坏，读 backup
  3. 比对 expect（A核自己计算的哈希）与存储的根
  4. 不一致 → 返回 -ECORRUPT
- **错误码**：
  - -ECORRUPT：哈希不匹配
  - -EIO：磁盘读失败
- **调试检查点**：打印 expect 和 stored 两个哈希的前 8 字节

### 8.2 节点磁盘映射

```c
// idx: 节点索引（根=1）
uint64_t node_to_block(uint64_t idx) {
    return merkle_start_block + (idx / 64);
}
uint64_t node_offset_in_block(uint64_t idx) {
    return (idx % 64) * 64;
}
```

- **边界检查**：
  - leaf_count == 0 → 拒绝挂载
  - leaf_count == 1 → 树高=2，根=1，叶子起始=2

---

## 9. 图形栈系统调用

### 9.1 `sys_gfx_create_surface`

```c
int sys_gfx_create_surface(uint32_t w, uint32_t h, uint32_t fmt, fb_handle_t* out);
```

- **参数**：
  - w/h：宽高（像素）
  - fmt：0=BGRA8888, 1=BGR24
  - out：输出帧缓冲句柄
- **LowMem 限制**：最多 4 个离屏 FB
- **Full 限制**：最多 16 个
- **调试检查点**：打印 w、h、分配的 fb 地址
- **错误码**：-ENOMEM 分配失败

### 9.2 `sys_gfx_submit_dirty`

```c
int sys_gfx_submit_dirty(fb_handle_t h, const rect_t* rects, uint32_t n);
```

- **参数 rect_t**：
  ```c
  typedef struct {
      uint32_t x, y, w, h;
  } rect_t;
  ```
- **限制**：n 最大 8（Full）/ 4（LowMem）
- **行为**：标记窗口脏区域，触发合成器重绘
- **调试检查点**：打印 rect 数量和坐标

---

## 10. IPC 接口

### 10.1 `ipc_send`

```c
int ipc_send(novus_ipc_hdr_t* hdr, const void* payload);
```

- **前置条件**：
  - 调用者已通过 `ipc_bind` 注册通道
  - 拥有对应窗口的归属权（或 gui.override CAP）
- **hdr 必须字段**：
  - magic = 0x4E574D49
  - sender_pid = 当前进程 PID
  - msg_type = 有效消息类型
  - payload_len = 实际 payload 长度
- **错误码**：
  - -EFULL：目标队列满
  - -EINVAL：magic 错误
  - -EPERM：无权限
- **调试检查点**：打印 msg_type、target_pid、payload_len

---

## 11. 系统调用 ABI（debug 要点）

### 11.1 寄存器约定

| 用途 | 寄存器 |
|---|---|
| 调用号 | rax |
| 参数1 | rdi |
| 参数2 | rsi |
| 参数3 | rdx |
| 参数4 | rcx |
| 参数5 | r8 |
| 参数6 | r9 |
| 返回值 | rax |
| 被调用者保存 | rbp, rbx, r12, r13, r14, r15 |

### 11.2 常见调试技巧

1. **系统调用号打印**：在 syscall 入口打印 rax 和参数
2. **返回值检查**：用户态库包装后检查 rax 是否为负
3. **栈对齐**：进入内核时检查 rsp % 16 == 0
4. **权限拒绝**：syscall 入口先 cap_check，拒绝时打印 bit 号

---

## 12. 日志接口

### 12.1 `log_print`

```c
void log_print(uint32_t level, const char* fmt, ...);
```

- **level**：
  - 0 = DEBUG（开发调试）
  - 1 = INFO（正常信息）
  - 2 = WARN（警告）
  - 3 = ERROR（错误）
- **行为**：写入环形缓冲区 + 串口输出
- **LowMem**：DEBUG 级别不输出（节省串口带宽）
- **调试检查点**：模块初始化函数开头打 INFO

### 12.2 `panic_handler`

```c
void panic_handler(cpu_state_t* state);
```

- **触发时机**：内核致命错误（双重缺页、致命锁死）
- **行为**：
  1. 关中断
  2. VGA 文本模式打印寄存器转储
  3. HLT 死循环
- **绝不**返回。用户态进程崩溃走 `sched_exception_report`，不走 panic。

---

## 13. 调试通用建议

### 13.1 打印策略
- 模块 init：打 INFO
- 关键错误：打 ERROR + 错误码
- 调试细节：打 DEBUG（LowMem 关闭）
- 不要在中断高频路径打日志（VSync 每帧）

### 13.2 断言
- 指针非 NULL：`assert(ptr != NULL);`
- 对齐：`assert((uint64_t)addr % 16 == 0);`
- 锁持有：调试时可记录当前锁持有者
- 返回值：`int ret = foo(); assert(ret == NOVUS_OK);`

### 13.3 常见 Bug 清单
1. **忘记持锁** → 多进程竞态
2. **锁顺序错误** → 死锁（必须按 超级块→目录→inode→块分配）
3. **双重释放** → 内存 corruption
4. **偏移未对齐** → x86_64 严格对齐异常
5. **CAP 忘记检查** → 越权访问
6. **WAL 写了 PREP 没写 COMMIT** → 崩溃后数据丢失
7. **Merkle 哈希包含了自身 hash 字段** → 校验永远失败
8. **NKM 签名时公钥不匹配** → 模块无法加载

---

## 文档状态

本文档为 Debug 级接口手册，开发时对照此文档逐行检查代码。
所有函数签名、参数、错误码、前置条件已冻结。

文档状态：✅ **冻结，可作为 M0–M10 开发调试基准。**

# Novus OS 自研分级增量更新体系完整规范

# 1\. Novus OS 自研更新架构核心体系

Novus OS 搭载完全自研、独立可控、工业级稳定的**分类补丁、分级推送、分通道灰度、断点续传、事务原子回滚、服务端统一管控**更新体系，专为自研操作系统量身设计，架构轻量化、逻辑透明、可手动调试、可全自动批量部署，为系统长期迭代、安全风控、软件运维提供标准化底层支撑。

## 1\.1 Novus OS 三大官方补丁体系（永久冻结）

- **\.hotpth 紧急安全热修复补丁**：专注高危漏洞、远程代码执行、内核提权、权限绕过等安全风险紧急兜底修复，最高系统优先级，强制静默更新

- **\.npth 系统通用累积补丁**：负责系统内核、NKM驱动、HAL层、系统基础库、核心服务的常规累积迭代、稳定性优化与功能迭代

- **\.apth 应用软件专属补丁**：面向NUC应用、第三方软件、桌面组件、用户工具的独立增量更新，隔离系统核心层与用户应用层更新逻辑

- **\.novu 全量安装包**：承接系统大版本跨代升级、首次装机、系统重置重装场景，作为增量补丁的底层兜底载体（替代已占用NUP格式，为全新自研专属后缀）

## 1\.2 Novus OS 五级官方更新推送通道（永久冻结）

系统内置自研五级更新分级机制，覆盖从紧急安全修复、稳定版本推送、灰度功能预览、普通可选更新、开发者内测更新全场景，分级策略独立、权限隔离、互不干扰，适配普通用户、进阶用户、开发者、企业批量运维全群体需求：

1. **紧急安全推送（level\_urgent）**：专属安全漏洞热修复，系统最高优先级，无拦截、无延后、强制即时修复

2. **稳定推荐推送（level\_recommend）**：系统与软件稳定版迭代更新，默认推荐安装，保障设备稳定性与兼容性

3. **版本预览推送（level\_preview）**：新功能灰度尝鲜版本，仅主动查询可见，无被动弹窗推送

4. **普通可选推送（level\_optional）**：非必要体验优化、辅助功能迭代，用户自主选择安装或忽略

5. **开发者内测推送（level\_dev）**：开发调试版、未稳定内测版本，默认隐藏，仅开发者模式解锁可见

# 2\. Novus OS 自研更新核心机制与技术规范

## 2\.1 服务端核心：全局唯一统一更新大表架构

Novus OS 远程更新服务端采用自研**单全局唯一更新索引大表**架构，为所有终端设备更新的唯一权威数据源，摒弃分散分表的复杂设计，架构极简、检索高效、运维便捷。

核心运行逻辑：

- 服务端统一收录全部 \.npth/\.apth/\.hotpth 格式补丁数据，集中管控所有版本、灰度、策略信息

- 客户端后台常驻定时轮回查询大表，静默完成版本比对与补丁匹配

- 所有复杂逻辑（版本适配、分级筛选、灰度命中、策略判定）由服务端统一完成

- 客户端仅负责下载、校验、执行更新，逻辑轻量化，降低系统资源占用与故障概率

## 2\.2 客户端核心：分层优先级更新队列机制（冻结）

系统内置固定优先级更新队列，多补丁同时存在时，严格按照既定优先级串行执行，避免更新冲突、资源抢占、版本错乱问题。

**更新执行优先级（从高至低，永久冻结）**：

\.hotpth 紧急安全热修复 \> \.npth 系统累积更新 \> \.apth 关键软件更新 \> 预览版灰度更新 \> 普通可选更新 \> Dev开发者内测更新

## 2\.3 自研事务性原子更新与智能回滚机制

- 更新前置自动快照备份系统关键文件、权限配置、版本信息，留存完整回滚镜像

- 针对更新中断、设备断电、文件异常、校验失败等所有异常场景，触发全自动事务回滚

- 严格杜绝半更新状态，保障系统文件完整性与运行稳定性

- 所有更新操作具备事务唯一性，要么全部成功生效，要么完整还原初始状态

## 2\.4 自研差分增量更新与断点续传机制

- 全系补丁默认启用字节级差分增量更新，仅传输文件变更数据块，极大降低远程更新流量开销

- 内置下载进度持久化模块，支持断网、断电、退出中断后无缝接续下载

- 安装阶段支持断点续执行，已完成的差分块、文件操作无需重复执行，提升更新效率

# 7\. Novus OS 更新体系二进制文件头规范（全局冻结｜可直接编码）

本节定义 **\.novu / \.npth / \.apth / \.hotpth** 四类更新载体的统一二进制文件头结构。所有结构体强制 `packed`、4字节对齐、字段偏移永久锁定，用于解析器精准识别文件类型、校验合法性、读取更新策略，杜绝后缀伪造、文件篡改、格式错乱。

核心设计原则：**后缀与文件头魔数强绑定、类型字段二次校验、标志位控制行为、全局哈希防篡改、预留位保证向前兼容**。

## 7\.1 全局公共定义（全部文件通用｜冻结）

```c
// 全局版本冻结
#define NOVUS_UPDATE_HDR_VER_MAJOR 1
#define NOVUS_UPDATE_HDR_VER_MINOR 0

// 文件类型枚举（永久唯一）
#define NOVU_TYPE_FULL       0   // .novu 全量安装包
#define NOVU_TYPE_SYS_PATCH  1   // .npth 系统通用补丁
#define NOVU_TYPE_APP_PATCH  2   // .apth 软件专属补丁
#define NOVU_TYPE_HOT_PATCH  3   // .hotpth 紧急热修复补丁

// 五级更新分级枚举（绑定服务端大表策略）
#define UPDATE_LVL_OPTIONAL    0
#define UPDATE_LVL_RECOMMEND   1
#define UPDATE_LVL_PREVIEW     2
#define UPDATE_LVL_URGENT      3
#define UPDATE_LVL_DEV         4

```

## 7\.2 四类文件专属魔数（防伪造｜一一对应｜冻结）

文件头魔数为第一校验依据，后缀仅为系统展示用，**解析器以魔数为准**，防止手动改后缀伪装补丁。

```c
// 小端内存序、文件存储序统一
#define NOVU_FULL_MAGIC    0x554E5653  // NVUS → .novu
#define NOVU_NPTH_MAGIC    0x50544853  // PTHS → .npth
#define NOVU_APTH_MAGIC    0x41505448  // APTH → .apth
#define NOVU_HOTPTH_MAGIC  0x484F5450  // HOTP → .hotpth

```

## 7\.3 统一标准文件头结构体（128Byte 固定｜四类文件通用）

四类更新文件共用同一套128字节头部布局，仅 `magic`、`file_type`、默认 `update_level` 不同，极大降低解析器代码冗余，同时严格隔离四类载体行为。

```c
typedef struct __attribute__((packed)) {
    // 0x00 基础魔数与版本
    uint32_t magic;               // 四类文件专属魔数
    uint16_t ver_major;
    uint16_t ver_minor;

    // 0x08 文件类型 + 更新分级
    uint8_t  file_type;           // 0=novu 1=npth 2=apth 3=hotpth
    uint8_t  update_level;        // 0~4 对应五级更新通道
    uint8_t  remote_support;      // 1=允许远程下发 0=仅本地手动安装
    uint8_t  reserved_0;

    // 0x0C 全局标志位（位掩码控制更新行为）
    uint32_t flag_bits;

    // 0x10 版本适配区间
    uint64_t target_os_ver;       // 目标适配系统版本
    uint64_t min_compat_ver;      // 最低兼容兜底版本

    // 0x20 内容块计数
    uint32_t entry_count;         // 文件操作项/资源项总数
    uint32_t delta_block_count;   // 差分块数量（全量包可为0）

    // 0x28 各区块文件偏移与长度
    uint32_t meta_offset;         // 元数据/Manifest 偏移
    uint32_t meta_len;
    uint32_t table_offset;        // 操作表/索引表偏移
    uint32_t table_len;
    uint32_t data_offset;         // 原始数据/差分数据区偏移
    uint32_t data_len;
    uint32_t snapshot_offset;     // 快照回滚哈希表偏移
    uint32_t snapshot_len;

    // 0x60 全局完整性校验
    uint8_t  file_sha256[32];     // 整包除签名区外哈希

    // 0x80 签名信息
    uint32_t sig_offset;
    uint32_t sig_len;

    // 0x88 补丁唯一ID（16位十六进制ID二进制存储）
    uint8_t  patch_uuid_bin[8];   

    // 0x90 预留填充至128字节，向前兼容扩展
    uint8_t  reserved_fill[24];
} novus_update_header_t;

```

## 7\.4 全局 Flag 位掩码定义（冻结）

统一位掩码控制各类更新行为，客户端/服务端按位判定策略。

```Plain Text
bit0  = 1 开启快照回滚
bit1  = 1 差分增量模式 / 0 全量替换模式
bit2  = 1 支持断点续传
bit3  = 1 支持内核热更新（无需重启）
bit4  = 1 允许覆盖系统只读路径
bit5  = 1 更新后自动刷新桌面/服务
bit6  = 1 远程静默安装模式
bit7  = 1 安全紧急强制兜底模式
bit8~31 保留

```

## 7\.5 四类文件头部字段差异化绑定规则（永久冻结）

统一结构体 \+ 差异化固化参数，保证格式统一、行为隔离、层级严谨。

|文件后缀|Magic|file\_type|默认 update\_level|核心行为固化|
|---|---|---|---|---|
|\.novu 全量包|NVUS|0|1（推荐级）|大版本替换、支持回滚、仅重大迭代使用|
|\.npth 系统补丁|PTHS|1|1（推荐级）|系统核心迭代、后台执行、可延后次数管控|
|\.apth 软件补丁|APTH|2|0（可选级）|用户态更新、弹窗询问、可永久忽略|
|\.hotpth 热修复|HOTP|3|3（紧急级）|最高优先级、静默强制、禁止延后、插队执行|

## 7\.6 16进制补丁UUID 二进制存储规范

对外文件名：**16位大写十六进制字符串**

对内文件头：**8字节原生二进制存储**（16Hex = 64bit）

校验逻辑双向绑定冻结：

1. 打包器由SHA256摘要截取前64bit生成唯一ID

2. 写入头部 `patch_uuid_bin[8]`

3. 同时格式化输出16位大写Hex作为文件名

4. 解析器校验：文件名Hex \<\-\> 头部二进制ID 必须一致，不一致直接拒绝安装，判定为非法篡改包

## 7\.7 头部合法性校验流水线（硬件级可靠｜冻结流程）

客户端/服务端接收任意更新文件，严格按以下顺序校验，任意一步失败直接丢弃：

1. 校验前128字节头部完整性

2. 匹配对应魔数，判定真实文件类型

3. 校验主次版本兼容

4. 校验二进制UUID与文件名一致性

5. 校验系统版本适配区间

6. 校验全局SHA256完整性

7. 校验Ed25519数字签名合法性

8. 通过后按 update\_level 进入对应更新队列

## 7\.8 区块偏移通用排布规则（四类文件统一）

所有更新文件从偏移0开始排布顺序永久固定：

**128B文件头 → Meta元数据区 → 文件操作索引表 → 差分数据表 → 数据正文区 → 快照哈希区 → 签名区**

保证解析器线性读取、无需自适应判断，极致降低解析复杂度与BUG率。

# 3\. Novus OS 自研更新体系增强策略规范

基于自研架构迭代优化，新增多项工业级增强策略，完善全场景更新能力，所有扩展规则兼容原有冻结底层结构，无破坏性变更。

## 3\.1 智能空闲时段静默更新策略

为兼顾更新时效性与用户使用体验，自研分时更新调度机制：

- \.hotpth 紧急安全补丁：不受时段限制，即时后台静默修复，优先保障系统安全

- 系统、软件常规更新：自动识别设备空闲、锁屏、夜间低活跃时段，后台静默执行更新

- 支持用户自定义免打扰时段，期间禁止非紧急类更新触发

## 3\.2 更新失败智能重试与设备自愈降级策略

- 单次更新异常失败后，系统自动触发3次梯度重试，重试间隔逐级递增，规避临时环境异常问题

- 多次重试持续失败，自动标记该补丁与当前设备不兼容，服务端自动拉黑停止推送

- 本地自动留存故障日志、更新快照、异常信息，同步上报服务端，形成运维闭环

## 3\.3 设备维度精细化灰度放量机制

服务端统一大表内置完整灰度管控逻辑，支撑版本平稳迭代：

- 支持按设备ID、设备批次、硬件机型、系统版本、用户分组精细化灰度推送

- 支持百分比放量更新，小范围验证稳定后逐步全量铺开，规避批量BUG风险

- 开发者预览、内测版本支持白名单专属推送，仅授权设备可获取更新

## 3\.4 系统后台驻留更新服务（完整后台能力闭环）

Novus OS 更新体系内置**系统级常驻后台更新守护服务**，独立于前台UI、独立生命周期、低功耗驻留系统内核服务层。所有更新检测、版本比对、下载预载、静默安装、状态同步、撤回预处理全部支持后台无感知运行，支持前台退出、锁屏待机、用户离线状态下持续完成更新全流程。

### 3\.4\.1 后台服务核心属性（系统常驻级）

- **内核级守护驻留**：更新服务为系统核心自启动服务，开机自动挂载、后台长期常驻、不受前台应用退出影响，无闪退、无后台冻结，保障更新链路持续可用

- **低资源占用调度**：后台空闲休眠、轮询时段轻量化唤醒，仅版本比对与增量校验时瞬时占用CPU，常态内存占用极低，不影响整机性能与续航

- **独立任务生命周期**：下载、校验、安装、回滚、残留清理均为后台独立任务，前台关闭设置界面、切换用户、锁屏待机不中断任务执行

- **断电续任务**：后台所有更新任务状态持久化写入系统更新注册表，重启后自动恢复未完成任务断点，接续执行剩余流程

### 3\.4\.2 后台完整可执行能力清单

所有更新核心逻辑完全后台化，无需前台介入：

- **后台静默轮询检测**：常驻后台定时轮回查询远程统一大表，自动匹配本机适配补丁、分级筛选更新队列

- **后台静默下载预载**：空闲时段后台自动下载差分补丁包，下载完成静默缓存，等待最佳安装时机，实现“开机即用最新版本”

- **后台静默校验鉴权**：后台自动完成魔数校验、UUID双向校验、SHA256完整性校验、Ed25519签名校验，非法包后台自动丢弃并日志归档

- **后台静默安装执行**：紧急安全补丁、后台许可的稳定补丁可完全后台静默安装，无弹窗、无打扰、无需用户确认

- **后台快照备份预处理**：检测到待更新任务时，后台提前异步生成增量快照，前置备好撤回环境，更新失败可瞬时回滚

- **后台残留自动清理**：更新完成、更新撤回、任务终止后，后台自动清理差分缓存、临时文件、无效配置，保持系统整洁

- **后台状态上报同步**：安装结果、撤回结果、失败日志、设备版本基线后台自动同步至远程大表，完成运维闭环

- **后台自愈重试降级**：更新异常后台自动梯度重试，多次失败后台自动标记设备兼容状态、停止推送问题补丁

### 3\.4\.3 后台任务场景适配规则

- **前台活跃场景**：仅执行检测、下载、预缓存任务，延迟高IO安装任务，避免占用系统资源、造成卡顿

- **用户空闲/锁屏场景**：自动放行全部后台安装、回滚、清理任务，全速完成更新迭代

- **低电量/流量受限场景**：后台智能节流，暂停大体积补丁下载，仅保留紧急安全热修复流程，兼顾续航与资费

- **多用户切换场景**：后台服务全局唯一，不受用户切换影响，跨用户持续完成系统级更新

### 3\.4\.4 后台权限与安全隔离机制

- 后台更新服务拥有系统专属更新权限，仅可操作更新指定文件目录与配置项，禁止越权篡改用户私有数据，权限最小化管控

- 所有后台操作全程日志溯源，记录操作时间、任务ID、执行步骤、结果状态，可审计、可追溯、可排查异常

- 非授权第三方程序禁止劫持、终止、篡改后台更新服务，保障更新链路安全不被劫持

### 3\.4\.5 后台与五级更新分级联动策略

- **level\_urgent 紧急补丁**：后台最高优先级插队执行，无视空闲策略、无视节流限制，即刻静默修复

- **level\_recommend 推荐补丁**：后台空闲自动下载、锁屏静默安装，延后次数由后台自动计数管控

- **level\_preview 预览补丁**：后台仅检测、不下发自动安装，等待用户前台确认后再执行后台任务

- **level\_optional 可选补丁**：后台仅版本比对、静默展示列表，不主动下载、不后台安装

- **level\_dev 开发补丁**：默认后台隐藏，仅开发者模式解锁后后台可见可更新

## 3\.5 更新撤回与卸载回滚子系统（工业级完整闭环）

## 3\.5 更新撤回与卸载回滚子系统（工业级完整闭环）

Novus OS 原生支持**已完成更新的可逆撤回能力**，支持所有增量补丁与小版本迭代更新一键卸载、还原更新前状态、自动清理更新残留、恢复原始文件权限与注册表配置，适配用户误更新、版本兼容异常、功能迭代不适配等场景，形成「更新\-生效\-撤回\-复原」完整闭环。

本机制为系统原生底层能力，无需重装系统、不丢失用户数据、不破坏应用环境，区分「可撤回更新」与「永久固化更新」，权限分级可控、日志全程溯源。

### 3\.5\.1 撤回适用范围界定（永久冻结规则）

四类更新载体撤回权限差异化管控：

- **\.apth 软件专属补丁**：完全支持一键撤回，卸载后恢复软件旧版本、还原旧配置，无任何残留

- **\.npth 系统通用累积补丁**：支持常规小迭代更新撤回，仅重大核心基线更新固化不可撤回

- **\.hotpth 紧急安全热修复补丁**：默认**禁止用户主动撤回**，防止安全漏洞复现；仅系统底层故障自愈时自动静默回滚

- **\.novu 全量大版本包**：支持跨版本回滚至上一稳定大版本，保留用户数据分区，还原系统基线环境

### 3\.5\.2 更新快照增量存档机制（撤回核心底层）

系统摒弃全量备份冗余方案，采用**增量快照存档**，仅备份更新被修改、替换、删除的原始文件与配置，节省磁盘空间同时保证100%可复原：

- 每次更新成功写入后，自动生成「更新快照存档」，绑定当前补丁16进制唯一UUID

- 快照内容包含：原始文件二进制备份、文件权限掩码、目录结构、系统配置快照、服务启动项状态

- 快照生命周期可控：常规补丁默认保留30天快照，紧急安全补丁永久留存快照，大版本快照保留60天

- 过期快照自动后台轻量化清理，仅保留更新日志与版本溯源记录，不影响系统运行

### 3\.5\.3 系统更新索引注册表（撤回溯源核心）

系统内置专属更新索引数据库，记录每一条已安装更新的完整元数据，为撤回功能提供精准索引：

单条更新索引固定字段：

- 补丁16进制唯一UUID、文件后缀类型、更新分级等级

- 安装时间、安装状态、是否成功生效、是否已撤回

- 关联修改文件列表、差分块映射表、快照存档存储路径

- 可撤回标记、固化锁定标记、过期清理时间戳

- 更新版本前后基线号、适配系统版本区间

所有已安装更新在系统更新列表可视化展示，支持按时间、类型、版本筛选，用户可自主选择指定更新单独撤回，支持精准单条回滚、不影响后续其他更新。

### 3\.5\.4 分层撤回执行流程（原子事务级冻结）

撤回操作全程事务化，遵循「要么完全撤回、要么原样保留」的原子原则，杜绝半撤回异常状态：

1. **前置校验**：校验补丁合法性、快照完整性、当前系统基线匹配度，检测是否存在依赖后置更新

2. **依赖检测**：若当前更新被后续高阶更新依赖，弹窗提示依赖关系，支持「连带撤回后续增量更新」或「禁止单独撤回」

3. **文件复原**：依据增量快照覆盖还原原始文件、恢复权限、修复目录结构

4. **配置回滚**：还原系统服务项、开机自启、环境变量、应用配置旧状态

5. **残留清理**：自动删除本次更新新增冗余文件、无效注册表项、废弃差分缓存

6. **状态刷新**：静默刷新系统核心服务、桌面环境、应用挂载状态，无需冗余重启（内核级变更按需提示重启）

7. **日志归档**：记录撤回时间、操作主体、回滚结果，同步更新索引数据库状态

### 3\.5\.5 特殊锁定与豁免策略

- **安全补丁锁定策略**：\.hotpth 紧急安全修复永久锁定用户撤回入口，杜绝人为关闭安全防护导致漏洞暴露

- **基线固化策略**：系统重大基线累积更新自动标记为固化版本，禁止普通用户撤回，保障系统底层稳定性

- **开发者豁免策略**：开发者模式下可解锁全部撤回权限，支持任意版本回滚，适配调试与二次开发场景

### 3\.5\.6 服务端同步撤回策略

- 客户端撤回操作自动同步上报远程统一大表，服务端更新设备版本基线状态

- 针对批量设备灰度异常更新，服务端可远程下发「批量撤回指令」，全网统一回滚问题补丁

- 已撤回的问题补丁自动降级灰度放量比例，严重问题补丁全网下架、停止推送

### 3\.5\.7 撤回能力差异化总表

|补丁类型|可用户撤回|可自动自愈回滚|快照保留周期|依赖联动策略|
|---|---|---|---|---|
|\.hotpth 紧急热修复|否（锁定保护）|是（故障自愈）|永久保留|禁止单独回滚，保障安全基线|
|\.npth 系统累积补丁|是（非基线版）|是|30天|检测后续依赖，支持连带回滚|
|\.apth 软件补丁|是（完全开放）|是|30天|独立应用隔离，无系统依赖|
|\.novu 全量版本包|是（大版本回退）|是|60天|整体基线还原，清空增量迭代记录|

## 3\.4 稳定版更新延后管控策略

- level\_recommend 稳定推荐更新，支持用户自主延后1\-3次更新，适配临时工作场景需求

- 延后次数耗尽后自动强制安装，避免设备版本长期滞后、漏洞堆积、兼容性断层问题

- 紧急安全热修复补丁不支持延后、忽略、拦截，保障系统安全底线

# 4\. Novus OS 自研更新体系能力总览表

|系统能力模块|Novus OS 自研实现方案|能力状态|
|---|---|---|
|紧急安全漏洞修复|\.hotpth 最高优先级静默热修复体系|已完全落地冻结|
|系统核心累积迭代|\.npth 系统通用增量补丁体系|已完全落地冻结|
|用户软件独立更新|\.apth 应用软件专属增量补丁体系|已完全落地冻结|
|系统大版本升级|\.novu 全量安装包兜底方案|已完全落地冻结|
|远程统一更新管控|全局唯一大表 \+ 客户端后台轮询架构|已完全落地冻结|
|五级精细化更新分级|紧急/推荐/预览/可选/开发 全通道体系|已完全落地冻结|
|字节级增量差分更新|自研Delta差分数据块更新机制|已完全落地冻结|
|原子更新与事务回滚|快照备份\+全自动异常回滚体系|已完全落地冻结|
|断点续传续更能力|下载与安装进度持久化机制|已完全落地冻结|
|智能时段调度更新|空闲识别\+免打扰时段自定义策略|待编码落地|
|精细化灰度推送管控|设备维度百分比放量\+白名单机制|已支持|
|更新失败自愈与重试|梯度重试\+设备兼容拉黑\+日志上报闭环|待编码落地|

# 5\. Novus OS 自研更新体系定位总结

Novus OS 更新体系为**100%纯自研、完全独立知识产权、工业级稳定**的操作系统原生更新架构，无任何第三方架构依赖，完全适配自研系统生态：

1. 搭建了独有的「三类补丁格式\+五级更新通道」分层更新模型，精准区分安全修复、系统迭代、软件更新场景，权责隔离、层级清晰。

2. 采用轻量化服务端大表管控\+客户端极简执行架构，兼顾批量运维效率与终端系统稳定性。

3. 融合自研差分增量、原子事务回滚、断点续更、智能调度、灰度自愈核心能力，形成安全、高效、可控、可调试的完整更新生态闭环。

# 6\. 后续开发落地清单

- 落地客户端智能空闲时段识别与分时更新调度逻辑

- 实现更新失败梯度重试、自愈检测、设备兼容拉黑机制

- 完善服务端大表设备维度百分比灰度推送、放量管控逻辑

- 完成稳定版更新延后次数统计、阈值管控、强制更新策略模块开发