This commit is contained in:
xyou
2026-07-29 10:26:25 +08:00
parent 2774c10d0c
commit 5ea84fac97
32 changed files with 6385 additions and 35 deletions
+39
View File
@@ -0,0 +1,39 @@
# Deshab Bug 记录
> 所有测试与开发过程中发现的 bug 统一登记于此。每个 bug 按 BUG-YYYYMMDD-NNN 编号。
> 测试用例文档位于 RE/test-cases/。
## 严重程度定义
- P0 阻断: 影响主链路启动或核心功能完全不可用(必须立即修复)
- P1 严重: 功能可降级但关键路径受损(本轮内修复)
- P2 一般: 非关键路径异常或体验问题(下一里程碑前修复)
- P3 提示: 日志/小问题,不影响功能(记录备查)
## Bug 条目格式
```
### BUG-YYYYMMDD-NNN [P级] [模块] 简述
- 现象:
- 复现步骤:
- 串口/日志证据:
- 根因分析:
- 修复方案:
- 状态: [OPEN/FIXING/FIXED/CLOSED]
- 修复提交: <commit hash 或 "待提交">
- 验证: <验证方法与结果>
```
---
## Bug 列表
<!-- 在此追加 bug 条目,最新放在顶部 -->
P2: 软件Files的窗口点击叉无法关闭
P3: 在第一页已经有了终端,所以在第四页的桌面上不用显示终端和CMD
P2: 在开发者模式中的shell输入命令并回车时文字消失没有反应
P3: 启动时的打字机效果再快3倍
P2: 桌面中第一页的shell中输入命令回车后,上一条命令输入的文字会跑到下一行
P2: 桌面中第一页的Files显示的不是SYSTEM/user中的文件夹内容
P2: Files中没有显示文件夹,直接显示了文件夹下的文件
P2: Files没有提供“..”来供用户返回上一级的文件夹
+504
View File
@@ -0,0 +1,504 @@
# UTSM 算法记录
```text
UTSM = UUID-Tuned Sealed Memory
中文名:UUID 调谐封缄内存
```
本文记录 UTSM v1 的核心算法。
---
## 1. 段创建算法
目标:为任务创建一个只存密文的连续内存段,并返回 capability。
```text
utsm_create_segment(process, size, flags)
1. size 按 64B / 4KB 对齐。
2. 从 buddy/slab 分配 cipher data pages。
3. 从 DMP pool 分配 DMP。
4. 生成 segment_uuid。
5. key_epoch = process.crypto_epoch。
6. tweak_seed = hash(process_uuid, segment_uuid, key_epoch)。
7. 初始化 dirty_bitmap。
8. 初始化 mac_table。
9. 填写 utsm_segment_desc。
10. 填写 utsm_dmp。
11. generation++。
12. 生成 utsm_capability。
13. 将 capability 写入任务 capability table。
14. 返回 capability。
```
复杂度:
```text
段元数据初始化:O(1)
数据页分配:O(page_count)
热路径访问定位:O(1)
```
---
## 2. 密钥派生算法
UUID 不作为明文密钥,而是作为调谐因子。
```text
segment_key = KDF(
DRR_root_key,
process_uuid,
segment_uuid,
key_epoch
)
```
每 64B cache line 生成 tweak:
```text
line_index = offset / 64
tweak = hash(tweak_seed, line_index, key_epoch)
```
加密和解密对称:
```text
ciphertext = plaintext XOR stream(segment_key, tweak)
plaintext = ciphertext XOR stream(segment_key, tweak)
```
设计理由:
```text
1. 避免十进制 UUID 解析。
2. 避免 UUID 孔洞破坏连续内存。
3. 以 64B cache line 为单位,适合 CPU cache 和 SIMD。
4. key_epoch 可用于快速作废旧段。
```
---
## 3. UTRW Fast Read 算法
```text
UTRW_READ_FAST(cap, offset, len, dst)
1. desc = SEGMENT_TABLE[cap.segment_slot]。
2. 检查 desc.generation == cap.generation。
3. 检查 cap.rights 包含 READ。
4. 检查 cap.epoch == desc.key_epoch。
5. 检查 offset + len <= desc.cipher_length。
6. 检查 desc.state == ACTIVE。
7. key = PCKC_LOOKUP(desc.segment_slot, desc.key_epoch)。
8. 如果 key miss,进入 slow path。
9. 读取 writer_seq_before。
10. 如果 writer_seq_before 为奇数,重试或 slow path。
11. 对访问范围涉及的每个 64B line:
a. 计算 line_index。
b. 生成 tweak。
c. 读取密文 line。
d. 解密成明文 line。
e. 拷贝目标字节到 dst。
12. 读取 writer_seq_after。
13. 如果 before != after,重试。
14. 返回 OK。
```
复杂度:
```text
段定位:O(1)
读写长度 n:O(n / 64)
```
---
## 4. UTRW Fast Write 算法
```text
UTRW_WRITE_FAST(cap, offset, len, src)
1. desc = SEGMENT_TABLE[cap.segment_slot]。
2. 检查 desc.generation == cap.generation。
3. 检查 cap.rights 包含 WRITE。
4. 检查 cap.epoch == desc.key_epoch。
5. 检查 offset + len <= desc.cipher_length。
6. 检查 desc.state == ACTIVE。
7. key = PCKC_LOOKUP(desc.segment_slot, desc.key_epoch)。
8. 如果 key miss,进入 slow path。
9. 如果是强恢复段,写 WRITE_INTENT log。
10. writer_seq++,进入奇数写入状态。
11. 对访问范围涉及的每个 64B line:
a. 计算 line_index。
b. 生成 tweak。
c. 如果覆盖完整 line,直接使用 src 明文。
d. 如果部分覆盖 line,读取旧密文,解密旧明文,合并新明文。
e. 加密成新密文。
f. 写回 cipher data。
12. 标记 dirty_bitmap。
13. writer_seq++,回到偶数稳定状态。
14. 如果是强恢复段,写 WRITE_COMMIT log。
15. 返回 OK。
```
部分写规则:
```text
UTSM 的加密单位是 64B line。
如果只写 line 的一部分,必须读旧密文、解密、合并、重新加密整条 line。
```
---
## 5. UTRW Slow Path 算法
Slow Path 触发条件:
```text
PCKC key miss
generation mismatch
epoch mismatch
state != ACTIVE
checkpoint busy
recovery busy
MAC failed
segment poisoned
out of bounds
access denied
```
处理策略:
```text
KEY_MISS
-> 派生 segment_key
-> 生成 key_schedule
-> 写入 PCKC
-> 回到 fast path
STALE_CAPABILITY
-> 尝试从 capability table 刷新
-> 失败则返回错误
EPOCH_EXPIRED
-> 刷新 cap.epoch 和 auth_tag
-> 清除旧 PCKC key
-> 回到 fast path
CHECKPOINT_BUSY
-> 短暂等待或写 side log
RECOVERING
-> 阻塞任务,等待 DRR 完成恢复
MAC_FAILED
-> 标记 suspicious page
-> 通知 DRR
-> 尝试 page rollback
SEGMENT_POISONED
-> 拒绝访问
-> 交给 DRR 决定回滚、重建或 kill task
```
---
## 6. PCKC 查找算法
每 CPU 保存少量热段 key。
```text
PCKC_LOOKUP(slot, epoch)
1. 检查 current hot slot。
2. 检查 hot_segment_slot[0..N]。
3. 如果 slot 和 epoch 均匹配,返回 key_schedule。
4. 否则返回 MISS。
```
替换策略:
```text
第一版使用小型 LRU 或替换最冷 slot。
```
建议槽数:
```text
8 个 key slot 起步。
高并发或服务型任务可扩展到 16 个。
```
---
## 7. Checkpoint 算法
### 7.1 Dirty Shard 标记算法
Dirty Bitmap 分片为 Dirty Shard,避免 checkpoint 扫描整块大 bitmap。
```text
UTSM_MARK_DIRTY(desc, page_index)
1. shard = desc.dirty_shards[page_index / PAGES_PER_SHARD]。
2. bit = page_index % PAGES_PER_SHARD。
3. 如果 bit 原来是 0:
a. 设置 bitmap bit。
b. shard.dirty_count++。
c. 如果 shard.dirty_count 从 0 变为 1,加入 per-cpu dirty_shard_list。
4. 返回。
```
复杂度:
```text
Dirty 标记:O(1)
Checkpoint 扫描:O(number_of_dirty_shards + number_of_dirty_pages)
```
### 7.2 A/B Checkpoint Metadata 提交算法
```text
CHECKPOINT_METADATA_COMMIT(gen)
1. active = checkpoint.active_slot。
2. inactive = opposite(active)。
3. 清理 inactive slot 的临时状态。
4. 写 inactive.metadata_header。
5. 写 segment desc snapshot。
6. 写 DMP snapshot。
7. 写 dirty shard summary。
8. 写 MAC root。
9. 写 generation。
10. 计算并写 CRC。
11. flush inactive slot。
12. 原子切换 checkpoint.active_slot = inactive。
13. 写 CHECKPOINT_COMMIT log。
```
恢复时:
```text
1. 读取 active slot。
2. 校验 generation 和 CRC。
3. 如果 active 有效,使用 active。
4. 如果 active 无效,校验 fallback slot。
5. 如果 fallback 有效,使用 fallback。
6. 如果双槽都无效,进入 system rollback。
```
### 7.3 Dirty Page Checkpoint 算法
```text
DRR_CHECKPOINT()
1. checkpoint_generation++。
2. 写 CHECKPOINT_BEGIN log。
3. inactive_slot = opposite(active_slot)。
4. 遍历 per-cpu dirty_shard_list。
5. 跳过 dirty_count == 0 的 shard。
6. 对每个 dirty shard:
a. 找到关联 segment。
b. desc.state = CHECKPOINTING。
c. 冻结 writer。
d. flush PWC / per-CPU dirty buffer。
e. 只扫描 shard 内 dirty bit。
f. 复制 dirty ciphertext page 到 checkpoint region。
g. 计算 page MAC。
h. 写 dirty shard summary。
i. 清 shard bitmap。
j. shard.dirty_count = 0。
k. desc.state = ACTIVE。
7. 写 segment desc snapshot。
8. 写 DMP snapshot。
9. CHECKPOINT_METADATA_COMMIT(checkpoint_generation)。
```
提交规则:
```text
只有存在 CHECKPOINT_COMMIT 且 CRC 正确的 checkpoint 才是稳定点。
中途崩溃的 checkpoint 直接丢弃。
A/B metadata 至少保留一个旧稳定点。
```
### 7.4 DRR Emergency Pool 分配算法
DRR Recovery 路径不能依赖普通 allocator。
```text
DRR_EMERGENCY_ALLOC(size, class)
1. 从 DRR emergency pool 的 class freelist 取对象。
2. 如果 freelist 非空,返回对象。
3. 如果 freelist 为空,从 emergency pages 切分。
4. 如果 emergency pages 不足:
a. 写 EMERGENCY_POOL_EXHAUSTED。
b. 进入 system rollback。
```
Emergency Pool 包含:
```text
DRR private stack
recovery log buffer
checkpoint metadata buffer
crash buffer
metadata slab
emergency pages
```
规则:
```text
普通 allocator 不可使用 Emergency Pool。
Emergency Pool 不参与普通内存回收。
DRR OOM 直接视为不可恢复故障。
```
---
## 8. Rollback 算法
分三级。
### 8.1 Page Rollback
```text
1. 定位最近稳定 checkpoint。
2. 校验 checkpoint page MAC。
3. 将旧密文页复制回 cipher data。
4. 恢复 page MAC。
5. 清 dirty bit。
6. 段保持 ACTIVE。
```
### 8.2 Segment Rollback
```text
1. desc.state = RECOVERING。
2. 恢复 segment desc snapshot。
3. 恢复 DMP snapshot。
4. 恢复 key_epoch。
5. 恢复 dirty bitmap。
6. 恢复 mac_table。
7. 清除对应 PCKC key。
8. desc.state = ACTIVE。
```
### 8.3 System Rollback
```text
1. DRR 写 crash reason。
2. 标记 boot attempt failed。
3. 触发 reboot。
4. bootloader 读取 BCB。
5. 如果失败次数超限,切换 last_good_slot。
```
---
## 9. 任务创建算法
```text
task_create(entry, priority, flags)
1. 分配 TCB。
2. 生成 tid。
3. 生成 process_uuid。
4. 创建 utsm_process_context。
5. 创建 stack segment。
6. 创建 heap segment。
7. 可选创建 ipc segment。
8. 初始化 capability table。
9. cap[0] = stack。
10. cap[1] = heap。
11. 初始化 CPU context。
12. 通过 UTRW_WRITE 写入 task_start_packet。
13. hot_segment_hint = stack.segment_slot。
14. state = READY。
15. enqueue_task(current_cpu)。
```
---
## 10. 调度切换算法
```text
schedule()
1. old = current。
2. utsm_switch_out(old)。
3. next = pick_next_task()。
4. utsm_switch_in(next)。
5. context_switch(old, next)。
```
`utsm_switch_out`:
```text
1. 如果 old 有 PWC dirty,登记 flush pending。
2. 保存 old.hot_segment_hint。
3. 更新 old.recovery_generation。
4. 更新 heartbeat。
```
`utsm_switch_in`:
```text
1. 如果 next.state == RECOVERING,跳过。
2. PCKC.current_process_uuid = next.crypto.process_uuid。
3. PCKC.current_crypto_epoch = next.crypto.crypto_epoch。
4. 预热 next.hot_segment_hint。
```
调度路径禁止:
```text
扫描段
扫描 capability table
计算 MAC
写 checkpoint
重加密整段
```
---
## 11. 任务异常处理算法
```text
UTRW_DETECT_FAULT(task, segment, error)
1. task.fault_segment_slot = segment.slot。
2. task.state = FAULTED。
3. 从 runqueue 移除。
4. 写 DRR fault event。
5. DRR 判断:
a. 刷新 capability。
b. page rollback。
c. segment rollback。
d. kill task。
e. system rollback。
```
任务 kill:
```text
task_kill(task)
1. task.state = ZOMBIE。
2. 从 runqueue 移除。
3. revoke capability table。
4. owned segment key_epoch++。
5. desc.state = DESTROYED。
6. 加入 deferred free。
7. 写 TASK_KILL recovery log。
```
---
## 12. 复杂度总结
```text
段定位:O(1)
UTRW 读写:O(n / 64)
PCKC 命中:O(1)
PCKC miss:O(KDF + key schedule)
Dirty 标记:O(1)
Checkpoint:O(number_of_dirty_shards + number_of_dirty_pages)
A/B metadata 切换:O(1)
DRR emergency alloc:O(1)
Page rollback:O(1 page)
Segment rollback:O(segment_dirty_pages + metadata)
调度切换额外成本:O(1)
```
+485
View File
@@ -0,0 +1,485 @@
# UTSM 设计架构记录
本文记录 Deshab 内核当前 UTSM 相关架构定稿。
---
## 1. 架构目标
UTSM 的目标不是传统强安全隔离,而是在极高权限、极高效率的单地址空间 Ring0 内核中提供一种封缄内存模型。
核心目标:
```text
所有普通内存可读,但默认是密文。
明文读写必须通过 UTRW。
UUID 作为进程和内存段的调谐因子。
数据区保持连续,避免 UUID 孔洞。
DRR 提供 root key、checkpoint、recovery log 和回滚。
调度器保持 O(1)。
```
---
## 2. 总架构模块
```text
Deshab Kernel Core
SAS-R0-PCQ
单地址空间 Ring0 任务模型
Per-CPU O(1) 位图调度器
DRR
Dedicated Recovery Root
专用恢复根
watchdog / root key / checkpoint / recovery log / A-B rollback
UTSM
UUID-Tuned Sealed Memory
UUID 调谐封缄内存
UTRW
UTSM Tagged Reader/Writer
UTSM 带标记读写器
DMP
Descriptor Meta Page
段描述符元页
PCKC
Per-CPU Key Cache
每 CPU 密钥缓存
```
---
## 3. UTSM 内存模型
每个 UTSM 段由两部分组成:
```text
DMP + Cipher Data
```
布局:
```text
+-------------------------------+
| DMP: Descriptor Meta Page |
+-------------------------------+
| Cipher Data Page 0 |
+-------------------------------+
| Cipher Data Page 1 |
+-------------------------------+
| Cipher Data Page 2 |
+-------------------------------+
| ... |
+-------------------------------+
```
规则:
```text
DMP 不属于用户数据。
Cipher Data 只存密文。
UUID 不插入 Cipher Data。
数据区保持连续。
```
---
## 4. 关键设计替代
从原始构想到 UTSM v1 的替代关系:
```text
十进制 UUID
-> 128-bit 二进制 UUID
UUID 数字间隔插入内存
-> 独立 DMP 元数据页
UUID 数字位置表
-> segment_slot + generation + tweak_seed
十进制凯撒
-> UUID 调谐的 cache-line 流式加密
每次传统 syscall
-> Ring0 fast accessor + PCKC
写入时避开 UUID
-> 连续密文数据区直接写
```
---
## 5. 数据结构架构
### 5.1 uuid128_t
```c
typedef struct {
uint64_t hi;
uint64_t lo;
} uuid128_t;
```
### 5.2 utsm_process_context
```c
struct utsm_process_context {
uuid128_t process_uuid;
uint64_t crypto_epoch;
uint64_t recovery_generation;
uint32_t capability_table_slot;
uint32_t capability_count;
uint32_t flags;
};
```
### 5.3 utsm_segment_desc
```c
struct utsm_segment_desc {
uuid128_t segment_uuid;
uuid128_t owner_process_uuid;
void *cipher_base;
uint64_t cipher_length;
void *dmp_base;
uint64_t key_epoch;
uint64_t tweak_seed;
void *dirty_bitmap;
void *mac_table;
uint32_t generation;
uint32_t flags;
uint32_t state;
uint32_t last_cpu;
uint64_t writer_seq;
uint64_t checkpoint_generation;
};
```
### 5.4 utsm_dmp
```c
struct utsm_dmp {
uint64_t magic;
uint32_t version;
uint32_t segment_slot;
uint64_t fast_base;
uint64_t fast_limit;
uint64_t fast_tweak_seed;
uint64_t fast_key_epoch;
uint64_t dirty_bitmap_base;
uint64_t mac_table_base;
uint64_t last_writer_seq;
uint32_t last_cpu;
uint32_t flags;
uint64_t crc;
};
```
### 5.5 utsm_capability
```c
struct utsm_capability {
uint32_t segment_slot;
uint32_t generation;
uint32_t rights;
uint32_t epoch;
uint64_t uuid_digest;
uint64_t auth_tag;
};
```
---
## 6. UTRW 读写器架构
UTRW 分三层:
```text
Level 0: Raw Access
直接访问 cipher_base,读到密文。
Level 1: Fast Path
capability O(1) 定位段。
PCKC 命中。
无全局锁。
无 trap。
Level 2: Slow Path
key miss。
epoch mismatch。
checkpoint/recovery。
MAC fail。
poisoned segment。
```
读写基本流程:
```text
Read:
cap -> segment desc -> PCKC key -> 64B line 解密 -> 返回明文
Write:
cap -> segment desc -> PCKC key -> 64B line 加密 -> 写密文 -> dirty bitmap -> recovery log
```
---
## 7. DRR 协作架构
DRR 保存:
```text
root_key 或 root_key handle
global_crypto_epoch
segment table snapshot
DMP snapshot
dirty shard summary
dirty bitmap
MAC root
recovery log
poisoned segment list
Boot Control Block
DRR Emergency Pool
A/B checkpoint metadata slot
```
DRR 负责:
```text
watchdog 检测
freeze-all
checkpoint
page rollback
segment rollback
system rollback
A/B 镜像回滚
```
---
## 8. Checkpoint / Rollback 架构
Checkpoint 类型:
```text
Light Checkpoint
控制面快照。
Dirty Page Checkpoint
dirty ciphertext page 快照。
Boot Checkpoint
启动状态和 A/B slot 信息。
```
### 8.1 Dirty Shard
Dirty Bitmap 采用分片结构。
```text
Dirty Shard
dirty_count
shard_id
page_base
page_count
last_checkpoint_epoch
bitmap
```
checkpoint 时:
```text
dirty_count == 0 的 shard 直接跳过。
dirty_count > 0 的 shard 才扫描 dirty bit。
```
这样 checkpoint 成本为:
```text
O(number_of_dirty_shards + number_of_dirty_pages)
```
### 8.2 A/B Checkpoint Metadata
checkpoint metadata 使用双槽:
```text
Checkpoint Metadata Slot A
Checkpoint Metadata Slot B
```
写入规则:
```text
写 inactive slot
写 metadata / dirty index / MAC root / CRC
flush
原子切换 active slot
旧 slot 作为 fallback
```
恢复规则:
```text
active slot 有效 -> 使用 active
active slot 无效 -> fallback 另一个 slot
双槽都无效 -> system rollback
```
### 8.3 DRR Emergency Pool
DRR 独立预留紧急内存池。
```text
DRR Emergency Pool
DRR private stack
recovery log buffer
checkpoint metadata buffer
crash buffer
metadata slab
emergency pages
```
约束:
```text
普通 allocator 不可使用。
普通 OOM 不影响 DRR recovery。
DRR recovery 路径禁止依赖普通堆分配器。
Emergency Pool 耗尽时进入 system rollback。
```
Rollback 级别:
```text
Page Rollback
单页恢复。
Segment Rollback
整段恢复。
System Rollback
重启并由 bootloader 切换 last_good_slot。
```
---
## 9. 与 SAS-R0-PCQ 的整合
UTSM Task 是:
```text
Ring0 调度实体
+ process_uuid
+ crypto context
+ capability table
+ encrypted stack/heap
+ PCKC hot hint
+ DRR recovery generation
```
调度切换:
```text
schedule()
-> utsm_switch_out(old)
-> pick_next_task()
-> utsm_switch_in(next)
-> context_switch(old, next)
```
调度路径只允许:
```text
设置 crypto 指针
加载 process_uuid
预热 hot_segment_hint
标记 PWC dirty flush
```
禁止:
```text
扫描段
扫描 capability table
计算 MAC
写 checkpoint
重加密整段
```
---
## 10. 启动顺序
```text
Bootloader
-> 读取 Boot Control Block
-> 选择 active_slot / last_good_slot
-> 加载 SYSTEM/boot/utsm.elf
-> 传入 memory map 和 DRR region
DRR Init
-> 初始化 watchdog
-> 建立 root key handle
-> 初始化 recovery log
-> 初始化 checkpoint region
-> 初始化 heartbeat page
-> 初始化 DRR Emergency Pool
-> 初始化 A/B checkpoint metadata slot
UTSM Init
-> 初始化 global crypto epoch
-> 初始化 segment table
-> 初始化 DMP pool
-> 初始化 PCKC area
-> 初始化 dirty shard pool
-> 初始化 dirty bitmap / MAC table pool
-> 注册 UTRW fast path / slow path
Scheduler Init
-> 初始化 per-CPU runqueue
-> 初始化 per-CPU heartbeat
-> 初始化每 CPU PCKC
-> 创建 bootstrap task
-> 创建核心服务 task
```
---
## 11. 当前定稿边界
UTSM v1 确定:
```text
加密粒度:64B cache line
Dirty 粒度:4KB page
Dirty 分片:Dirty Shard
MAC 粒度:4KB page
段定位:O(1)
调度额外成本:O(1)
checkpoint 成本:O(dirty shards + dirty pages)
checkpoint metadata:A/B 双槽,CRC 校验,原子切换
DRR recovery 内存:Emergency Pool 独立预留
```
暂不追求:
```text
完整 RAM 原地回滚
对恶意 Ring0 代码的强安全隔离
设备外部副作用回滚
```
设备恢复策略:
```text
内存恢复后,设备 reset/reinit。
磁盘依赖文件系统 journal。
网卡 TX 已发包不回滚,RX/TX ring 重建。
```
+461
View File
@@ -0,0 +1,461 @@
# Deshab 桌面环境架构设计
## 1. 概述
Deshab 桌面环境(Deshab Desktop Environment, DDE)是基于 UTSM/DSK 内核的图形桌面系统,
运行在 SAS-R0(单地址空间 Ring0)任务模型上,使用 "Sealed Arc" 视觉风格系统。
**设计原则**:
- **SAS-R0 适配**:无内存隔离,所有应用共享地址空间,信任模型为 Ring0 全信任
- **单屏幕协作**:初期采用"多窗口前台 + 桌面后台"模式,桌面管理器始终驻留
- **应用独立开发**:内置应用使用回调模式;未来工具应用为独立 .elf,通过 ELF 加载方式载入
- **帧缓冲直绘**:无 GPU 加速,所有渲染通过 du_context 直接写 framebuffer
**当前实现状态**:desktop.elf 已实现完整的桌面管理器框架,包括窗口管理、事件路由、
PS/2 鼠标初始化+轮询、光标 save/restore、任务栏、桌面图标和 3 个内置应用。
## 2. 系统架构
```
┌─────────────────────────────────────────────────────┐
│ Framebuffer │
│ ┌─────────────────────────────────────────────┐ │
│ │ Desktop Manager (desktop.elf) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Window 1 │ │ Window 2 │ │ Window 3 │ │ │
│ │ │ (bash) │ │ (editor) │ │ (calc) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────┐│ │
│ │ │ Taskbar (40px) ││ │
│ │ └─────────────────────────────────────────┘│ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
```
## 3. 启动流程
```
UEFI → Limine → utsm.elf → DKM 驱动加载
→ deshab.elf (DSK) → spinner → firstInit.txt 检查
→ mouseInit.elf → netman.elf → [首次] FirstInit.elf
→ desktop.elf ← 桌面管理器
```
DSK 在 FirstInit 完成或 firstInit=1 时,加载 `desktop.elf`。
desktop.elf 通过 `dsk_entry(dsk_boot_context *ctx)` 入口接收系统上下文,
自行初始化 PS/2 鼠标、注册应用、进入主事件循环。
## 4. Desktop Manager 核心设计
### 4.1 窗口模型
```c
typedef struct desktop_window {
int id; /* 窗口 ID(自增分配) */
int x, y, w, h; /* 窗口位置和尺寸 */
int visible; /* 可见性 */
int focused; /* 焦点 */
int minimized; /* 最小化 */
char title[48]; /* 窗口标题 */
/* 应用关联 */
int app_id; /* 关联的应用 ID(g_apps 索引) */
void *app_state; /* 应用私有状态(on_create 返回值) */
int closing; /* 关闭中标记 */
int dirty; /* 脏标记(需要重绘) */
} desktop_window;
```
**Z 序**:窗口按数组顺序排列,数组末尾的窗口在最上层。`win_bring_to_front()` 将窗口移到数组末尾。
**窗口限制**:最多 8 个窗口(`MAX_WINDOWS`)。
**固定地址分配**:当前内置应用使用固定地址分配状态结构,避免堆依赖:
- `0x4000000` — bash_state(终端)
- `0x5000000` — editor_state(编辑器)
- `0x6000000` — calc_state(计算器)
### 4.2 事件系统
```c
typedef enum {
EV_MOUSE_MOVE = 1,
EV_MOUSE_DOWN,
EV_MOUSE_UP,
EV_KEY_DOWN,
EV_KEY_UP,
} ev_type;
typedef struct {
ev_type type;
int mx, my; /* 鼠标全局坐标 */
int button; /* 0=左, 1=右 */
u8 scancode;
int shift, ctrl, alt;
} desktop_event;
```
**事件路由**:
1. **鼠标事件** → 从后往前命中测试 → 找到目标窗口 → 检查关闭按钮/标题栏/客户区 → 路由到窗口回调
2. **键盘事件** → 当前焦点窗口的 `on_event` 回调
3. **任务栏点击** → 桌面管理器直接处理(快速启动/窗口按钮)
4. **桌面图标点击** → 桌面管理器处理(`launch_app()`)
**拖拽机制**:
- 鼠标按下 + 命中标题栏 → 进入拖拽模式(`g_dragging=1`)
- 拖拽期间鼠标移动 → 更新窗口位置(`w->x = mouse_x - offset`)
- 鼠标释放 → 退出拖拽模式
**关闭机制**:
- 鼠标点击窗口右上角红色 X 按钮(24×20 圆角矩形,DP_ERROR 底色)
- `win_destroy()` 调用应用的 `on_destroy`,从窗口数组移除,焦点转移到最后一个窗口
### 4.3 应用 ABI(回调模式)
```c
typedef struct app_ctx {
du_context *fb; /* 全局帧缓冲渲染上下文 */
desktop_win *win; /* 关联窗口 */
int client_x, client_y, client_w, client_h; /* 客户区坐标 */
int should_exit; /* 退出标志 */
desktop_block_read_fn block_read; /* FAT32 块读取函数 */
const void *kernel_api; /* DKM kernel_api 分发表 */
} app_ctx;
typedef void *(*app_create_fn)(app_ctx *ctx);
typedef void (*app_event_fn)(void *state, app_ctx *ctx, desktop_event *ev);
typedef void (*app_draw_fn)(void *state, app_ctx *ctx);
typedef void (*app_destroy_fn)(void *state);
typedef struct {
const char *name; /* 应用标识名 */
const char *display_name; /* UI 显示名 */
u32 default_w, default_h; /* 默认窗口尺寸 */
app_create_fn on_create;
app_event_fn on_event;
app_draw_fn on_draw;
app_destroy_fn on_destroy;
} app_descriptor;
```
**应用生命周期**:
1. 用户点击桌面图标或快速启动 → `launch_app(app_id)`
2. 创建窗口 → 构建 `app_ctx` → 调用 `on_create(ctx)` → 返回 `app_state`
3. 事件循环中:`on_event(state, ctx, ev)` 处理输入
4. 绘制时:`on_draw(state, ctx)` 渲染客户区
5. 关闭窗口 → `on_destroy(state)` 清理
**当前注册的应用**:
| app_id | name | display_name | 默认尺寸 | 状态 |
|--------|------|-------------|----------|------|
| 0 | bash | Terminal | 640×440 | 已实现 |
| 1 | editor | Editor | 600×450 | 已实现 |
| 2 | fileman | Files | 500×400 | 占位(无回调) |
| 3 | calc | Calculator | 280×400 | 已实现 |
### 4.4 任务栏 (Taskbar)
位置:屏幕底部,高度 40px。
布局:
```
┌──────────────────────────────────────────────────────────┐
│ [D] │ 🖥️ 📝 📁 🧮 │ │ 12:34 │
│Start│ 快速启动(4图标) │ 窗口按钮 │ RTC时钟 │
└──────────────────────────────────────────────────────────┘
```
分区:
- **Start 按钮**(48×32,DP_ABYSS_600 圆角矩形):显示 "D" 字符(DS_DARK_ACCENT_LIGHT)
- **快速启动**(4 图标 × 40px):按 app_id 顺序绘制程序化图标(终端/编辑器/文件夹/计算器)
- **窗口按钮区**:每个打开窗口一个 100×32 按钮,焦点窗口用 DS_DARK_ACCENT 底色,其余用 DP_ABYSS_600
- **RTC 时钟**(右侧 80px 区域):通过 CMOS I/O(端口 0x70/0x71)读取 BCD 时分,转换为 HH:MM 格式
### 4.5 桌面图标
位置:桌面右侧垂直排列。
参数:
- 列宽 80px(`DESKTOP_ICON_W`),行高 72px(`DESKTOP_ICON_H`)
- 左边距 16px(`ICON_GUTTER_X`),上边距 16px(`ICON_GUTTER_Y`)
- 起始 X = `fb_width - 80 - 16`
图标:32×32 像素,程序化生成(无需位图文件),通过 `draw_icon_*` 函数绘制:
- **终端图标**:DP_ABYSS_700 圆角矩形 + DP_SEAL_300 的 >_ 符号 + DP_SEAL_500 边框
- **编辑器图标**:DP_ABYSS_700 圆角矩形 + DP_SEAL_500 文本行 + DP_SEAL_300 边框
- **文件夹图标**:DP_ARC_500 圆角矩形 + DP_ARC_300 文件夹形状 + DP_ARC_700 边框
- **计算器图标**:DP_ABYSS_700 圆角矩形 + DP_WARNING 按键 + DP_NEUTRAL_400 网格
标签:图标下方 36px 处,居中绘制应用 display_name,使用 DS_DARK_TEXT_PRIMARY 颜色。
### 4.6 窗口装饰
**标题栏**(28px,`TITLEBAR_H`):
- 焦点窗口:DP_ABYSS_600 背景
- 非焦点窗口:DP_ABYSS_800 背景
- 标题文字:左侧 DU_SPACE_SM 偏移,DS_DARK_TEXT_PRIMARY 颜色
- 关闭按钮:右上角,窗口右边 -28px 处,24×20 圆角矩形,DP_ERROR (红色) 底色 + 白色 "X"
**边框**(2px,`BORDER_W`):
- 焦点窗口:DS_DARK_BORDER(Seal Cyan 发光效果)
- 非焦点窗口:DS_DARK_BORDER
- 焦点发光:`du_rect_glow()` 3px 扩展范围,10px 衰减
**标题栏底线**:1px 分隔线,颜色同边框色。
**圆角**:窗口主体使用 `DU_RADIUS_LG` 圆角,关闭按钮使用 `DU_RADIUS_SM` 圆角。
### 4.7 应用加载模型
**方式一:回调式(当前实现)**
应用编译进 desktop.elf 内部,通过 `app_descriptor` 注册回调函数。
桌面管理器在事件循环中调用 `on_event()`/`on_draw()`,应用通过 `app_ctx` 访问系统服务。
特点:
- 应用与桌面管理器在同一 ELF 中,共享代码和全局变量
- 应用状态使用固定地址分配(避免堆依赖)
- 应用可以直接访问 g_fb 全局帧缓冲
**方式二:独立 ELF 加载式(未来实现)**
工具应用独立开发为单独 .elf 文件(如 `CODE/tools/bash/`),通过 DSK 的 FAT32 + ELF loader 加载。
独立工具实现 `dsk_entry(dsk_boot_context *ctx)` 入口点,接收与 DSK 相同的系统上下文。
未来桌面管理器将通过 ELF 加载方式载入工具 .elf,需要实现:
- ELF 加载到内存 + PIE 重定位
- 传入 dsk_boot_context(framebuffer、kernel_api、block_read 等)
- 返回机制(在 ELF 入口点保存返回地址)
- 独立工具的公共辅助代码(`CODE/tools/desktop_app.h`)
## 5. 渲染管线
```
redraw_all() 完整管线:
1. 渐变背景(du_fill_bg_gradient: DP_ABYSS_900 → DP_ABYSS_800)
2. 桌面图标(draw_desktop_icons)
3. 窗口循环(从底到顶):
a. 应用 on_draw() 绘制客户区内容
b. draw_window_frame() 绘制窗口装饰(在应用内容之上)
4. 任务栏(draw_taskbar)
5. 鼠标光标(cursor_save_bg + cursor_draw)
```
**渲染策略**:
- 每帧全屏重绘(无增量更新)
- 鼠标光标使用 save/restore 机制:移动前恢复旧位置背景,重绘后保存新位置背景
- 应用直接写入全局 framebuffer(无窗口后缓冲),窗口装饰在应用内容之上绘制
- 重绘触发:鼠标移动/点击、键盘事件、窗口状态变化
## 6. 像素格式
与现有 framebuffer 一致:32bpp ARGB(0xAARRGGBB),小端存储。
所有颜色值使用 deshab_ui.h 中的语义色令牌。
## 7. 鼠标光标
24×24 像素箭头光标:
- 热点在左上角 (0,0)
- 形状定义:`cursor_shape[24][24]` 位图数组(1=前景,0=透明)
- 前景色:DS_DARK_TEXT_PRIMARY
- save/restore 实现无闪烁移动:
- `cursor_save_bg()`: 保存光标位置 24×24 像素到 `g_cursor_save[]`
- `cursor_restore_bg()`: 恢复上次保存的像素
- 每帧重绘时:先 restore 旧位置 → 全屏绘制 → save + draw 新位置
- 边界限制:光标不超出屏幕范围(减去 CURSOR_SIZE)
## 8. 输入处理
### 8.1 PS/2 鼠标
**初始化**(`ps2_mouse_init()`):
1. 启用 AUX 设备(命令 0xA8 → 0x64)
2. 读取控制器配置字节(0x20 → 0x64),设置 bit1(AUX IRQ12)+ 清除 bit5(AUX clock)
3. 写回配置(0x60 → 0x64)
4. 复位鼠标(0xD4 → 0x64,0xFF → 0x60)
5. 启用 streaming(0xD4 → 0x64,0xF4 → 0x60)
**轮询**(`ps2_mouse_poll()`):
- 读取端口 0x64 状态,检查 bit0(数据就绪)和 bit5(AUX 标记)
- 读取 0x60 数据,累积 3 字节组成一个鼠标包
- 校验 byte0 bit3 同步位
- 解析 X/Y 位移(带符号扩展)和左键状态(byte0 bit0)
- Y 轴翻转处理(鼠标 Y 向上为正,屏幕 Y 向下为正)
- 边界裁剪:光标限制在屏幕范围内
### 8.2 PS/2 键盘
- IRQ1 → scan code set 1
- 扩展键 E0 前缀追踪(`g_e0` 标记)
- Shift 修饰键追踪(0x2A/0x36 按下,0xAA/0xB6 释放)
- `scan_to_ascii()` 映射:normal[58] + shifted[58] 查找表
- 键盘事件发送到焦点窗口的 `on_event` 回调
**全局快捷键**(规划中):
- Alt+Tab:窗口切换
- Alt+F4:关闭窗口
## 9. 文件系统接口
工具应用通过 `app_ctx.block_read` 访问 FAT32 文件系统。
`block_read` 函数类型:
```c
typedef int (*desktop_block_read_fn)(void *ctx, unsigned long long lba, unsigned int count, void *buffer);
```
从 `dkm_kernel_api + 0xA8` 偏移处获取函数指针。
暂不实现 VFS 系统调用——所有文件操作通过直接 FAT32 路径解析完成。
## 10. 网络接口
网络工具(curl、ping、browser)依赖 netman 已实现的:
- DHCP 客户端
- ARP 解析
- DNS 查询
- e1000/virtio_net TX/RX
工具应用通过 `kernel_api.net` 访问网络功能。
## 11. 内置应用详情
### 11.1 终端 (Bash)
- 状态结构:`bash_state` @ 0x4000000
- 终端缓冲:80 列 × 40 行(TERM_MAX_COLS × TERM_MAX_ROWS)
- 每格存储:字符(u8) + 前景色(u32)
- 输入缓冲:256 字节,支持插入模式和光标移动
- 提示符:`deshab# `
- 命令:help, clear, echo, version/ver, uname, date, about, reboot, halt, pwd, whoami, id
- 渲染:先绘制历史内容,再绘制当前输入行+光标
- 光标:2px 高下划线,DS_DARK_CURSOR 颜色
- 配色:DS_DARK_* 暗色主题
### 11.2 文本编辑器 (Editor)
- 状态结构:`editor_state` @ 0x5000000
- 文本缓冲:65536 字节(EDITOR_BUF_SIZE)
- 编辑操作:插入/删除字符、换行、方向键移动、Home/End
- 行号:3 位数字 + 分隔线(DS_DARK_TEXT_DIM 颜色)
- 自动滚动:光标超出可视区域时调整 scroll_y
- 状态栏:底部 20px,显示 L:行 C:列 + 修改标记(*)
- 光标:2px 宽竖线,DS_DARK_CURSOR 颜色
- 编辑区背景:DS_DARK_BG_SECONDARY
- 窗口标题:`Editor - untitled`
### 11.3 计算器 (Calculator)
- 状态结构:`calc_state` @ 0x6000000
- 运算:四则运算(+/-/×/÷),i64 精度
- 显示屏:圆角矩形,右对齐数字
- 按钮网格:4×5 布局(C/+/-/%/÷, 7/8/9/×, 4/5/6/-, 1/2/3/+, 0/./=)
- 按键颜色:功能键 DP_ABYSS_600,运算符 DS_DARK_ACCENT,等号 DP_SUCCESS
- 输入:键盘数字键 + 运算符,C 清零,Enter/= 计算
## 12. 分阶段实现计划
### Phase 1 — 桌面基础(已完成)
- ✅ Desktop Manager 核心框架
- ✅ 任务栏 + 时钟 + 桌面图标
- ✅ 窗口管理(创建/销毁/移动/焦点/拖拽)
- ✅ 事件路由系统
- ✅ PS/2 鼠标初始化 + 轮询
- ✅ 光标 save/restore
- ✅ 终端应用(Bash)
- ✅ 文本编辑器(Editor)
- ✅ 计算器(Calculator)
### Phase 2 — 文件操作与独立应用
- 工具应用独立开发框架(CODE/tools/ + desktop_app.h)
- FAT32 路径解析增强(目录遍历)
- 文件管理器(独立 .elf)
- 编辑器独立化(从内置 → 独立 tools/editor/)
- 文件打开器(关联 .txt → 编辑器)
- Ctrl+S 保存(需 FAT32 write API)
### Phase 3 — 网络
- TCP/IP 最小实现(基于 e1000/virtio_net)
- ping 工具(ICMP Echo)
- curl 工具(HTTP GET)
### Phase 4 — 高级应用
- 浏览器(HTTP + 简单 HTML 渲染)
- Bash 增强版(命令历史↑↓、ls、cat、Tab 补全)
- 更多系统工具
## 13. 目录结构
```
CODE/
desktop/ 桌面管理器(当前实现)
main.c 主循环、事件路由、compositing、3个内置应用
linker.ld PIE 链接脚本
MAKEFILE 构建脚本(输出 desktop.elf)
tools/ 独立工具应用(未来实现)
desktop_app.h 公共辅助头文件
bash/ 独立终端
main.c
MAKEFILE
linker.ld
editor/ 独立文本编辑器
main.c
MAKEFILE
linker.ld
fileman/ 文件管理器
main.c
MAKEFILE
linker.ld
browser/ 浏览器
main.c
MAKEFILE
linker.ld
curl/ HTTP 客户端
main.c
MAKEFILE
linker.ld
ping/ ICMP 工具
main.c
MAKEFILE
linker.ld
```
## 14. 构建与打包
### 当前构建
desktop.elf 编译输出到 `SYSTEM/system/deshab64/desktop.elf`。
编译参数(与 DSK / shell / FirstInit 一致):
```
clang -target x86_64-unknown-none -std=c11 -ffreestanding -fno-builtin
-fno-stack-protector -fpie -mno-red-zone -mno-sse -mno-sse2
-mno-mmx -msoft-float -m64 -Wall -Wextra -I../UTSM/include -O2
ld.lld -nostdlib -static -pie -z max-page-size=0x1000 -T linker.ld
```
### 未来工具应用构建
独立工具 .elf 将输出到 `SYSTEM/system/deshab64/tools/`,构建集成:
- 每个工具有独立 MAKEFILE(与 desktop 相同模式)
- build.ps1 中添加工具构建步骤
- mkfat32.c 中添加工具 .elf 入口
```
SYSTEM/system/deshab64/
desktop.elf ← 桌面管理器
tools/
bash.elf ← 独立终端
editor.elf ← 独立文本编辑器
fileman.elf ← 文件管理器
browser.elf ← 浏览器
curl.elf ← HTTP 客户端
ping.elf ← ICMP 工具
```
DSK 启动流程:
- 首次启动:mouseInit → netman → FirstInit → desktop
- 非首次启动:mouseInit → netman → desktop
+528
View File
@@ -0,0 +1,528 @@
# Deshab 工具应用设计文档
## 1. 概述
Deshab 工具应用是独立开发、独立编译的 .elf 可执行文件,运行在桌面管理器(Desktop Manager)环境中。
每个工具在 `CODE/tools/{name}/` 下拥有独立的 `main.c` + `MAKEFILE` + `linker.ld`,
通过 DSK 的 FAT32 + ELF loader 加载,接收 `dsk_boot_context` 系统上下文。
**核心约束**:
- 所有应用运行在 Ring0,单地址空间,无内存隔离
- 独立工具通过 `dsk_entry(dsk_boot_context *ctx)` 入口点启动
- 工具可以直接访问 framebuffer、PS/2 输入、kernel_api
- 网络工具依赖 kernel_api.net,文件工具依赖 FAT32 block_read
- 公共辅助代码通过 `CODE/tools/desktop_app.h` 共享
**开发模式演进**:
- **当前阶段**:3 个内置应用(Bash/Editor/Calculator)使用回调模式编译在 desktop.elf 内
- **目标阶段**:工具应用独立开发为单独 .elf,桌面管理器通过 ELF 加载方式载入
## 2. 应用 ABI
### 2.1 独立工具入口
独立工具 .elf 实现以下入口点:
```c
__attribute__((visibility("default")))
void dsk_entry(const dsk_boot_context *ctx);
```
工具接收完整的 `dsk_boot_context`,包含:
```c
typedef struct dsk_boot_context {
u64 magic; /* 0x44534B31424F4F54 ("DSK1BOOT") */
u32 abi_version; /* 1 */
u32 size;
u64 flags;
u64 hhdm_offset;
u64 rsdp_address;
u64 framebuffer_address; /* 帧缓冲物理地址 (+ HHDM) */
u64 framebuffer_width;
u64 framebuffer_height;
u64 framebuffer_pitch;
u32 framebuffer_bpp;
u64 boot_modules_response;
u64 dkm_kernel_api; /* DKM kernel_api 分发表 */
u64 dkm_driver_table;
u64 dkm_driver_count;
u64 utsm_state;
u64 drr_state;
u64 memory_map;
u64 memory_map_count;
u64 memory_map_entry_size;
u64 kernel_stack_top;
} dsk_boot_context;
```
### 2.2 公共辅助头文件
`CODE/tools/desktop_app.h` 提供所有工具共享的定义和辅助函数:
```c
/* 类型定义 */
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
/* COM1 串口日志 */
#define COM1 0x3F8
static inline void outb(u16 port, u8 value);
static inline u8 inb(u16 port);
void sputc(char c);
void swrite(const char *s);
void slog(const char *s);
/* PS/2 键盘轮询 */
int ps2kbd_poll(u8 *scancode); /* 返回 1=有数据 */
/* PS/2 鼠标轮询 */
int ps2mouse_poll(int *dx, int *dy, int *btn); /* 返回 1=有数据包 */
/* scan code set 1 → ASCII 映射 */
char scan_to_ascii(u8 sc, int shift);
/* 帧缓冲绘制辅助 */
void fb_init(u64 addr, u64 w, u64 h, u64 pitch);
void fb_pixel(int x, int y, u32 color);
void fb_rect(int x, int y, int w, int h, u32 color);
void fb_string(const char *s, int x, int y, u32 fg, u32 bg, int step);
/* FAT32 文件读取辅助 */
typedef int (*block_read_fn)(u32 index, u64 lba, u32 count, void *buf);
int fat32_read_file(block_read_fn br, const char *path, u8 **data, u32 *size);
/* 窗口概念(标题栏+关闭按钮+客户区) */
#define WIN_TITLEBAR_H 28
#define WIN_BORDER_W 2
void win_draw_frame(int x, int y, int w, int h, const char *title, int focused);
int win_hit_close(int wx, int wy, int ww, int wh, int mx, int my);
```
### 2.3 当前内置应用 ABI(回调模式)
当前 3 个内置应用编译在 desktop.elf 内,使用回调模式:
```c
typedef struct app_ctx {
du_context *fb; /* 全局帧缓冲渲染上下文 */
desktop_win *win; /* 关联窗口 */
int client_x, client_y, client_w, client_h; /* 客户区坐标 */
int should_exit; /* 退出标志 */
desktop_block_read_fn block_read; /* FAT32 块读取函数 */
const void *kernel_api; /* DKM kernel_api 分发表 */
} app_ctx;
typedef void *(*app_create_fn)(app_ctx *ctx);
typedef void (*app_event_fn)(void *state, app_ctx *ctx, desktop_event *ev);
typedef void (*app_draw_fn)(void *state, app_ctx *ctx);
typedef void (*app_destroy_fn)(void *state);
```
### 2.4 应用生命周期
**回调式(当前)**:
```
1. 用户点击图标/快速启动按钮
2. 桌面管理器创建窗口
3. 桌面调用 app->on_create(ctx) → 返回 app_state
4. 事件循环:桌面调用 app->on_event(app_state, ctx, ev)
5. 绘制:桌面调用 app->on_draw(app_state, ctx)
6. 用户关闭窗口 → 桌面调用 app->on_destroy(app_state)
7. 桌面销毁窗口,回收资源
```
**独立 ELF 式(未来)**:
```
1. 桌面管理器通过 FAT32 读取工具 .elf
2. PIE ELF loader 加载 + 重定位
3. 调用 dsk_entry(ctx)
4. 工具自行接管输入/渲染/主循环
5. 工具返回 → 桌面管理器恢复控制
```
## 3. 工具应用详细设计
### 3.1 终端 (Bash) — CODE/tools/bash/
**状态**:内置版本已实现(回调模式);独立版本待开发
**功能**:
- 接收 dsk_boot_context,全屏暗色终端
- PS/2 键盘输入,命令历史(↑↓键)
- 内置命令:help, clear, echo, version/ver, uname, date, about, reboot, halt, pwd, whoami, id, ls, cat
- Sealed Arc 暗色主题(DS_DARK_* 色系)
**UI 设计**:
```
┌─ deshab# ────────────────────────────[✕]─┐
│ deshab# echo "Hello, Deshab!" │
│ Hello, Deshab! │
│ deshab# _ │
│ │
│ │
│ │
├──────────────────────────────────────────┤
│ / 12:34 │
└──────────────────────────────────────────┘
```
**独立版本结构**:
- 标题栏:`deshab#` 标题 + 右侧红色 X 关闭按钮
- 主区域:暗色终端输出区 + 当前输入行 + 闪烁光标
- 状态栏(底部 20px):左侧当前目录 `/`,右侧 RTC 时间
**数据结构**:
```c
typedef struct {
u8 ch[TERM_MAX_CHARS]; /* 字符缓冲 */
u32 fg[TERM_MAX_CHARS]; /* 前景色缓冲 */
int cols, rows; /* 终端尺寸 */
int cur_col, cur_row; /* 当前光标位置 */
char input_buf[256]; /* 当前输入行 */
int input_len, input_cursor; /* 输入长度和光标 */
int prompt_len; /* 提示符长度 */
char history[16][256]; /* 命令历史 */
int history_count; /* 历史条数 */
int history_pos; /* 历史浏览位置 */
} bash_state;
```
**命令实现**:
| 命令 | 功能 | 依赖 |
|------|------|------|
| help | 显示可用命令列表 | 无 |
| clear | 清屏 | 无 |
| echo | 回显参数 | 无 |
| version / ver | 显示版本 "Deshab OS v0.1.0" | 无 |
| uname | 显示系统名 "Deshab" | 无 |
| date | 显示 RTC 日期时间 | CMOS |
| about | 显示系统信息 | 无 |
| reboot | 重启(0x64→0xFE) | 键盘控制器 |
| halt | 停机(HLT) | 无 |
| pwd | 显示当前目录 "/" | 无 |
| whoami | 显示 "root" | 无 |
| id | 显示 "uid=0(root) gid=0(root)" | 无 |
| ls | 列出目录内容 | FAT32 增强遍历 |
| cat | 显示文件内容 | FAT32 读取 |
---
### 3.2 文本编辑器 (Editor) — CODE/tools/editor/
**状态**:内置版本已实现(回调模式);独立版本待开发
**功能**:
- 全屏编辑器,行号 + 编辑区 + 状态栏
- FAT32 文件打开(通过 kernel_api block_read)
- 编辑操作:插入/删除字符、换行、光标移动(方向键/Home/End)
- PageUp/PageDown 翻页
- 文本选择:Shift+方向键
- Ctrl+S 保存(需 FAT32 write API)
- 状态栏:行:列、文件名、修改标记
**UI 设计**:
```
┌─ Editor — README.TXT ───────────────[✕]─┐
│ 1│ # Deshab OS │
│ 2│ 单地址空间 Ring0 内核实验系统 │
│ 3│ │
│ 4│ ## 概述 │
│ 5│ Deshab 是一个...█ │
│ │ │ │
│ │ │ │
├───┴──────────────────────────────────────┤
│ L:5 C:15 README.TXT * │
└──────────────────────────────────────────┘
```
**数据结构**:
```c
typedef struct {
char text[EDITOR_BUF_SIZE]; /* 文本缓冲 (64KB) */
int text_len; /* 文本长度 */
int cursor_pos; /* 光标位置(字节偏移) */
int scroll_y; /* 垂直滚动偏移(行数) */
int cursor_line; /* 光标行号 */
int cursor_col; /* 光标列号 */
int sel_start, sel_end; /* 选择范围 */
int modified; /* 修改标记 */
char filename[128]; /* 当前文件名 */
} editor_state;
```
**渲染细节**:
- 行号:3 位数字宽度(`DS_DARK_TEXT_DIM` 颜色)+ 1px 分隔线(`DS_DARK_DIVIDER`)
- 编辑区背景:`DS_DARK_BG_SECONDARY`
- 光标:2px 宽竖线,`DS_DARK_CURSOR` 颜色
- 状态栏:底部 20px,`DP_ABYSS_800` 背景,显示 `L:行 C:列 文件名 *修改标记`
---
### 3.3 文件管理器 (FileManager) — CODE/tools/fileman/
**状态**:占位(当前 desktop.elf 中 fileman 无回调);独立版本待开发
**功能**:
- 双栏布局:左侧目录树、右侧文件列表
- FAT32 目录遍历(需增强到子目录)
- 文件图标区分:目录/ELF/TXT/CONF
- 双击打开:.txt/.conf → 编辑器,.elf → 执行
- 路径栏 + 返回按钮
**UI 设计**:
```
┌─ 文件管理器 ────────────────────────[✕]─┐
│ [←] /system/deshab64/ │
├──────────┬───────────────────────────────┤
│ / │ 📁 tools/ DIR │
│ /system │ 📄 desktop.elf 53KB ELF │
│ /driver │ 📄 editor.elf 28KB ELF │
│ │ 📄 deshab.elf 131KB ELF │
│ │ 📄 README.TXT 2KB TXT │
│ │ 📄 user.conf 1KB CONF │
├──────────┴───────────────────────────────┤
│ 6 项 │
└──────────────────────────────────────────┘
```
**文件图标颜色**:
| 类型 | 图标 | 主色调 |
|------|------|--------|
| 目录 | 📁 | DP_ARC_500 (紫) |
| ELF | 📄 + 可执行标记 | DP_SEAL_300 (青) |
| TXT | 📄 + 文本标记 | DP_NEUTRAL_300 (灰) |
| CONF | 📄 + 齿轮标记 | DP_WARNING (琥珀) |
**依赖**:FAT32 子目录遍历(当前 DSK 仅支持根目录读取,需增强)
---
### 3.4 浏览器 (Browser) — CODE/tools/browser/
**状态**:Phase 4 实现(依赖 TCP/IP + HTTP + HTML 渲染)
**功能**:
- 地址栏 + 导航按钮(后退/前进/刷新)
- HTTP GET 请求(通过 kernel_api.net)
- 简单 HTML 渲染:标题、段落、链接、列表
- 超链接点击导航
- 历史记录(后退/前进栈)
**UI 设计**:
```
┌─ 浏览器 ────────────────────────────[✕]─┐
│ [←][→][↻] [http://example.com ][Go] │
├──────────────────────────────────────────┤
│ Example Domain │
│ │
│ This domain is for use in illustrative │
│ examples in documents. You may use this │
│ domain in literature... │
│ │
│ More information... │
└──────────────────────────────────────────┘
```
**依赖**:
- TCP/IP 栈(需实现 TCP 连接、发送/接收、拥塞控制)
- HTTP/1.1 客户端(GET 请求、响应解析)
- DNS 解析(netman 已实现)
- HTML 解析器(简化版,仅处理常见标签)
---
### 3.5 HTTP 客户端 (curl) — CODE/tools/curl/
**状态**:Phase 3 实现(依赖 TCP/IP 最小实现)
**功能**:
- 命令行界面运行(终端风格)
- HTTP GET/HEAD 请求
- URL 解析(host:port/path)
- 响应头显示(`-i` 选项)
- 超时处理
**命令行**:
```
curl http://example.com
curl -i http://example.com
curl --head http://example.com
```
**UI 设计**:
```
┌─ curl ──────────────────────────────[✕]─┐
│ > curl http://example.com │
│ HTTP/1.1 200 OK │
│ Content-Type: text/html │
│ │
│ <!doctype html> │
│ <html> │
│ ... │
└──────────────────────────────────────────┘
```
**依赖**:TCP/IP 栈 + DNS 解析
**实现方式**:作为窗口化终端风格应用运行,输出 HTTP 响应内容。
---
### 3.6 ICMP 工具 (ping) — CODE/tools/ping/
**状态**:Phase 3 实现(依赖 ICMP + ARP)
**功能**:
- 发送 ICMP Echo Request
- 接收 ICMP Echo Reply
- RTT 计算(基于 PIT 已校准计时器)
- 统计信息显示(发送/接收/丢包率/平均 RTT)
**命令行**:
```
ping 192.168.1.1
ping -c 4 10.0.2.2
```
**UI 设计**:
```
┌─ ping ──────────────────────────────[✕]─┐
│ PING 192.168.1.1 │
│ 64 bytes: seq=0 time=2ms │
│ 64 bytes: seq=1 time=1ms │
│ 64 bytes: seq=2 time=3ms │
│ │
│ --- 192.168.1.1 ping statistics --- │
│ 3 packets transmitted, 3 received, 0% │
│ RTT min/avg/max = 1/2/3 ms │
└──────────────────────────────────────────┘
```
**依赖**:
- ICMP 协议实现(需通过 kernel_api.net 发送原始 IP 包)
- ARP 解析(netman 已实现)
- 计时器(PIT 已校准)
---
### 3.7 更多应用(规划中)
| 应用 | 描述 | Phase | 依赖 |
|------|------|-------|------|
| System Monitor | CPU/内存/网络状态 | 2 | kernel_api |
| Paint | 简单绘图工具 | 2 | 无 |
| Settings | 系统偏好设置 | 2 | FAT32 write |
| Screenshot | 屏幕截图保存 | 3 | FAT32 write |
| Music Player | PC 喇叭/AC97 音频 | 4 | 音频驱动 |
## 4. 依赖矩阵
```
FAT32 Read | FAT32 Write | TCP/IP | ICMP | DNS | ARP | PS/2输入
bash ✓ | | | | | | ✓
editor ✓ | (保存) | | | | | ✓
fileman ✓ | | | | | | ✓
browser ✓ | | ✓ | | ✓ | ✓ | ✓
curl ✓ | | ✓ | | ✓ | ✓ | ✓
ping ✓ | | | ✓ | | ✓ | ✓
calculator | | | | | | | ✓
```
## 5. 应用图标设计
每个应用使用 32×32 像素图标,程序化生成(C 函数绘制,无需位图文件)。
| 应用 | 图标描述 | 主色调 | 绘制函数 |
|------|----------|--------|----------|
| bash | 终端窗口 >_ | DP_SEAL_300 (亮青) | `draw_icon_terminal()` |
| editor | 笔记本+文本行 | DP_SEAL_500 (青) | `draw_icon_editor()` |
| fileman | 文件夹 | DP_ARC_500 (紫) | `draw_icon_folder()` |
| calculator | 计算器按键 | DP_WARNING (琥珀) | `draw_icon_calc()` |
| browser | 地球/指南针 | DP_SEAL_300 (亮青) | 待实现 |
| curl | 箭头+网络 | DP_SEAL_700 (深青) | 待实现 |
| ping | 信号波 | DP_SUCCESS (绿) | 待实现 |
**图标绘制规范**:
- 圆角矩形背景(6px 圆角,`DU_RADIUS_SM`)
- 1px 描边(使用边框色)
- 前景图形使用应用主色调
- 背景色:DP_ABYSS_700
## 6. 构建集成
### 6.1 独立工具 MAKEFILE
每个工具有独立的 MAKEFILE(与 desktop.elf 相同模式):
```makefile
# tools/bash/MAKEFILE 示例
CC := clang
LD := ld.lld
ROOT := ../../..
OUT := $(ROOT)/SYSTEM/system/deshab64/tools/bash.elf
CFLAGS := -target x86_64-unknown-none -std=c11 -ffreestanding -fno-builtin \
-fno-stack-protector -fpie -mno-red-zone -mno-sse -mno-sse2 \
-mno-mmx -msoft-float -m64 -Wall -Wextra -I.. -I../../UTSM/include -O2
LDFLAGS := -nostdlib -static -pie -z max-page-size=0x1000 -T linker.ld
C_SOURCES := main.c
OBJECTS := $(C_SOURCES:.c=.o)
.PHONY: all clean
all: $(OUT)
$(OUT): $(OBJECTS) linker.ld
@if not exist "$(ROOT)\SYSTEM\system\deshab64\tools" mkdir "$(ROOT)\SYSTEM\system\deshab64\tools"
$(LD) $(LDFLAGS) -o $@ $(OBJECTS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
```
### 6.2 build.ps1 集成
在 `build.ps1` 中添加工具构建步骤:
```powershell
# 构建工具应用
$tools = @("bash", "editor", "fileman", "curl", "ping", "browser")
foreach ($tool in $tools) {
Push-Location "CODE/tools/$tool"
& make -f MAKEFILE
Pop-Location
}
```
### 6.3 FAT32 镜像更新
`mkfat32.c` 中添加工具 .elf 入口:
```
SYSTEM/system/deshab64/tools/bash.elf
SYSTEM/system/deshab64/tools/editor.elf
SYSTEM/system/deshab64/tools/fileman.elf
SYSTEM/system/deshab64/tools/curl.elf
SYSTEM/system/deshab64/tools/ping.elf
SYSTEM/system/deshab64/tools/browser.elf
```
## 7. 测试策略
- **单元测试**:每个应用的事件处理回调可用模拟事件测试
- **QEMU 集成测试**:完整的启动→桌面→打开应用→操作→关闭流程
- **串口日志**:所有应用通过 COM1 输出调试信息(`[bash]`、`[editor]` 等前缀)
- **FAT32 验证**:使用 `driver/test.fat32` 测试镜像验证文件读取功能
- **独立工具验证**:DSK 直接加载工具 .elf,检查 dsk_entry 入口调用和上下文传递
+38
View File
@@ -0,0 +1,38 @@
# Deshab 测试用例矩阵
本目录组织 Deshab-OS 的系统化测试用例文档。
## 测试矩阵总览
| 文档 | 范围 | 优先级 |
|---|---|---|
| [boot-regression.md](boot-regression.md) | 启动链路回归(首启/正常/dev_mode/无盘/无NIC) | P0 |
| [linux-compat.md](linux-compat.md) | UTSM+Linux 双内核兼容层端到端 | P0 |
| [pe-compat.md](pe-compat.md) | PE/EXE 兼容层(PE32+ native + PE32 x86emu32) | P1 |
| [driver-matrix.md](driver-matrix.md) | 14 DKM 驱动功能矩阵 | P1 |
| [userapps-matrix.md](userapps-matrix.md) | 用户态程序矩阵(shell/cmd/desktop/tools) | P1 |
| [network-e2e.md](network-e2e.md) | 网络端到端(DHCP/ARP/DNS/ping/curl) | P1 |
| [performance-baseline.md](performance-baseline.md) | 性能基线(TSC 测量) | P2 |
| [x86emu32-coverage.md](x86emu32-coverage.md) | x86emu32 指令覆盖率 | P2 |
## 测试场景状态标记
- ✅ PASS: 全部测试项通过
- 🔶 PARTIAL: 部分测试项通过,存在已知限制
- ❌ FAIL: 关键测试项失败,需修复
- ⬜ PENDING: 未执行
- ⏭ SKIP: 因环境/依赖不可用而跳过
## 自动化执行
```powershell
# 运行全部自动化测试场景
.\ISO\run_tests.bat
# 输出
# ISO/logs/test-report-<timestamp>.md
```
## Bug 跟踪
所有测试发现的 bug 登记到 [../Bug记录.txt](../Bug记录.txt),并在对应测试文档中引用 bug 编号。
+96
View File
@@ -0,0 +1,96 @@
# 启动链路回归测试矩阵
> 对应计划 Phase C2:验证不同启动场景下系统行为正确
## 状态: ⬜ PENDING
## 测试场景
| # | 场景 | firstInit.txt | 配置 | 期望串口锚点 | 状态 | Bug# |
|---|---|---|---|---|---|---|
| B1 | 首次启动 | `0\n0` | 空 user.conf | `[DSK] firstInit=0` → `mouseInit` → `FirstInit` → 完成向导 → 写盘 | ⬜ | |
| B2 | 正常启动 | `1\n0` | 已有 user.conf | `[DSK] firstInit=1` → `login` → desktop | ⬜ | |
| B3 | dev_mode | `1\n1` | dev_mode=1 | `[DSK] dev_mode` → shell run_dev_tests 全绿 → Esc → 正常流程 | ⬜ | |
| B4 | 无 SATA 盘 | 任意 | 移除 sata_fat32_dsk.img | DSK fallback 到 Limine module | ⬜ | |
| B5 | 无 NIC | 任意 | 移除 `-netdev` | e1000 not found → netman 警告 → 继续启动 | ⬜ | |
| B6 | Linux 兼容层启用 | 任意 | +linux-bzImage +linux-initrd | UTSM VMM + Linux park → DSK 正常接管 | ⬜ | |
## 串口日志锚点(标准启动)
### 首次启动(B1)
```
[UTSM] boot
[UTSM] SELFTEST PASS
[UTSM] loading DSK
[DSK] boot
[DSK] context ok
[DSK] firstInit=0
[DSK] loading mouseInit.elf
[DSK] loading FirstInit.elf
[FirstInit] ...
[DSK] writing firstInit=1
[DSK] loading shell.elf
```
### 正常启动(B2)
```
[UTSM] boot
[UTSM] SELFTEST PASS
[UTSM] loading DSK
[DSK] boot
[DSK] firstInit=1
[DSK] loading login.elf
[DSK] loading desktop.elf
```
### dev_mode(B3)
```
[UTSM] boot
[UTSM] SELFTEST PASS
[DSK] dev_mode=1
[DSK] loading shell.elf
[shell] run_dev_tests:
[shell] ls: OK
[shell] echo>: OK
[shell] cat: OK
[shell] cp: OK
[shell] mv: OK
[shell] rm: OK
[shell] dev_tests done
... (Esc 返回后正常流程)
```
## 自动化脚本
[ISO/run_qemu_scenario.bat](../../ISO/run_qemu_scenario.bat) 接收场景名参数:
```powershell
.\ISO\run_qemu_scenario.bat firstboot
.\ISO\run_qemu_scenario.bat normal
.\ISO\run_qemu_scenario.bat devmode
.\ISO\run_qemu_scenario.bat nosata
.\ISO\run_qemu_scenario.bat nonic
.\ISO\run_qemu_scenario.bat linux
```
每个场景输出独立日志到 `ISO/logs/<scenario>-<timestamp>.log`。
## 配置文件准备
### B1 首次启动
- `SYSTEM/system/user/use/firstInit.txt`: `0\n0`
- 备份 `user.conf` 后清空内容(仅保留 `DESHAB_USERCONF_V1` 头)
### B3 dev_mode
- `firstInit.txt`: `1\n1`
- 保持现有 user.conf
### B4 无 SATA
- 临时重命名 `.build_tmp/sata_fat32_dsk.img` → `.build_tmp/sata_fat32_dsk.img.bak`
- run_qemu.bat 自动检测,缺失时跳过 `-device ide-hd`
+70
View File
@@ -0,0 +1,70 @@
# 14 DKM 驱动功能矩阵
> 对应计划 Phase C3:每个驱动的加载、探测、功能验证点
## 状态: ⬜ PENDING
## 驱动清单
| # | 驱动 | stage | class | required | QEMU 参数 | 期望串口日志 | 功能验证点 | 状态 | Bug# |
|---|---|---|---|---|---|---|---|---|---|
| 1 | timer | 0 | timer | ✅ | 默认 | `[DKM:timer]` | 100ms busy-wait 精度 | ⬜ | |
| 2 | apic | 0 | interrupt | ✅ | 默认 | `[DKM:apic] MADT found` | LAPIC MMIO 只读 | ⬜ | |
| 3 | acpi | 0 | platform | ❌ | 默认 | `[DKM:acpi]` | RSDP/XSDT 枚举 | ⬜ | |
| 4 | pci | 0 | bus | ✅ | 默认 | `[DKM:pci]` | PCI config space 扫描 | ⬜ | |
| 5 | console_fb | 1 | console | ❌ | 默认 | `[DKM:console_fb]` | 淡蓝色背景清屏 | ⬜ | |
| 6 | ahci | 1 | storage | ❌ | +SATA 测试盘 | `[DKM:ahci] ahci0 registered` | LBA0 读取 | ⬜ | |
| 7 | nvme | 1 | storage | ❌ | `-device nvme` | `[DKM:nvme] 1b36:0010 found` | BAR0 读取(高位 MMIO 未解决则 SKIP) | ⏭ | |
| 8 | bootfs | 1 | fs | ✅ | 默认 | `[DKM:bootfs]` | Limine boot module FS | ⬜ | |
| 9 | vfs | 2 | fs-core | ✅ | 默认 | `[DKM:vfs]` | 挂载 bootfs | ⬜ | |
| 10 | fat32 | 2 | fs | ❌ | +SATA 测试盘 | `[DKM:fat32]` | BPB/FAT/目录项解析 | ⬜ | |
| 11 | devfs | 2 | fs | ❌ | 默认 | `[DKM:devfs]` | /dev/version, /dev/fb0 等 | ⬜ | |
| 12 | e1000 | 3 | net | ❌ | `-device e1000` | `tx=ready rx=ready` | DHCP + ping | ⬜ | |
| 13 | virtio_net | 3 | net | ❌ | `-device virtio-net-pci` | `[DKM:virtio_net] 1af4:1001 found` | capability 枚举 | ⬜ | |
| 14 | ath9k | 3 | net | ❌ | (QEMU 不支持 WiFi) | `no Atheros WiFi device found` | 跳过(QEMU 限制) | ⏭ | |
| 15 | ps2kbd | 3 | input | ❌ | 默认 | scan code 读取 | 输入回显 | ⬜ | |
## stage 加载顺序
```
stage 0 (platform): timer → apic → acpi → pci
stage 1 (boot): console_fb → ahci → nvme → bootfs
stage 2 (fs): vfs → fat32 → devfs
stage 3 (optional): e1000 → virtio_net → ath9k → ps2kbd
```
## 测试设备 QEMU 参数
### AHCI + FAT32 测试盘
```
-drive id=sata0,format=raw,file=.build_tmp/sata_fat32_dsk.img,if=none ^
-device ide-hd,drive=sata0,bus=ide.0 ^
```
### NVMe
```
-device nvme,drive=nvme0,serial=UTSMTEST ^
-drive id=nvme0,format=raw,file=.build_tmp/nvme_test.img,if=none ^
```
### e1000
```
-netdev user,id=net0 ^
-device e1000,netdev=net0,mac=52:54:00:12:34:56 ^
```
### virtio-net
```
-netdev user,id=net0 ^
-device virtio-net-pci,netdev=net0 ^
```
## 已知限制
- NVMe BAR0 在 QEMU 中常位于 4G 以上,当前 HHDM 不能安全访问,需 Phase 0 高位 MMIO 映射解决
- ath9k 在 QEMU 中无对应设备模拟,永远走 "not found" 路径
- 多个 NIC 同时挂载会改变 PCI 拓扑,可能影响 e1000 探测位置
+77
View File
@@ -0,0 +1,77 @@
# Linux 兼容层测试矩阵
> 对应计划 Phase A:UTSM+Linux 双内核 park-and-resume 端到端验证
> 前置条件:Linux 6.6 LTS bzImage 已构建(SYSTEM/boot/linux-bzImage + linux-initrd.img)
## 状态: ⬜ PENDING
## 测试环境
- QEMU 加速: WHPX (`-accel whpx -cpu max`),TCG 不支持 VMX
- Linux 模块: limine.conf 中 bzImage/initrd 模块已启用
- 串口: `-serial stdio`,过滤 `Linux version|utsm-linux|linux_compat|UTSM.*Linux|DSK|shell`
## 测试矩阵
| # | 测试项 | 串口/Shell 预期 | 状态 | 失败处理 | Bug# |
|---|---|---|---|---|---|
| A5.1 | UTSM VMM self-test 通过 | `[UTSM] VMM self-test PASS` | ⬜ | 检查 VMCS/EPT 初始化;BIOS 启用 VT-x | |
| A5.2 | bzImage 加载与解析 | `[UTSM] Linux bzImage loaded` | ⬜ | 检查 linux_loader_init header magic 校验 | |
| A5.3 | EPT 映射 + vmlaunch | `[UTSM] Linux guest launched` | ⬜ | 检查 EPT 表、VMCS guest 状态 | |
| A5.4 | Linux 内核启动 | `Linux version 6.6.x` 串口日志 | ⬜ | 检查 cmdline、boot_params、E820 表 | |
| A5.5 | init 脚本运行 | `[utsm-linux] init started` | ⬜ | 检查 initramfs 结构 | |
| A5.6 | exec daemon 启动 + park | `[utsm-linux] starting utsm_exec_daemon...` → `linux_compat_init() ready` | ⬜ | 检查 daemon 编译、IPC 共享内存初始化 | |
| A5.7 | DSK 正常接管 | `[DSK] boot` → `[DSK] SELFTEST PASS` | ⬜ | 验证 Linux park 不阻塞 DSK | |
| A5.8 | shell `linux`(无参)状态查询 | `Linux 兼容层已就绪 (双内核 park-and-resume)` | ⬜ | 检查 reserved[5] 传递链 | |
| A5.9 | shell `linux ls` | 输出 initramfs 根目录内容 | ⬜ | 检查 IPC exec 协议、vmresume 路径 | |
| A5.10 | shell `linux uname -a` | 输出 `Linux ... 6.6.x ...` | ⬜ | 同上 | |
| A5.11 | shell `linux cat /etc/hostname` | 输出 hostname | ⬜ | 同上 | |
| A5.12 | 错误路径:`linux nosuchprog` | 输出 exec 失败,shell 不崩溃 | ⬜ | 检查 EXEC_EXIT 消息处理 | |
## 关键约束验证
| 约束 | 验证方法 | 状态 |
|---|---|---|
| Linux guest cmdline 含 `nohlt idle=poll` | 检查 [linux_loader.c](../../CODE/UTSM/vmm/linux_loader.c) cmdline 构造 | ⬜ |
| IPC 共享内存 GPA=0x04000000, 1MB | e820 中标记 RESERVED,Linux 不分配 | ⬜ |
| Linux guest RAM 起始 0x05000000 | 检查 EPT 映射范围 | ⬜ |
| exec daemon 先发 EXEC_READY 再 HLT | daemon 源码 [utsm_exec_daemon.c](../../CODE/linux/initramfs/bin/utsm_exec_daemon.c) | ⬜ |
| UTSM hypercall ABI: RAX=magic\|op | 检查 [hypercall.c](../../CODE/UTSM/vmm/hypercall.c) 处理 | ⬜ |
## 已知限制
- QEMU TCG 不支持 VMX,必须 WHPX 或真机
- WHPX 可能不暴露 nested VMX 给 guest(需实测)
- 若 CPU 不支持 VT-x,整个 Linux 兼容层降级为"不可用",不影响其他系统功能
## 手动测试命令
进入 shell 后执行:
```
deshab:/ $ linux
deshab:/ $ linux ls
deshab:/ $ linux uname -a
deshab:/ $ linux cat /etc/hostname
deshab:/ $ linux nosuchprog
```
## 串口日志锚点
启动后期望按顺序出现:
```
[UTSM] VMM self-test PASS
[UTSM] Linux bzImage loaded
[UTSM] Linux guest launched
Linux version 6.6.x ...
[utsm-linux] init started
[utsm-linux] kernel: 6.6.x
[utsm-linux] starting utsm_exec_daemon...
[utsm-linux] daemon PID=...
[utsm-linux] init: daemon running, entering idle hold
[UTSM] linux_compat service ready
[DSK] boot
[DSK] SELFTEST PASS
... (进入 shell 提示符)
```
+62
View File
@@ -0,0 +1,62 @@
# 网络端到端测试矩阵
> 对应计划 Phase C4 网络部分:e1000 + net_stack + ping/curl/browser
## 状态: ✅ 已验证([deshab_system_roadmap_plan.md](../../.trae/documents/deshab_system_roadmap_plan.md) Phase 1)
> 本矩阵用于回归验证,确保不退化
## 测试环境
- QEMU 网络: `-netdev user,id=net0 -device e1000,netdev=net0`
- slirp 默认: guest 10.0.2.15, 网关 10.0.2.2, DNS 10.0.2.3
- 主机 http 服务: `python -m http.server 8000`
## 测试矩阵
| # | 测试项 | 命令 | 预期 | 状态 | Bug# |
|---|---|---|---|---|---|
| N1 | e1000 驱动加载 | (自动) | `tx=ready rx=ready` | ✅ | |
| N2 | netman 注册 | (自动) | netman 打印设备枚举 | ✅ | |
| N3 | DHCP 获取 IP | (自动) | netman DHCP final rc=0 | ✅ | |
| N4 | ARP 解析网关 | (自动) | netman ARP final rc=0 | ✅ | |
| N5 | DNS 查询 | (自动) | netman DNS final rc=0 | ✅ | |
| N6 | shell ping 网关 | `ping 10.0.2.2` | 4/4 reply, RTT<10ms | ✅ | |
| N7 | shell ping 外网 | `ping 8.8.8.8` | (依赖主机联网) | 🔶 | |
| N8 | shell curl 本地 | `curl http://10.0.2.2:8000/` | HTTP 200 + 目录 HTML | ✅ | |
| N9 | shell curl 外网 | `curl http://example.com/` | HTTP 200 (依赖主机联网) | 🔶 | |
| N10 | curl.elf 工具 | `run CURL.ELF` | 独立工具执行 curl | ✅ | |
| N11 | ping.elf 工具 | `run PING.ELF` | 独立工具执行 ping | ✅ | |
| N12 | browser.elf 工具 | `run BROWSER.ELF` | URL 输入 + HTTP GET | ✅ | |
## 回归验证
每次启动 dev_mode 时,run_dev_tests 应包含:
```
[shell] dev_tests:
...
ping 10.0.2.2: OK (4/4 reply, RTT=Xms)
...
```
若 ping 失败:
1. 检查 e1000 是否加载(`-device e1000` 参数)
2. 检查 netman 是否成功 DHCP
3. 检查 ARP 是否解析网关
4. 串口日志 grep `e1000|netman|DHCP|ARP|DNS|network`
## 性能基线
参见 [performance-baseline.md](performance-baseline.md):
- ping RTT < 10ms
- curl 64KB 页面接收无明显停顿
- DHCP 总耗时 < 5s
## 已知限制
- HTTPS/TLS 不支持(curl 仅 http)
- TCP 仅最小 client 实现(无拥塞控制/乱序队列)
- QEMU slirp 不支持真实 Wi-Fi 模式,ath9k 驱动在 QEMU 中无设备
+72
View File
@@ -0,0 +1,72 @@
# PE/EXE 兼容层测试矩阵
> 对应计划 Phase B:PE32+ (64位 native) 与 PE32 (32位 x86emu32) 兼容层验证
> 入口:cmd.elf 通过 `ctx->reserved[4]` 取 pe_service
## 状态: ⬜ PENDING
## 测试程序
| 文件 | 类型 | 来源 | FAT32 8.3 名 | 路径 |
|---|---|---|---|---|
| hello64.exe | PE32+ (64位) | MinGW/MSVC 编译或 Python 生成 | `HELLO64 EXE` | SYSTEM/system/deshab64/tools/ |
| hello32.exe | PE32 (32位) | MinGW 交叉编译或 Python 生成 | `HELLO32 EXE` | SYSTEM/system/deshab64/tools/ |
## 测试矩阵
| # | 测试项 | 命令 | 预期输出 | 状态 | Bug# |
|---|---|---|---|---|---|
| B2.1 | PE32+ 加载执行 | `pe HELLO64.EXE` | `Hello from PE32+!` | ⬜ | |
| B2.2 | PE32 加载执行(解释器) | `pe HELLO32.EXE` | `Hello from PE32!` | ⬜ | |
| B2.3 | PE 头解析 | `peinfo HELLO64.EXE` | `machine=0x8664 entry=0x... image_base=0x...` | ⬜ | |
| B2.4 | 文件不存在错误路径 | `pe NONEXIST.EXE` | `Error: file not found` | ⬜ | |
| B2.5 | 无参用法提示 | `pe` | 显示用法 | ⬜ | |
| B2.6 | ExitProcess 返回 | (执行后) | cmd 接管,longjmp 跳回 pe_service_run | ⬜ | |
| B2.7 | PE32 头解析 | `peinfo HELLO32.EXE` | `machine=0x14c entry=0x... image_base=0x00400000` | ⬜ | |
## 关键 ABI 验证
| ABI | 验证方法 | 状态 |
|---|---|---|
| `ctx->reserved[4]` 持 pe_service* | [cmd/main.c:825](../../CODE/cmd/main.c#L825) | ⬜ |
| `PE_SERVICE_MAGIC` 校验 | [cmd/main.c:830](../../CODE/cmd/main.c#L830) | ⬜ |
| `g_pe_svc` 缓存 | [cmd/main.c:108](../../CODE/cmd/main.c#L108) | ⬜ |
| PE32+ IAT 填 ms_abi shim | [pe_loader.c](../../CODE/UTSM/pe/pe_loader.c) | ⬜ |
| PE32 IAT 填合成地址 0x00010000\|idx | [pe_loader.c](../../CODE/UTSM/pe/pe_loader.c) | ⬜ |
| x86emu32 拦截 CALL 合成地址 | [x86emu32.c](../../CODE/UTSM/pe/x86emu32.c) | ⬜ |
## 测试程序源码
### hello64.c (PE32+)
```c
#include <windows.h>
int main(void) {
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "Hello from PE32+!\r\n", 19, NULL, NULL);
return 0;
}
```
编译:`x86_64-w64-mingw32-gcc -o hello64.exe hello64.c` 或 `cl /Fe:hello64.exe hello64.c`
### hello32.c (PE32)
```c
#include <windows.h>
int main(void) {
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "Hello from PE32!\r\n", 18, NULL, NULL);
return 0;
}
```
编译:`i686-w64-mingw32-gcc -o hello32.exe hello32.c -Wl,--image-base=0x00400000`
### Fallback: Python 生成器
若无 MinGW/MSVC,使用 [CODE/tools/pe-samples/gen_pe.py](../../CODE/tools/pe-samples/gen_pe.py) 生成最小 PE 程序。
## 已知限制
- pe_shim 实现的 Win32 API 子集有限,测试程序仅使用 WriteFile + ExitProcess
- x86emu32 指令覆盖率参见 [x86emu32-coverage.md](x86emu32-coverage.md)
- TLS / IFUNC / lazy binding 不支持(DKM ABI 约束)
@@ -0,0 +1,88 @@
# 性能基线测量
> 对应计划 Phase C5:基于 TSC 的关键性能指标测量
## 状态: ⬜ PENDING
## 测量方法
所有指标基于 TSC(Time Stamp Counter):
```c
static inline u64 rdtsc(void) {
u32 lo, hi;
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
return ((u64)hi << 32) | lo;
}
```
TSC 频率需先校准(PIT 100ms busy-wait 测量):
```c
u64 tsc_freq; // Hz
u64 calibrate_tsc(void) {
u64 start = rdtsc();
pit_busy_wait(100); // 100ms
u64 end = rdtsc();
return (end - start) * 10; // ×10 得到 Hz
}
```
时间换算:`ms = (tsc_diff * 1000) / tsc_freq`
## 基线指标
| # | 指标 | 测量位置 | 基线目标 | 实测 | 状态 |
|---|---|---|---|---|---|
| P1 | UTSM 启动到 DSK SELFTEST | UTSM entry → DSK selftest pass | < 500ms (QEMU) | | ⬜ |
| P2 | DSK 加载 shell.elf 时间 | FAT32 read + PIE load 包围 | < 200ms | | ⬜ |
| P3 | DSK 加载 desktop.elf 时间 | 同上 | < 200ms | | ⬜ |
| P4 | shell `ping 10.0.2.2` RTT | echo request → reply | < 10ms (user-net) | | ⬜ |
| P5 | shell `linux ls` 完整 RTT | IPC exec round-trip | < 100ms (park-and-resume) | | ⬜ |
| P6 | shell `run PING.ELF` 加载时间 | FAT32 read + PIE load | < 150ms | | ⬜ |
| P7 | desktop 窗口拖动帧率 | 帧计数/TSC | 30+ FPS | | ⬜ |
| P8 | `pe HELLO64.EXE` 加载+执行 | pe_service_run 包围 | < 50ms | | ⬜ |
| P9 | `pe HELLO32.EXE` 加载+执行 | x86emu32 解释 | < 200ms | | ⬜ |
| P10 | UTSM VMM self-test | vmm_init → vmm_self_test | < 50ms | | ⬜ |
| P11 | Linux guest 启动到 park | vmlaunch → daemon HLT | < 3s (QEMU WHPX) | | ⬜ |
| P12 | e1000 DHCP 完整耗时 | netman DHCP start → final rc | < 5s | | ⬜ |
## 自动化测量
在 dev_mode run_dev_tests 中追加性能测量代码:
```c
/* 在 run_dev_tests 开头校准 TSC */
u64 tsc_freq = calibrate_tsc();
logl("[shell] TSC freq: <Hz>");
/* 各项测试包围 TSC */
u64 t0 = rdtsc();
/* ... 操作 ... */
u64 t1 = rdtsc();
u64 ms = (t1 - t0) * 1000 / tsc_freq;
logl("[shell] perf: <name> = <ms>ms");
```
输出到串口日志,由 [ISO/run_tests.bat](../../ISO/run_tests.bat) 收集汇总。
## 性能回归检测
```powershell
# 比较两次测试结果
$prev = Get-Content ISO/logs/perf-baseline-prev.json | ConvertFrom-Json
$curr = Get-Content ISO/logs/perf-baseline-curr.json | ConvertFrom-Json
foreach ($m in $curr.metrics) {
$p = $prev.metrics | Where-Object name -eq $m.name
if ($p -and $m.ms -gt $p.ms * 1.5) {
Write-Host "[REGRESSION] $($m.name): $($p.ms)ms -> $($m.ms)ms (>50%)"
}
}
```
## 已知限制
- QEMU 性能数据不等于真机,仅作回归参考
- WHPX vs TCG 性能差异巨大,必须固定加速方案
- 多次测量取中位数,避免单次抖动
+76
View File
@@ -0,0 +1,76 @@
# 用户态程序功能矩阵
> 对应计划 Phase C4:FirstInit/login/desktop/shell/cmd + 5 个工具应用
## 状态: ⬜ PENDING
## 程序矩阵
| # | 程序 | ELF 路径 | 入口 | 关键命令/功能 | 验证点 | 状态 | Bug# |
|---|---|---|---|---|---|---|---|
| 1 | FirstInit | `system/user/use/FirstInit.elf` | 首启触发 | 计算机名/用户名/密码输入、空字段红字、网络配置 | SHA256 密码、user.conf 写入缓冲 | ⬜ | |
| 2 | login | `system/user/use/login.elf` | 次启触发 | 用户选择、密码输入、错误重试 | USER.CONF 解密、密码匹配 | ⬜ | |
| 3 | desktop | `system/deshab64/desktop.elf` | login 后 | 双击图标、窗口拖动、任务栏、内建 bash | 6 个工具启动、鼠标光标 | ⬜ | |
| 4 | shell | `system/deshab64/shell.elf` | desktop Terminal | ls/cat/cp/mv/rm/echo>/ping/curl/run/linux | dev_mode 自动测试全绿 | ⬜ | |
| 5 | cmd | `system/deshab64/cmd.elf` | desktop CMD | dir/type/copy/del + `pe <NAME.EXE>` | PE 兼容层调用 | ⬜ | |
| 6 | netman | `system/deshab64/network/netman.elf` | DSK 调度 | 读 conf.conf、应用网络配置 | DHCP/静态 IP | ⬜ | |
| 7 | mouseInit | `system/deshab64/mouse/mouseInit.elf` | DSK 调度 | 安全 stub | 不阻塞启动 | ⬜ | |
| 8 | editor | `system/deshab64/tools/editor.elf` | desktop 双击 | 文件打开/编辑/保存 | FAT32 写盘 | ⬜ | |
| 9 | fileman | `system/deshab64/tools/fileman.elf` | desktop 双击 | 浏览/打开/复制 | 目录遍历 | ⬜ | |
| 10 | browser | `system/deshab64/tools/browser.elf` | desktop 双击 | URL 输入/HTTP GET | net_stack 协议栈 | ⬜ | |
| 11 | curl | `system/deshab64/tools/curl.elf` | desktop 双击 | `curl http://...` | HTTP GET | ⬜ | |
| 12 | ping | `system/deshab64/tools/ping.elf` | desktop 双击 | `ping <ip>` | ICMP echo | ⬜ | |
## 启动链路
```
首启: utsm → DSK → mouseInit → netman → FirstInit → desktop
次启: utsm → DSK → login → desktop
dev_mode: utsm → DSK → shell(dev_tests) → Esc → login → desktop
desktop → 双击 Terminal → shell.elf
desktop → 双击 CMD → cmd.elf
shell → run FILEMAN.ELF → fileman.elf → Esc 返回 shell
shell → run BROWSER.ELF → browser.elf
shell → run EDITOR.ELF → editor.elf
shell → run PING.ELF → ping.elf
shell → run CURL.ELF → curl.elf
```
## 详细测试用例
### shell 命令测试
| 命令 | 参数 | 预期 | 状态 |
|---|---|---|---|
| `ls` | (无) | 列出根目录文件(DESHAB.ELF, SHELL.ELF 等) | ⬜ |
| `pwd` | (无) | `/` | ⬜ |
| `cat` | `README.TXT` | 显示文件内容 | ⬜ |
| `cp` | `a b` | 复制成功 | ⬜ |
| `mv` | `a b` | 移动成功 | ⬜ |
| `rm` | `a` | 删除成功 | ⬜ |
| `echo>` | `text > file` | 写入文件 | ⬜ |
| `ping` | `10.0.2.2` | 4/4 reply | ⬜ |
| `curl` | `http://10.0.2.2:8000/` | HTTP 200 + body | ⬜ |
| `run` | `PING.ELF` | 加载并执行 ping | ⬜ |
| `linux` | (无) | 显示兼容层状态 | ⬜ |
| `linux` | `ls` | 输出 initramfs 内容 | ⬜ |
| `help` | (无) | 显示命令列表 | ⬜ |
| `ver`/`version` | (无) | 显示版本 | ⬜ |
### desktop UI 测试
| 操作 | 预期 | 状态 |
|---|---|---|
| 双击 Terminal 图标 | 打开 shell 窗口 | ⬜ |
| 双击 CMD 图标 | 打开 cmd 窗口 | ⬜ |
| 双击 Editor 图标 | 打开 editor | ⬜ |
| 双击 File Manager 图标 | 打开 fileman | ⬜ |
| 双击 Browser 图标 | 打开 browser | ⬜ |
| 鼠标移动 | 光标跟随,无闪烁 | ⬜ |
| 窗口拖动 | 流畅,无撕裂 | ⬜ |
| 任务栏点击 | 窗口切换 | ⬜ |
## 已知问题
- fileman.elf 之前触发过 QEMU 退出(访问未支持 boot context 字段),需观察是否复现
- 真实 TTF 字体未运行时光栅化,使用预渲染位图(已知设计选择,非 bug)
+86
View File
@@ -0,0 +1,86 @@
# x86emu32 指令覆盖率测试
> 对应计划 Phase B3:枚举 x86emu32.c 已实现指令,验证覆盖率
## 状态: ⬜ PENDING
## 已实现指令清单
> 待根据 [x86emu32.c](../../CODE/UTSM/pe/x86emu32.c) 实际代码枚举填充
### 数据传送
| 指令 | 操作码 | 测试程序 | 预期 | 状态 |
|---|---|---|---|---|
| MOV r32, imm32 | B8+rd | `mov eax, 0x12345678` | eax=0x12345678 | ⬜ |
| MOV r32, r/m32 | 8B /r | `mov eax, ebx` | eax=ebx | ⬜ |
| MOV r/m32, r32 | 89 /r | `mov [esi], eax` | [esi]=eax | ⬜ |
| PUSH r32 | 50+rd | `push eax` | [esp]=eax, esp-=4 | ⬜ |
| POP r32 | 58+rd | `pop eax` | eax=[esp], esp+=4 | ⬜ |
### 算术运算
| 指令 | 操作码 | 测试程序 | 预期 | 状态 |
|---|---|---|---|---|
| ADD r32, r/m32 | 03 /r | `add eax, ebx` | eax=eax+ebx | ⬜ |
| SUB r32, r/m32 | 2B /r | `sub eax, ebx` | eax=eax-ebx | ⬜ |
| INC r32 | FF /0 | `inc eax` | eax=eax+1 | ⬜ |
| DEC r32 | FF /1 | `dec eax` | eax=eax-1 | ⬜ |
| MUL r/m32 | F7 /4 | `mul ebx` | edx:eax=eax*ebx | ⬜ |
| DIV r/m32 | F7 /6 | `div ebx` | eax=edx:eax/ebx | ⬜ |
### 逻辑运算
| 指令 | 操作码 | 测试程序 | 预期 | 状态 |
|---|---|---|---|---|
| AND r32, r/m32 | 23 /r | `and eax, ebx` | eax=eax&ebx | ⬜ |
| OR r32, r/m32 | 0B /r | `or eax, ebx` | eax=eax\|ebx | ⬜ |
| XOR r32, r/m32 | 33 /r | `xor eax, ebx` | eax=eax^ebx | ⬜ |
| NOT r/m32 | F7 /2 | `not eax` | eax=~eax | ⬜ |
### 控制流
| 指令 | 操作码 | 测试程序 | 预期 | 状态 |
|---|---|---|---|---|
| JMP rel32 | E9 cw/cd | `jmp label` | rip=label | ⬜ |
| JMP r/m32 | FF /4 | `jmp eax` | rip=eax | ⬜ |
| CALL rel32 | E8 cd | `call func` | push rip, rip=func | ⬜ |
| RET | C3 | `ret` | pop rip | ⬜ |
| Jcc rel32 | 0F 8x cd | `jz label` | 条件跳转 | ⬜ |
### 字符串操作
| 指令 | 操作码 | 测试程序 | 预期 | 状态 |
|---|---|---|---|---|
| MOVSB | A4 | `movsb` | [edi]=[esi], inc/dec | ⬜ |
| STOSB | AA | `stosb` | [edi]=al, inc/dec | ⬜ |
| REP MOVSB | F3 A4 | `rep movsb` | 重复 ecx 次 | ⬜ |
| REP STOSB | F3 AA | `rep stosb` | 重复 ecx 次 | ⬜ |
### 堆栈与控制
| 指令 | 操作码 | 测试程序 | 预期 | 状态 |
|---|---|---|---|---|
| ENTER imm16, imm8 | C8 iw ib | `enter 8, 0` | 建立栈帧 | ⬜ |
| LEAVE | C9 | `leave` | 释放栈帧 | ⬜ |
| NOP | 90 | `nop` | 无操作 | ⬜ |
| INT3 | CC | `int3` | 触发断点 | ⬜ |
## 测试 PE 程序
每个指令类别构造一个最小 PE32 测试程序,在 [CODE/tools/pe-samples/](../../CODE/tools/pe-samples/) 下:
- `test_arith.exe`:算术运算
- `test_logic.exe`:逻辑运算
- `test_control.exe`:控制流
- `test_string.exe`:字符串操作
每个测试程序通过 WriteFile 输出结果到 cmd.elf,与预期对比。
## 覆盖率统计
```
已测试指令数 / 已实现指令数 = 覆盖率
```
目标:核心指令(MOV/ADD/SUB/CMP/JMP/CALL/RET/PUSH/POP)覆盖率 100%。
+627
View File
@@ -0,0 +1,627 @@
# Deshab 驱动模块 ABI 设计
本文记录 Deshab 内核启动驱动模块系统的 ABI、manifest、ELF loader、加载状态机和 stage0/stage1 boot module 方案。
---
## 1. 总体定义
驱动模块系统命名:
```text
DKM = Deshab Kernel Module
DSM = Driver Startup Manager
```
当前规则:
```text
驱动目录:SYSTEM/driver
驱动清单:SYSTEM/driver/manifest.json
驱动格式:ELF64 .drv
加载模式:module loading
启动顺序:staged loading
内存模型:UTSM
```
---
## 2. driver_desc ABI
每个驱动必须导出三个符号:
```text
driver_desc
driver_init
driver_exit
```
### 2.1 driver_desc
```c
#define DKM_DRIVER_MAGIC 0x444B4D31u /* "DKM1" */
#define DKM_ABI_VERSION 1
struct dkm_driver_desc {
uint32_t magic;
uint16_t abi_version;
uint16_t desc_size;
const char *name;
const char *version;
const char *vendor;
uint32_t driver_class;
uint32_t stage;
uint32_t flags;
uint32_t priority;
const char *const *depends;
uint32_t depends_count;
const char *const *provides;
uint32_t provides_count;
uint64_t min_kernel_abi;
uint64_t feature_bits;
uint64_t reserved0;
uint64_t reserved1;
};
```
### 2.2 driver_class
```text
DKM_CLASS_PLATFORM
DKM_CLASS_BUS
DKM_CLASS_INTERRUPT
DKM_CLASS_TIMER
DKM_CLASS_CONSOLE
DKM_CLASS_STORAGE
DKM_CLASS_FS
DKM_CLASS_NET
DKM_CLASS_INPUT
DKM_CLASS_GPU
DKM_CLASS_MISC
```
### 2.3 flags
```text
DKM_F_REQUIRED
当前 stage 中失败则进入 DRR recovery 或 panic。
DKM_F_BOOT_MODULE
可由 bootloader 预加载。
DKM_F_NO_UNLOAD
不允许卸载。
DKM_F_STRONG_RECOVERY
驱动 data 段使用 UTSM 强恢复策略。
DKM_F_DMA_REQUIRED
驱动需要 DMA API。
DKM_F_EARLY_LOG
驱动 init 期间允许使用 early log。
```
### 2.4 driver_init / driver_exit
```c
typedef int (*dkm_driver_init_fn)(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle);
typedef int (*dkm_driver_exit_fn)(struct dkm_driver_handle *handle);
```
约定:
```text
driver_init 返回 0 表示成功。
driver_init 返回负数表示失败。
driver_exit 只用于非 NO_UNLOAD 驱动。
required 驱动 init 失败会触发 DRR recovery 或 panic。
optional 驱动 init 失败会被标记为 FAILED。
```
---
## 3. kernel_api ABI
驱动不直接依赖任意内核符号,默认通过 `dkm_kernel_api` 调用内核服务。
### 3.1 API 总结构
```c
#define DKM_KERNEL_API_VERSION 1
struct dkm_kernel_api {
uint32_t version;
uint32_t size;
uint64_t feature_bits;
const struct dkm_log_api *log;
const struct dkm_mem_api *mem;
const struct dkm_utsm_api *utsm;
const struct dkm_irq_api *irq;
const struct dkm_pci_api *pci;
const struct dkm_dma_api *dma;
const struct dkm_vfs_api *vfs;
const struct dkm_net_api *net;
const struct dkm_timer_api *timer;
const struct dkm_drr_api *drr;
};
```
### 3.2 log API
```c
struct dkm_log_api {
void (*info)(const char *fmt, ...);
void (*warn)(const char *fmt, ...);
void (*error)(const char *fmt, ...);
void (*panic)(const char *fmt, ...);
};
```
### 3.3 memory API
```c
struct dkm_mem_api {
void *(*alloc)(uint64_t size, uint32_t flags);
void (*free)(void *ptr);
void *(*alloc_pages)(uint32_t order, uint32_t flags);
void (*free_pages)(void *ptr, uint32_t order);
void *(*mmio_map)(uint64_t phys, uint64_t size, uint32_t flags);
void (*mmio_unmap)(void *virt, uint64_t size);
};
```
### 3.4 UTSM API
```c
struct dkm_utsm_api {
int (*create_segment)(uint64_t size, uint32_t flags, struct utsm_capability *out);
int (*read)(struct utsm_capability cap, uint64_t off, void *dst, uint64_t len);
int (*write)(struct utsm_capability cap, uint64_t off, const void *src, uint64_t len);
int (*pin)(struct utsm_capability cap, uint64_t off, uint64_t len, void **window);
int (*unpin)(void *window, uint32_t flags);
};
```
### 3.5 IRQ API
```c
struct dkm_irq_api {
int (*register_irq)(uint32_t vector, int (*handler)(void *ctx), void *ctx, uint32_t flags);
int (*unregister_irq)(uint32_t vector);
void (*ack)(uint32_t vector);
};
```
### 3.6 PCI API
```c
struct dkm_pci_api {
int (*scan)(int (*cb)(const struct pci_device *dev, void *ctx), void *ctx);
int (*enable_device)(const struct pci_device *dev);
uint64_t (*bar_phys)(const struct pci_device *dev, uint32_t bar);
uint64_t (*bar_size)(const struct pci_device *dev, uint32_t bar);
};
```
### 3.7 DMA API
```c
struct dkm_dma_api {
int (*alloc)(uint64_t size, uint32_t flags, struct dkm_dma_buffer *out);
void (*free)(struct dkm_dma_buffer *buf);
int (*sync_for_device)(struct dkm_dma_buffer *buf);
int (*sync_for_cpu)(struct dkm_dma_buffer *buf);
};
```
### 3.8 VFS / NET / TIMER / DRR API
第一版只定义边界:
```text
vfs: register_fs / mount / open / read / write / close
net: register_netdev / submit_tx / poll_rx
timer: sleep_ns / call_later / monotonic_ns
drr: register_recovery_ops / report_fault / mark_critical
```
详细结构后续随对应子系统实现细化。
---
## 4. ELF Loader 支持的 relocation
第一版仅支持 x86_64 ELF64 小型内核模型。
### 4.1 必须支持
```text
R_X86_64_64
绝对 64-bit 地址重定位。
R_X86_64_RELATIVE
base + addend。
R_X86_64_GLOB_DAT
GOT 符号地址。
R_X86_64_JUMP_SLOT
PLT 函数地址。
```
### 4.2 建议支持
```text
R_X86_64_PC32
32-bit PC-relative 调用。
R_X86_64_PLT32
PLT-relative 调用。
R_X86_64_32 / R_X86_64_32S
仅允许确认地址范围安全时使用。
```
### 4.3 第一版禁止
```text
TLS relocation
IFUNC
lazy binding
外部动态库依赖
用户态 libc 依赖
异常展开表强依赖
```
### 4.4 加载流程
```text
DKM_ELF_LOAD(path_or_boot_module)
1. 读取 ELF header。
2. 校验 ELFCLASS64 / EM_X86_64 / endian / ABI。
3. 读取 program headers 或 section headers。
4. 计算模块内存大小和对齐。
5. 通过 UTSM 创建 code/data 段。
6. 加载 PT_LOAD 或 SHF_ALLOC section。
7. 清零 .bss。
8. 解析 symbol table。
9. 解析 relocation section。
10. 将内核导出符号或 kernel_api 符号填入。
11. 执行 relocation。
12. 查找 driver_desc / driver_init / driver_exit。
13. 设置 code 段 READ|EXEC|SEALED。
14. 设置 data 段 READ|WRITE|STRONG_RECOVERY。
15. 返回 module handle。
```
---
## 5. manifest.json 格式
当前使用 JSON,不再使用 ini 格式的 manifest.drv。
路径:
```text
SYSTEM/driver/manifest.json
```
### 5.1 顶层字段
```json
{
"schema": "deshab.driver.manifest.v1",
"root": "SYSTEM",
"driverRoot": "SYSTEM/driver",
"format": "elf64-drv",
"abi": {},
"policy": {},
"stages": []
}
```
### 5.2 abi 字段
```json
{
"name": "DKM",
"version": 1,
"entry": "driver_init",
"exit": "driver_exit",
"descriptor": "driver_desc"
}
```
### 5.3 policy 字段
```json
{
"loadModel": "module",
"loadOrder": "staged",
"requiredFailure": "drr_recovery_or_panic",
"optionalFailure": "mark_failed_and_continue",
"memoryModel": "UTSM",
"codeSegment": "READ|EXEC|SEALED",
"dataSegment": "READ|WRITE|STRONG_RECOVERY",
"dmaSegment": "DMA|PINNED"
}
```
### 5.4 stage 字段
```json
{
"id": 0,
"name": "platform",
"required": true,
"description": "平台发现、中断、总线、基础计时。",
"drivers": []
}
```
### 5.5 driver 字段
```json
{
"name": "pci",
"path": "driver/bus/pci.drv",
"class": "bus",
"required": true,
"depends": ["irq"],
"provides": ["pci"]
}
```
### 5.6 路径规则
```text
manifest 中的 path 相对 SYSTEM 根目录。
SYSTEM/driver/manifest.json 内的 driver/bus/pci.drv 指向 SYSTEM/driver/bus/pci.drv。
stage0/stage1 驱动允许来自 boot module,不要求文件系统已挂载。
stage2/stage3 驱动默认从 SYSTEM/driver 加载。
```
---
## 6. 驱动加载状态机
```text
DISCOVERED
-> QUEUED
-> DEP_WAIT
-> LOADING
-> ELF_CHECKED
-> MEMORY_ALLOCATED
-> RELOCATED
-> ABI_CHECKED
-> INITING
-> ACTIVE
```
失败状态:
```text
FAILED_ELF
FAILED_RELOCATION
FAILED_DEPENDENCY
FAILED_ABI
FAILED_INIT
FAILED_REQUIRED
```
卸载状态:
```text
ACTIVE
-> QUIESCING
-> EXITING
-> UNLOADING
-> UNLOADED
```
恢复状态:
```text
ACTIVE
-> SUSPENDED_BY_DRR
-> RECOVERING
-> REINITING
-> ACTIVE
```
### 6.1 加载策略
```text
1. DSM 读取 manifest.json。
2. 按 stage 顺序加载。
3. 每个 stage 内按 priority 排序。
4. 检查 depends 是否已由 provides 满足。
5. 未满足依赖的驱动进入 DEP_WAIT。
6. 每轮加载成功后更新 provides set。
7. 一轮后仍 DEP_WAIT 的 required 驱动进入 FAILED_REQUIRED。
8. optional 驱动失败只记录状态。
```
### 6.2 required 失败策略
```text
stage0/stage1 required 失败:
-> DRR report_fault
-> 尝试 boot fallback
-> 不可恢复则 panic / system rollback
stage2 required 失败:
-> DRR recovery
-> fallback 到 bootfs 或只读模式
stage3 optional 失败:
-> mark FAILED
-> continue boot
```
---
## 7. stage0/stage1 boot module 方案
问题:
```text
stage0/stage1 负责 timer、irq、pci、bootfs、block 等早期能力。
此时 VFS 和普通文件系统可能还没准备好。
所以不能完全依赖 SYSTEM/driver 的普通文件遍历。
```
### 7.1 Bootloader 预加载
bootloader 负责把关键文件作为 boot module 交给内核:
```text
SYSTEM/driver/manifest.json
SYSTEM/driver/platform/timer.drv
SYSTEM/driver/platform/apic.drv
SYSTEM/driver/bus/pci.drv
SYSTEM/driver/fs/bootfs.drv
```
可选:
```text
SYSTEM/driver/console/console_fb.drv
SYSTEM/driver/block/ahci.drv
SYSTEM/driver/block/nvme.drv
```
### 7.2 Boot Module 表
内核早期接收 boot module 表:
```c
struct dkm_boot_module {
const char *path;
void *base;
uint64_t size;
uint32_t type;
uint32_t flags;
uint64_t checksum;
};
struct dkm_boot_module_table {
uint32_t count;
struct dkm_boot_module modules[];
};
```
### 7.3 查找规则
```text
DSM_LOAD_DRIVER(path)
1. 如果 path 在 boot module table 中,直接从内存加载。
2. 否则如果 VFS 已可用,从 SYSTEM/path 加载。
3. 否则返回 BOOT_MODULE_NOT_FOUND。
```
### 7.4 stage0/stage1 限制
```text
1. 不依赖普通 VFS。
2. 不依赖普通 heap。
3. 优先使用 early allocator 或 DRR emergency-safe allocator。
4. 日志使用 early log。
5. 不启动复杂后台任务。
6. 只注册最小服务能力。
```
### 7.5 stage 切换点
```text
stage0 完成:
timer / irq / pci 基础能力可用。
stage1 完成:
bootfs 或 block + fs 基础能力可用。
stage2 开始:
VFS 可用,可以从 SYSTEM/driver 正常读取更多驱动。
stage3 开始:
普通调度、网络、输入、图形等可异步加载。
```
---
## 8. 与 UTSM / DRR 的关系
### 8.1 UTSM 内存策略
```text
驱动 text:READ | EXEC | SEALED
驱动 rodata:READ | SEALED
驱动 data:READ | WRITE | STRONG_RECOVERY
驱动 bss:READ | WRITE | STRONG_RECOVERY
驱动 DMA:DMA | PINNED,必要时 CIPHERTEXT_DMA 或 NO_ENCRYPT
```
### 8.2 DRR 记录项
DRR 为每个驱动记录:
```text
driver name
stage
state
module memory range
provided services
recovery ops
init result
last fault
```
### 8.3 驱动 recovery ops
驱动可注册:
```c
struct dkm_driver_recovery_ops {
int (*quiesce)(void *ctx);
int (*reset)(void *ctx);
int (*reinit)(void *ctx);
int (*dump_state)(void *ctx, void *buf, uint64_t len);
};
```
DRR recovery 顺序:
```text
quiesce -> UTSM rollback -> device reset -> driver reinit -> resume
```
---
## 9. 第一版定稿
第一版驱动系统确定:
```text
1. SYSTEM 是 IMG 内系统根目录。
2. 驱动清单为 SYSTEM/driver/manifest.json。
3. 驱动文件为 ELF64 .drv。
4. 驱动必须导出 driver_desc / driver_init / driver_exit。
5. 驱动通过 dkm_kernel_api 调用内核服务。
6. ELF loader 第一版支持常用 x86_64 relocation。
7. 驱动按 stage 分阶段加载。
8. stage0/stage1 支持 bootloader 预加载 boot module。
9. stage2/stage3 从 SYSTEM/driver 加载。
10. 驱动内存纳入 UTSM,驱动恢复纳入 DRR。
```