Record networking and DMA development progress
Add the current OS source tree, build scripts, system image layout, and development notes covering DMA page allocation, e1000 bring-up, net API dispatch, and DHCP work in progress.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
CC := clang
|
||||
LD := ld.lld
|
||||
OBJCOPY := llvm-objcopy
|
||||
|
||||
ROOT := ../..
|
||||
OUT := $(ROOT)/SYSTEM/boot/utsm.elf
|
||||
|
||||
CFLAGS := -target x86_64-unknown-none -std=c11 -ffreestanding -fno-builtin -fno-stack-protector -fno-pic -fno-pie -mcmodel=kernel -mno-red-zone -mno-sse -mno-sse2 -mno-mmx -msoft-float -m64 -Wall -Wextra -Iinclude -O2
|
||||
ASFLAGS := -target x86_64-unknown-none -ffreestanding -fno-pic -fno-pie -mcmodel=kernel -mno-red-zone -mno-sse -mno-sse2 -mno-mmx -msoft-float -m64 -Iinclude
|
||||
LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -T linker.ld
|
||||
|
||||
C_SOURCES := $(wildcard arch/x86_64/*.c kernel/*.c runtime/*.c mm/*.c core/*.c crypto/*.c pckc/*.c utrw/*.c drr/*.c dkm/*.c test/*.c)
|
||||
S_SOURCES := $(wildcard arch/x86_64/*.S)
|
||||
OBJECTS := $(C_SOURCES:.c=.o) $(S_SOURCES:.S=.o)
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(OUT)
|
||||
|
||||
$(OUT): $(OBJECTS) linker.ld
|
||||
@if not exist "$(ROOT)\SYSTEM\boot" mkdir "$(ROOT)\SYSTEM\boot"
|
||||
$(LD) $(LDFLAGS) -o $@ $(OBJECTS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(ASFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
powershell -NoProfile -Command "Get-ChildItem -Path . -Recurse -Filter *.o | Remove-Item -Force; if (Test-Path '$(OUT)') { Remove-Item '$(OUT)' -Force }"
|
||||
@@ -0,0 +1,935 @@
|
||||
// 编译到 SYSTEM/boot/utsm.elf
|
||||
|
||||
# UTSM 内核模块设计
|
||||
|
||||
UTSM 是当前内核架构中的封缄内存模块。
|
||||
|
||||
```text
|
||||
UTSM = UUID-Tuned Sealed Memory
|
||||
中文名:UUID 调谐封缄内存
|
||||
```
|
||||
|
||||
UTSM 的目标是在单地址空间 Ring0 高性能内核中提供一种轻量内存语义:
|
||||
|
||||
```text
|
||||
所有普通内存可以被直接读取,但直接读取到的是密文。
|
||||
真正有效的明文读写必须经过 UTSM 读写器。
|
||||
UUID 作为进程和内存段的调谐因子。
|
||||
DRR 负责 root key、checkpoint、recovery log 和回滚。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. 所属总架构
|
||||
|
||||
```text
|
||||
SAS-R0-PCQ
|
||||
单地址空间 Ring0 任务模型
|
||||
Per-CPU O(1) 位图调度器
|
||||
|
||||
DRR
|
||||
Dedicated Recovery Root
|
||||
看门狗 / checkpoint / recovery log / A-B 回滚
|
||||
|
||||
UTSM
|
||||
UUID-Tuned Sealed Memory
|
||||
UUID 调谐封缄内存
|
||||
|
||||
UTRW
|
||||
UTSM Tagged Reader/Writer
|
||||
UTSM 带标记读写器
|
||||
|
||||
DMP
|
||||
Descriptor Meta Page
|
||||
段描述符元页
|
||||
|
||||
PCKC
|
||||
Per-CPU Key Cache
|
||||
每 CPU 密钥缓存
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. UTSM 核心规则
|
||||
|
||||
```text
|
||||
1. 数据区只存连续密文。
|
||||
2. UUID 不插入数据区。
|
||||
3. UUID 使用 128-bit 二进制格式。
|
||||
4. 每个加密段有独立 DMP。
|
||||
5. 每个任务有 process_uuid 和 capability table。
|
||||
6. 读写明文必须经过 UTRW。
|
||||
7. 直接读取 cipher_base 只得到密文。
|
||||
8. 直接写入 cipher_base 会破坏段一致性,段可被标记为 POISONED。
|
||||
9. DRR 保存 root key、checkpoint、recovery log 和恢复状态。
|
||||
10. 调度器只加载 crypto context,不扫描段,不破坏 O(1) 调度。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 内存布局
|
||||
|
||||
每个 UTSM 段由 DMP 和密文数据区组成。
|
||||
|
||||
```text
|
||||
+-------------------------------+
|
||||
| DMP: Descriptor Meta Page |
|
||||
| 段描述符元页 |
|
||||
+-------------------------------+
|
||||
| Cipher Data Page 0 |
|
||||
+-------------------------------+
|
||||
| Cipher Data Page 1 |
|
||||
+-------------------------------+
|
||||
| Cipher Data Page 2 |
|
||||
+-------------------------------+
|
||||
| ... |
|
||||
+-------------------------------+
|
||||
```
|
||||
|
||||
全局区域:
|
||||
|
||||
```text
|
||||
+--------------------------------------------------+
|
||||
| Normal Encrypted Segment Region |
|
||||
| 普通加密段数据区 |
|
||||
+--------------------------------------------------+
|
||||
| DMP Pool |
|
||||
| 段描述符元页池 |
|
||||
+--------------------------------------------------+
|
||||
| Segment Table |
|
||||
| 全局段表 |
|
||||
+--------------------------------------------------+
|
||||
| PCKC Area |
|
||||
| Per-CPU Key Cache 区 |
|
||||
+--------------------------------------------------+
|
||||
| DRR Reserved Region |
|
||||
| root key / checkpoint / recovery log |
|
||||
+--------------------------------------------------+
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 基础类型
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
uint64_t hi;
|
||||
uint64_t lo;
|
||||
} uuid128_t;
|
||||
```
|
||||
|
||||
UUID 不转十进制字符串,原因:
|
||||
|
||||
```text
|
||||
16 字节固定长度
|
||||
比较快
|
||||
cache 友好
|
||||
适合 KDF
|
||||
适合 SIMD
|
||||
避免十进制解析和孔洞布局
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 进程加密上下文
|
||||
|
||||
```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;
|
||||
};
|
||||
```
|
||||
|
||||
字段含义:
|
||||
|
||||
```text
|
||||
process_uuid
|
||||
创建任务时生成的进程 UUID。
|
||||
|
||||
crypto_epoch
|
||||
当前密钥版本,用于重加密、回滚和 crypto erase。
|
||||
|
||||
recovery_generation
|
||||
当前 DRR checkpoint 版本。
|
||||
|
||||
capability_table_slot
|
||||
该任务 capability table 的位置。
|
||||
|
||||
capability_count
|
||||
该任务拥有的段能力数量。
|
||||
|
||||
flags
|
||||
PWC、DMA、强恢复等策略标志。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 加密段描述符
|
||||
|
||||
```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;
|
||||
};
|
||||
```
|
||||
|
||||
段状态:
|
||||
|
||||
```text
|
||||
FREE
|
||||
ACTIVE
|
||||
CHECKPOINTING
|
||||
SEALED
|
||||
RECOVERING
|
||||
POISONED
|
||||
DESTROYED
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. DMP 段描述符元页
|
||||
|
||||
DMP 是热路径加速结构,替代“UUID 数字位置表”。
|
||||
|
||||
```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;
|
||||
};
|
||||
```
|
||||
|
||||
DMP 用于:
|
||||
|
||||
```text
|
||||
O(1) 段定位
|
||||
快速边界检查
|
||||
tweak 生成
|
||||
Dirty Bitmap 定位
|
||||
MAC Table 定位
|
||||
checkpoint
|
||||
recovery
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Capability
|
||||
|
||||
任务访问段时使用 capability,而不是裸 UUID。
|
||||
|
||||
```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;
|
||||
};
|
||||
```
|
||||
|
||||
权限:
|
||||
|
||||
```text
|
||||
READ
|
||||
WRITE
|
||||
EXEC
|
||||
SHARE
|
||||
DMA
|
||||
```
|
||||
|
||||
热路径通过:
|
||||
|
||||
```text
|
||||
segment_slot + generation + epoch
|
||||
```
|
||||
|
||||
直接定位并验证段。
|
||||
|
||||
---
|
||||
|
||||
## 9. 加密规则
|
||||
|
||||
UTSM 不使用十进制凯撒和 UUID 孔洞,改为按 cache line 的 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)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 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 等异常处理。
|
||||
```
|
||||
|
||||
### 10.1 读流程
|
||||
|
||||
```text
|
||||
UTRW_READ(cap, offset, len, dst)
|
||||
-> segment_slot 找 desc
|
||||
-> generation 检查
|
||||
-> rights 检查
|
||||
-> epoch 检查
|
||||
-> 边界检查
|
||||
-> PCKC 取 key
|
||||
-> 按 64B line 解密
|
||||
-> 返回明文
|
||||
```
|
||||
|
||||
### 10.2 写流程
|
||||
|
||||
```text
|
||||
UTRW_WRITE(cap, offset, len, src)
|
||||
-> segment_slot 找 desc
|
||||
-> generation 检查
|
||||
-> rights 检查
|
||||
-> epoch 检查
|
||||
-> 边界检查
|
||||
-> PCKC 取 key
|
||||
-> 按 64B line 加密
|
||||
-> 写入 cipher data
|
||||
-> 标记 dirty bitmap
|
||||
-> writer_seq++
|
||||
-> 按策略写 recovery log
|
||||
```
|
||||
|
||||
部分写必须先解密旧 64B line,合并新明文后重新加密整条 line。
|
||||
|
||||
---
|
||||
|
||||
## 11. PCKC 每 CPU 密钥缓存
|
||||
|
||||
```c
|
||||
struct utsm_pckc {
|
||||
uuid128_t current_process_uuid;
|
||||
|
||||
uint32_t hot_segment_slot[8];
|
||||
uint64_t hot_key_epoch[8];
|
||||
|
||||
void *key_schedule[8];
|
||||
|
||||
uint64_t hit_count;
|
||||
uint64_t miss_count;
|
||||
};
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
```text
|
||||
每 CPU 一个 PCKC。
|
||||
调度切换时只加载 next.crypto 指针和 hot_segment_hint。
|
||||
不扫描 capability table。
|
||||
不刷新全部 key。
|
||||
不破坏 PCQ 的 O(1) 调度。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 与 SAS-R0-PCQ 的整合
|
||||
|
||||
任务结构扩展:
|
||||
|
||||
```c
|
||||
struct task {
|
||||
uint64_t tid;
|
||||
uint32_t state;
|
||||
uint32_t priority;
|
||||
|
||||
uint64_t runtime;
|
||||
uint64_t time_slice;
|
||||
|
||||
void *stack_top;
|
||||
void *entry;
|
||||
|
||||
struct context cpu_context;
|
||||
|
||||
uint32_t last_cpu;
|
||||
uint64_t affinity_mask;
|
||||
|
||||
struct utsm_process_context *crypto;
|
||||
struct utsm_capability_table *cap_table;
|
||||
|
||||
uint32_t hot_segment_hint;
|
||||
uint32_t fault_segment_slot;
|
||||
|
||||
uint64_t recovery_generation;
|
||||
uint64_t heartbeat_seq;
|
||||
|
||||
uint32_t flags;
|
||||
|
||||
struct task *prev;
|
||||
struct task *next;
|
||||
};
|
||||
```
|
||||
|
||||
任务状态:
|
||||
|
||||
```text
|
||||
READY
|
||||
RUNNING
|
||||
BLOCKED
|
||||
SLEEPING
|
||||
RECOVERING
|
||||
FAULTED
|
||||
ZOMBIE
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. 任务创建流程
|
||||
|
||||
```text
|
||||
task_create(entry, priority, flags)
|
||||
-> 分配 TCB
|
||||
-> 生成 tid
|
||||
-> 生成 process_uuid
|
||||
-> 创建 utsm_process_context
|
||||
-> 创建 stack segment
|
||||
-> 创建 heap segment
|
||||
-> 创建 ipc segment 可选
|
||||
-> 生成 capability table
|
||||
-> cap[0] = stack
|
||||
-> cap[1] = heap
|
||||
-> 初始化 CPU context
|
||||
-> 通过 UTRW_WRITE 写入 start packet
|
||||
-> hot_segment_hint = stack segment
|
||||
-> state = READY
|
||||
-> enqueue_task(current_cpu)
|
||||
```
|
||||
|
||||
默认 capability:
|
||||
|
||||
```text
|
||||
cap[0] = stack segment, READ | WRITE
|
||||
cap[1] = heap segment, READ | WRITE
|
||||
cap[2] = ipc segment, READ | WRITE | SHARE,可选
|
||||
cap[3] = code segment, READ | EXEC,可选
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. 调度切换流程
|
||||
|
||||
```text
|
||||
schedule()
|
||||
-> old = current
|
||||
-> utsm_switch_out(old)
|
||||
-> next = pick_next_task()
|
||||
-> utsm_switch_in(next)
|
||||
-> context_switch(old, next)
|
||||
```
|
||||
|
||||
`utsm_switch_out` 只做:
|
||||
|
||||
```text
|
||||
标记 PWC dirty flush
|
||||
保存 hot_segment_hint
|
||||
更新 recovery_generation
|
||||
更新 heartbeat
|
||||
```
|
||||
|
||||
`utsm_switch_in` 只做:
|
||||
|
||||
```text
|
||||
设置 PCKC.current_process_uuid
|
||||
加载 next.crypto
|
||||
检查 recovery_generation
|
||||
预热 hot_segment_hint
|
||||
```
|
||||
|
||||
禁止在调度路径中:
|
||||
|
||||
```text
|
||||
扫描所有 segment
|
||||
扫描 capability table
|
||||
计算 MAC
|
||||
写 checkpoint
|
||||
重加密整段
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 15. Checkpoint / Rollback 协议
|
||||
|
||||
### 15.1 Checkpoint 类型
|
||||
|
||||
```text
|
||||
Light Checkpoint
|
||||
保存 segment table、DMP、dirty shard summary、writer_seq、key_epoch、MAC root。
|
||||
|
||||
Dirty Page Checkpoint
|
||||
保存 dirty page 的密文副本、dirty page MAC、dirty shard、segment descriptor。
|
||||
|
||||
Boot Checkpoint
|
||||
保存内核镜像 slot、UTSM root epoch、DRR boot status、启动阶段状态。
|
||||
```
|
||||
|
||||
### 15.2 Dirty Shard 分片
|
||||
|
||||
Dirty Bitmap 不再只是一整块大 bitmap,而是拆成多个 Dirty Shard。
|
||||
|
||||
```c
|
||||
struct utsm_dirty_shard {
|
||||
uint32_t dirty_count;
|
||||
uint32_t shard_id;
|
||||
|
||||
uint64_t page_base;
|
||||
uint64_t page_count;
|
||||
|
||||
uint64_t last_checkpoint_epoch;
|
||||
void *bitmap;
|
||||
};
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
```text
|
||||
1. 每个 shard 管理一段连续页范围。
|
||||
2. UTRW_WRITE 标记 dirty page 时,同时更新 dirty_count。
|
||||
3. checkpoint 时 dirty_count == 0 的 shard 直接跳过。
|
||||
4. checkpoint 只扫描 dirty_count > 0 的 shard。
|
||||
5. 每 CPU 可以维护 dirty shard list,避免全局扫描。
|
||||
```
|
||||
|
||||
复杂度从:
|
||||
|
||||
```text
|
||||
扫描全 dirty bitmap
|
||||
```
|
||||
|
||||
优化为:
|
||||
|
||||
```text
|
||||
O(number_of_dirty_shards + number_of_dirty_pages)
|
||||
```
|
||||
|
||||
### 15.3 A/B Checkpoint Metadata 双槽
|
||||
|
||||
每个 checkpoint metadata 使用双槽。
|
||||
|
||||
```text
|
||||
Checkpoint Metadata Slot A
|
||||
Checkpoint Metadata Slot B
|
||||
```
|
||||
|
||||
提交规则:
|
||||
|
||||
```text
|
||||
当前 active = A
|
||||
新 checkpoint 写 B
|
||||
B 写完 metadata、dirty index、MAC root、CRC
|
||||
flush
|
||||
最后原子切换 active = B
|
||||
旧 A 保留为 fallback
|
||||
```
|
||||
|
||||
恢复规则:
|
||||
|
||||
```text
|
||||
优先读取 active slot
|
||||
如果 active slot CRC 错误或 generation 不完整
|
||||
fallback 到另一个 slot
|
||||
如果两个 slot 都损坏
|
||||
进入 system rollback
|
||||
```
|
||||
|
||||
这样可以避免 checkpoint 写一半崩溃导致旧稳定点也损坏。
|
||||
|
||||
### 15.4 正常 checkpoint 流程
|
||||
|
||||
```text
|
||||
DRR 发起 checkpoint
|
||||
-> checkpoint_generation++
|
||||
-> 选择 inactive metadata slot
|
||||
-> UTSM 遍历 dirty shard list
|
||||
-> 跳过 dirty_count == 0 的 shard
|
||||
-> 对 dirty shard 内的 ACTIVE 段执行 checkpoint
|
||||
-> desc.state = CHECKPOINTING
|
||||
-> 刷出 PWC / per-CPU dirty buffer
|
||||
-> 复制 dirty ciphertext page 到 checkpoint region
|
||||
-> 计算 page MAC
|
||||
-> 写 segment desc snapshot
|
||||
-> 写 DMP snapshot
|
||||
-> 写 dirty shard summary
|
||||
-> 写 checkpoint metadata CRC
|
||||
-> flush checkpoint metadata
|
||||
-> 原子切换 active metadata slot
|
||||
-> CHECKPOINT_COMMIT
|
||||
-> 清 dirty bitmap / dirty_count
|
||||
-> desc.state = ACTIVE
|
||||
```
|
||||
|
||||
### 15.5 rollback 级别
|
||||
|
||||
```text
|
||||
Page Rollback
|
||||
单页损坏,从 checkpoint slot 恢复密文页。
|
||||
|
||||
Segment Rollback
|
||||
整段损坏,恢复 segment desc、DMP、key_epoch、dirty shard、MAC table。
|
||||
|
||||
System Rollback
|
||||
控制面严重损坏,写 crash reason,reboot,由 bootloader 切换 last_good_slot。
|
||||
```
|
||||
|
||||
### 15.6 DRR Emergency Pool
|
||||
|
||||
DRR 启动时必须预留独立紧急内存池。
|
||||
|
||||
```text
|
||||
DRR Emergency Pool
|
||||
emergency pages
|
||||
recovery log buffer
|
||||
checkpoint metadata buffer
|
||||
DRR private stack
|
||||
DRR metadata slab
|
||||
crash buffer
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
```text
|
||||
1. 普通 allocator 永远不能分配 Emergency Pool。
|
||||
2. Emergency Pool 只供 watchdog、checkpoint、rollback、crash dump 使用。
|
||||
3. 普通系统 OOM 不等于 DRR OOM。
|
||||
4. recovery 路径禁止依赖普通堆分配器。
|
||||
5. Emergency Pool 耗尽时直接进入 system rollback。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 16. 启动流程
|
||||
|
||||
### 16.1 Bootloader 阶段
|
||||
|
||||
```text
|
||||
1. 读取 Boot Control Block。
|
||||
2. 校验 BCB CRC。
|
||||
3. 选择 active_slot。
|
||||
4. 如果 active_slot 失败次数超限,切换 last_good_slot。
|
||||
5. 将 SYSTEM 作为打包后 IMG 内的系统根目录。
|
||||
6. 加载 SYSTEM/boot/utsm.elf。
|
||||
7. 加载或暴露 SYSTEM/driver/manifest.json。
|
||||
8. 传入 memory map、BCB 地址、DRR reserved region 信息。
|
||||
```
|
||||
|
||||
### 16.2 DRR 初始化
|
||||
|
||||
```text
|
||||
1. 保留 DRR region。
|
||||
2. 初始化 watchdog。
|
||||
3. 建立 root key 或 root key handle。
|
||||
4. 初始化 recovery log。
|
||||
5. 初始化 checkpoint region。
|
||||
6. 初始化 heartbeat page。
|
||||
7. 初始化 DRR Emergency Pool。
|
||||
8. 初始化 A/B checkpoint metadata slot。
|
||||
```
|
||||
|
||||
### 16.3 UTSM 初始化
|
||||
|
||||
```text
|
||||
1. 接收 DRR root key handle。
|
||||
2. 初始化 global crypto epoch。
|
||||
3. 初始化 segment table。
|
||||
4. 初始化 DMP pool。
|
||||
5. 初始化 PCKC area。
|
||||
6. 初始化 dirty shard pool。
|
||||
7. 初始化 dirty bitmap pool。
|
||||
8. 初始化 MAC table pool。
|
||||
9. 注册 UTRW fast path / slow path。
|
||||
```
|
||||
|
||||
### 16.4 Scheduler 初始化
|
||||
|
||||
```text
|
||||
1. 初始化 per-CPU runqueue。
|
||||
2. 初始化 per-CPU heartbeat。
|
||||
3. 初始化每 CPU PCKC。
|
||||
4. 创建 bootstrap task。
|
||||
5. 创建核心服务 task。
|
||||
6. 将 task 加入 PCQ runqueue。
|
||||
```
|
||||
|
||||
### 16.5 Driver Manifest 加载
|
||||
|
||||
驱动清单位于系统根目录下:
|
||||
|
||||
```text
|
||||
SYSTEM/driver/manifest.json
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
```text
|
||||
1. manifest.json 是启动驱动模块的唯一默认清单。
|
||||
2. 驱动文件使用 ELF64 .drv 格式。
|
||||
3. 驱动按 stage 分阶段加载。
|
||||
4. required=true 的驱动失败时进入 DRR recovery 或 panic。
|
||||
5. required=false 的驱动失败时标记 FAILED 并继续启动。
|
||||
6. stage0/stage1 可由 bootloader 预加载为 boot module。
|
||||
7. stage2/stage3 在文件系统可用后从 SYSTEM/driver 扫描加载。
|
||||
```
|
||||
|
||||
默认阶段:
|
||||
|
||||
```text
|
||||
stage0: platform,timer / apic / acpi / pci
|
||||
stage1: boot,console / block / bootfs
|
||||
stage2: filesystem,vfs / fat32 / devfs
|
||||
stage3: optional,net / input / gpu
|
||||
```
|
||||
|
||||
### 16.6 DKM 驱动 ABI 摘要
|
||||
|
||||
驱动模块系统:
|
||||
|
||||
```text
|
||||
DKM = Deshab Kernel Module
|
||||
DSM = Driver Startup Manager
|
||||
```
|
||||
|
||||
每个 ELF .drv 必须导出:
|
||||
|
||||
```text
|
||||
driver_desc
|
||||
driver_init
|
||||
driver_exit
|
||||
```
|
||||
|
||||
`driver_desc` 至少描述:
|
||||
|
||||
```text
|
||||
magic / abi_version / desc_size
|
||||
name / version / vendor
|
||||
driver_class / stage / flags / priority
|
||||
depends / provides
|
||||
min_kernel_abi / feature_bits
|
||||
```
|
||||
|
||||
驱动入口:
|
||||
|
||||
```c
|
||||
int driver_init(const struct dkm_kernel_api *api, struct dkm_driver_handle *handle);
|
||||
int driver_exit(struct dkm_driver_handle *handle);
|
||||
```
|
||||
|
||||
驱动默认通过 `dkm_kernel_api` 访问内核服务:
|
||||
|
||||
```text
|
||||
log
|
||||
mem
|
||||
utsm
|
||||
irq
|
||||
pci
|
||||
dma
|
||||
vfs
|
||||
net
|
||||
timer
|
||||
drr
|
||||
```
|
||||
|
||||
ELF loader 第一版支持:
|
||||
|
||||
```text
|
||||
必须支持:
|
||||
R_X86_64_64
|
||||
R_X86_64_RELATIVE
|
||||
R_X86_64_GLOB_DAT
|
||||
R_X86_64_JUMP_SLOT
|
||||
|
||||
建议支持:
|
||||
R_X86_64_PC32
|
||||
R_X86_64_PLT32
|
||||
R_X86_64_32 / R_X86_64_32S
|
||||
|
||||
第一版禁止:
|
||||
TLS relocation
|
||||
IFUNC
|
||||
lazy binding
|
||||
外部动态库依赖
|
||||
用户态 libc 依赖
|
||||
```
|
||||
|
||||
驱动加载状态机:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
stage0/stage1 boot module 查找规则:
|
||||
|
||||
```text
|
||||
1. 如果 path 在 boot module table 中,直接从内存加载。
|
||||
2. 否则如果 VFS 已可用,从 SYSTEM/path 加载。
|
||||
3. 否则返回 BOOT_MODULE_NOT_FOUND。
|
||||
```
|
||||
|
||||
完整设计见:
|
||||
|
||||
```text
|
||||
RE/驱动模块ABI设计.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 17. 错误处理
|
||||
|
||||
UTRW 错误状态:
|
||||
|
||||
```text
|
||||
OK
|
||||
KEY_MISS_RETRY
|
||||
STALE_CAPABILITY
|
||||
EPOCH_EXPIRED
|
||||
OUT_OF_BOUNDS
|
||||
ACCESS_DENIED
|
||||
CHECKPOINT_BUSY
|
||||
RECOVERING
|
||||
MAC_FAILED
|
||||
SEGMENT_POISONED
|
||||
CORRUPTED_DESCRIPTOR
|
||||
```
|
||||
|
||||
严重错误处理:
|
||||
|
||||
```text
|
||||
1. 记录 task.fault_segment_slot。
|
||||
2. task.state = FAULTED。
|
||||
3. 从 runqueue 移除。
|
||||
4. 通知 DRR。
|
||||
5. DRR 决定刷新 capability、回滚 segment、kill task 或 system rollback。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 18. UTSM v1 定稿
|
||||
|
||||
```text
|
||||
UTSM v1 包含:
|
||||
二进制 UUID
|
||||
连续密文数据区
|
||||
独立 DMP
|
||||
全局 Segment Table
|
||||
Segment Capability
|
||||
Per-CPU Key Cache
|
||||
UTRW 统一读写器
|
||||
Dirty Shard + Dirty Bitmap
|
||||
MAC Table
|
||||
DRR Emergency Pool
|
||||
A/B Checkpoint Metadata
|
||||
DRR checkpoint / rollback 对接
|
||||
SAS-R0-PCQ task 整合
|
||||
|
||||
加密粒度:
|
||||
64B cache line
|
||||
|
||||
Dirty 粒度:
|
||||
4KB page
|
||||
|
||||
Dirty 分片:
|
||||
Dirty Shard,checkpoint 只扫描 dirty_count > 0 的 shard
|
||||
|
||||
MAC 粒度:
|
||||
4KB page
|
||||
|
||||
Checkpoint 元数据:
|
||||
A/B 双槽,CRC 校验,原子切换 active slot
|
||||
|
||||
大页优化:
|
||||
2MB hugepage 可选
|
||||
```
|
||||
@@ -0,0 +1,21 @@
|
||||
.section .text
|
||||
.global _start
|
||||
.type _start, @function
|
||||
_start:
|
||||
cli
|
||||
cld
|
||||
lea kernel_stack_top(%rip), %rsp
|
||||
andq $-16, %rsp
|
||||
call kernel_main
|
||||
.hang:
|
||||
cli
|
||||
hlt
|
||||
jmp .hang
|
||||
|
||||
.section .bss
|
||||
.align 16
|
||||
.global kernel_stack
|
||||
.global kernel_stack_top
|
||||
kernel_stack:
|
||||
.skip 16384
|
||||
kernel_stack_top:
|
||||
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
void arch_halt_forever(void) {
|
||||
for (;;) {
|
||||
__asm__ volatile ("cli; hlt");
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,222 @@
|
||||
#include <utsm/idt.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/types.h>
|
||||
|
||||
/* IDT gate descriptor (64-bit) */
|
||||
typedef struct __attribute__((packed)) {
|
||||
u16 offset_low;
|
||||
u16 selector;
|
||||
u8 ist;
|
||||
u8 type_attr;
|
||||
u16 offset_mid;
|
||||
u32 offset_high;
|
||||
u32 reserved;
|
||||
} idt_entry;
|
||||
|
||||
/* IDT register */
|
||||
typedef struct __attribute__((packed)) {
|
||||
u16 limit;
|
||||
u64 base;
|
||||
} idt_ptr;
|
||||
|
||||
#define IDT_ENTRIES 256
|
||||
static idt_entry g_idt[IDT_ENTRIES] __attribute__((aligned(16)));
|
||||
|
||||
#define PIC1_CMD 0x20
|
||||
#define PIC1_DATA 0x21
|
||||
#define PIC2_CMD 0xA0
|
||||
#define PIC2_DATA 0xA1
|
||||
#define ICW1_ICW4 0x01
|
||||
#define ICW1_INIT 0x10
|
||||
|
||||
/* assembly stub declarations */
|
||||
extern void isr_stub_0(void);
|
||||
extern void isr_stub_1(void);
|
||||
extern void isr_stub_2(void);
|
||||
extern void isr_stub_3(void);
|
||||
extern void isr_stub_4(void);
|
||||
extern void isr_stub_5(void);
|
||||
extern void isr_stub_6(void);
|
||||
extern void isr_stub_7(void);
|
||||
extern void isr_stub_8(void);
|
||||
extern void isr_stub_9(void);
|
||||
extern void isr_stub_10(void);
|
||||
extern void isr_stub_11(void);
|
||||
extern void isr_stub_12(void);
|
||||
extern void isr_stub_13(void);
|
||||
extern void isr_stub_14(void);
|
||||
extern void isr_stub_15(void);
|
||||
extern void isr_stub_16(void);
|
||||
extern void isr_stub_17(void);
|
||||
extern void isr_stub_18(void);
|
||||
extern void isr_stub_19(void);
|
||||
extern void isr_stub_20(void);
|
||||
extern void isr_stub_21(void);
|
||||
extern void isr_stub_22(void);
|
||||
extern void isr_stub_23(void);
|
||||
extern void isr_stub_24(void);
|
||||
extern void isr_stub_25(void);
|
||||
extern void isr_stub_26(void);
|
||||
extern void isr_stub_27(void);
|
||||
extern void isr_stub_28(void);
|
||||
extern void isr_stub_29(void);
|
||||
extern void isr_stub_30(void);
|
||||
extern void isr_stub_31(void);
|
||||
extern void isr_stub_32(void);
|
||||
extern void isr_stub_33(void);
|
||||
extern void isr_stub_34(void);
|
||||
extern void isr_stub_35(void);
|
||||
extern void isr_stub_36(void);
|
||||
extern void isr_stub_37(void);
|
||||
extern void isr_stub_38(void);
|
||||
extern void isr_stub_39(void);
|
||||
extern void isr_stub_40(void);
|
||||
extern void isr_stub_41(void);
|
||||
extern void isr_stub_42(void);
|
||||
extern void isr_stub_43(void);
|
||||
extern void isr_stub_44(void);
|
||||
extern void isr_stub_45(void);
|
||||
extern void isr_stub_46(void);
|
||||
extern void isr_stub_47(void);
|
||||
|
||||
static void *g_isr_table[] = {
|
||||
isr_stub_0, isr_stub_1, isr_stub_2, isr_stub_3,
|
||||
isr_stub_4, isr_stub_5, isr_stub_6, isr_stub_7,
|
||||
isr_stub_8, isr_stub_9, isr_stub_10, isr_stub_11,
|
||||
isr_stub_12, isr_stub_13, isr_stub_14, isr_stub_15,
|
||||
isr_stub_16, isr_stub_17, isr_stub_18, isr_stub_19,
|
||||
isr_stub_20, isr_stub_21, isr_stub_22, isr_stub_23,
|
||||
isr_stub_24, isr_stub_25, isr_stub_26, isr_stub_27,
|
||||
isr_stub_28, isr_stub_29, isr_stub_30, isr_stub_31,
|
||||
isr_stub_32, isr_stub_33, isr_stub_34, isr_stub_35,
|
||||
isr_stub_36, isr_stub_37, isr_stub_38, isr_stub_39,
|
||||
isr_stub_40, isr_stub_41, isr_stub_42, isr_stub_43,
|
||||
isr_stub_44, isr_stub_45, isr_stub_46, isr_stub_47,
|
||||
};
|
||||
|
||||
static void outb(u16 port, u8 value) {
|
||||
__asm__ volatile ("outb %0, %1" :: "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static u8 inb(u16 port) {
|
||||
u8 value;
|
||||
__asm__ volatile ("inb %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
static void io_wait(void) {
|
||||
outb(0x80, 0);
|
||||
}
|
||||
|
||||
static void pic_remap(void) {
|
||||
/* save masks */
|
||||
u8 m1 = inb(PIC1_DATA);
|
||||
u8 m2 = inb(PIC2_DATA);
|
||||
|
||||
/* ICW1: start init + ICW4 */
|
||||
outb(PIC1_CMD, ICW1_INIT | ICW1_ICW4);
|
||||
io_wait();
|
||||
outb(PIC2_CMD, ICW1_INIT | ICW1_ICW4);
|
||||
io_wait();
|
||||
|
||||
/* ICW2: vector offsets */
|
||||
outb(PIC1_DATA, 0x20); /* master: vectors 0x20-0x27 */
|
||||
io_wait();
|
||||
outb(PIC2_DATA, 0x28); /* slave: vectors 0x28-0x2F */
|
||||
io_wait();
|
||||
|
||||
/* ICW3: master/slave wiring */
|
||||
outb(PIC1_DATA, 0x04); /* master: IRQ2 → slave */
|
||||
io_wait();
|
||||
outb(PIC2_DATA, 0x02); /* slave: cascade identity */
|
||||
io_wait();
|
||||
|
||||
/* ICW4: 8086 mode */
|
||||
outb(PIC1_DATA, 0x01);
|
||||
io_wait();
|
||||
outb(PIC2_DATA, 0x01);
|
||||
io_wait();
|
||||
|
||||
/* restore masks: mask all except IRQ1 (keyboard) */
|
||||
outb(PIC1_DATA, 0xFD); /* 1111_1101: enable IRQ0 (timer) and IRQ1 (kb) */
|
||||
outb(PIC2_DATA, 0xFF); /* mask all slave */
|
||||
}
|
||||
|
||||
static void idt_set_entry(u8 vector, void *handler, u8 ist, u8 type) {
|
||||
u64 addr = (u64)handler;
|
||||
g_idt[vector].offset_low = (u16)(addr & 0xffff);
|
||||
g_idt[vector].selector = 0x08; /* kernel code segment (from GDT) */
|
||||
g_idt[vector].ist = ist;
|
||||
g_idt[vector].type_attr = type;
|
||||
g_idt[vector].offset_mid = (u16)((addr >> 16) & 0xffff);
|
||||
g_idt[vector].offset_high = (u32)(addr >> 32);
|
||||
g_idt[vector].reserved = 0;
|
||||
}
|
||||
|
||||
void idt_init(void) {
|
||||
log_info("[IDT] init begin");
|
||||
|
||||
for (u16 i = 0; i < 48; i++) {
|
||||
idt_set_entry((u8)i, g_isr_table[i], 0, 0x8E); /* present, ring0, 64-bit interrupt gate */
|
||||
}
|
||||
/* fill unused entries with null */
|
||||
for (u16 i = 48; i < IDT_ENTRIES; i++) {
|
||||
idt_set_entry((u8)i, 0, 0, 0);
|
||||
}
|
||||
|
||||
idt_ptr idtr;
|
||||
idtr.limit = (u16)(sizeof(g_idt) - 1);
|
||||
idtr.base = (u64)&g_idt;
|
||||
|
||||
__asm__ volatile ("lidt %0" :: "m"(idtr));
|
||||
|
||||
pic_remap();
|
||||
log_info("[IDT] PIC remapped (master=0x20 slave=0x28)");
|
||||
|
||||
__asm__ volatile ("sti");
|
||||
log_info("[IDT] interrupts enabled");
|
||||
log_info("[IDT] init ok");
|
||||
}
|
||||
|
||||
/* IRQ handler table */
|
||||
static irq_handler_t g_irq_handlers[16];
|
||||
|
||||
int irq_register(u8 irq, irq_handler_t handler) {
|
||||
if (irq >= 16) return -1;
|
||||
g_irq_handlers[irq] = handler;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Stack frame pushed by isr_common in idt.S */
|
||||
typedef struct {
|
||||
u64 r11, r10, r9, r8, rax, rcx, rdx, rsi, rdi;
|
||||
u64 vector;
|
||||
u64 error_code;
|
||||
u64 rip, cs, rflags;
|
||||
} isr_frame;
|
||||
|
||||
void idt_handler(isr_frame *frame) {
|
||||
if (frame->vector < 32) {
|
||||
log_error("[IDT] exception");
|
||||
log_hex64("[IDT] vector=", frame->vector);
|
||||
log_hex64("[IDT] err=", frame->error_code);
|
||||
log_hex64("[IDT] rip=", frame->rip);
|
||||
for (;;) { __asm__ volatile ("cli; hlt"); }
|
||||
}
|
||||
|
||||
if (frame->vector >= 32 && frame->vector <= 47) {
|
||||
u8 irq = (u8)(frame->vector - 0x20);
|
||||
|
||||
/* call registered handler */
|
||||
if (irq < 16 && g_irq_handlers[irq]) {
|
||||
int suppress_eoi = g_irq_handlers[irq](irq);
|
||||
if (suppress_eoi) return;
|
||||
}
|
||||
|
||||
/* send EOI */
|
||||
if (frame->vector >= 0x28) {
|
||||
outb(PIC2_CMD, 0x20);
|
||||
}
|
||||
outb(PIC1_CMD, 0x20);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,62 @@
|
||||
/* IDT assembly stubs — SAS-R0 interrupt vectors */
|
||||
.section .text
|
||||
|
||||
.macro isr_no_err n
|
||||
.global isr_stub_\n
|
||||
.type isr_stub_\n, @function
|
||||
isr_stub_\n:
|
||||
pushq $0
|
||||
pushq $\n
|
||||
jmp isr_common
|
||||
.endm
|
||||
|
||||
.macro isr_err n
|
||||
.global isr_stub_\n
|
||||
.type isr_stub_\n, @function
|
||||
isr_stub_\n:
|
||||
pushq $\n
|
||||
jmp isr_common
|
||||
.endm
|
||||
|
||||
/* Exceptions 0-31 */
|
||||
isr_no_err 0; isr_no_err 1; isr_no_err 2; isr_no_err 3
|
||||
isr_no_err 4; isr_no_err 5; isr_no_err 6; isr_no_err 7
|
||||
isr_err 8; isr_no_err 9; isr_err 10; isr_err 11
|
||||
isr_err 12; isr_err 13; isr_err 14; isr_no_err 15
|
||||
isr_no_err 16; isr_err 17; isr_no_err 18; isr_no_err 19
|
||||
isr_no_err 20; isr_no_err 21; isr_no_err 22; isr_no_err 23
|
||||
isr_no_err 24; isr_no_err 25; isr_no_err 26; isr_no_err 27
|
||||
isr_no_err 28; isr_no_err 29; isr_err 30; isr_no_err 31
|
||||
|
||||
/* IRQ 32-47 */
|
||||
isr_no_err 32; isr_no_err 33; isr_no_err 34; isr_no_err 35
|
||||
isr_no_err 36; isr_no_err 37; isr_no_err 38; isr_no_err 39
|
||||
isr_no_err 40; isr_no_err 41; isr_no_err 42; isr_no_err 43
|
||||
isr_no_err 44; isr_no_err 45; isr_no_err 46; isr_no_err 47
|
||||
|
||||
/* Common ISR */
|
||||
isr_common:
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
pushq %rdx
|
||||
pushq %rcx
|
||||
pushq %rax
|
||||
pushq %r8
|
||||
pushq %r9
|
||||
pushq %r10
|
||||
pushq %r11
|
||||
|
||||
movq %rsp, %rdi
|
||||
call idt_handler
|
||||
|
||||
popq %r11
|
||||
popq %r10
|
||||
popq %r9
|
||||
popq %r8
|
||||
popq %rax
|
||||
popq %rcx
|
||||
popq %rdx
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
addq $16, %rsp
|
||||
iretq
|
||||
Binary file not shown.
@@ -0,0 +1,15 @@
|
||||
#include <utsm/types.h>
|
||||
|
||||
void outb(u16 port, u8 value) {
|
||||
__asm__ volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
u8 inb(u16 port) {
|
||||
u8 value;
|
||||
__asm__ volatile ("inb %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
void io_wait(void) {
|
||||
outb(0x80, 0);
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,154 @@
|
||||
#ifndef UTSM_LIMINE_H
|
||||
#define UTSM_LIMINE_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88ULL, 0x0a82e883a194f07bULL
|
||||
|
||||
struct limine_hhdm_response {
|
||||
u64 revision;
|
||||
u64 offset;
|
||||
};
|
||||
|
||||
struct limine_hhdm_request {
|
||||
u64 id[4];
|
||||
u64 revision;
|
||||
struct limine_hhdm_response *response;
|
||||
};
|
||||
|
||||
struct limine_kernel_address_response {
|
||||
u64 revision;
|
||||
u64 physical_base;
|
||||
u64 virtual_base;
|
||||
};
|
||||
|
||||
struct limine_kernel_address_request {
|
||||
u64 id[4];
|
||||
u64 revision;
|
||||
struct limine_kernel_address_response *response;
|
||||
};
|
||||
|
||||
#define LIMINE_KERNEL_ADDRESS_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63ULL, 0xb2644a48c516a487ULL }
|
||||
|
||||
struct limine_file {
|
||||
u64 revision;
|
||||
void *address;
|
||||
u64 size;
|
||||
char *path;
|
||||
char *cmdline;
|
||||
u32 media_type;
|
||||
u32 unused;
|
||||
u32 tftp_ip;
|
||||
u32 tftp_port;
|
||||
u32 partition_index;
|
||||
u32 mbr_disk_id;
|
||||
u8 gpt_disk_uuid[16];
|
||||
u8 gpt_part_uuid[16];
|
||||
u8 part_uuid[16];
|
||||
};
|
||||
|
||||
struct limine_module_response {
|
||||
u64 revision;
|
||||
u64 module_count;
|
||||
struct limine_file **modules;
|
||||
};
|
||||
|
||||
struct limine_module_request {
|
||||
u64 id[4];
|
||||
u64 revision;
|
||||
struct limine_module_response *response;
|
||||
};
|
||||
|
||||
#define LIMINE_MODULE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x3e7e279702be32afULL, 0xca1c4f3bd1280ceeULL }
|
||||
|
||||
struct limine_rsdp_response {
|
||||
u64 revision;
|
||||
void *address;
|
||||
};
|
||||
|
||||
struct limine_rsdp_request {
|
||||
u64 id[4];
|
||||
u64 revision;
|
||||
struct limine_rsdp_response *response;
|
||||
};
|
||||
|
||||
#define LIMINE_RSDP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xc5e77b6b397e7b43ULL, 0x27637845accdcf3cULL }
|
||||
|
||||
struct limine_framebuffer {
|
||||
void *address;
|
||||
u64 width;
|
||||
u64 height;
|
||||
u64 pitch;
|
||||
u16 bpp;
|
||||
u8 memory_model;
|
||||
u8 red_mask_size;
|
||||
u8 red_mask_shift;
|
||||
u8 green_mask_size;
|
||||
u8 green_mask_shift;
|
||||
u8 blue_mask_size;
|
||||
u8 blue_mask_shift;
|
||||
u8 unused[7];
|
||||
u64 edid_size;
|
||||
void *edid;
|
||||
u64 mode_count;
|
||||
struct limine_video_mode **modes;
|
||||
};
|
||||
|
||||
struct limine_video_mode {
|
||||
u64 pitch;
|
||||
u64 width;
|
||||
u64 height;
|
||||
u16 bpp;
|
||||
u8 memory_model;
|
||||
u8 red_mask_size;
|
||||
u8 red_mask_shift;
|
||||
u8 green_mask_size;
|
||||
u8 green_mask_shift;
|
||||
u8 blue_mask_size;
|
||||
u8 blue_mask_shift;
|
||||
};
|
||||
|
||||
struct limine_framebuffer_response {
|
||||
u64 revision;
|
||||
u64 framebuffer_count;
|
||||
struct limine_framebuffer **framebuffers;
|
||||
};
|
||||
|
||||
struct limine_framebuffer_request {
|
||||
u64 id[4];
|
||||
u64 revision;
|
||||
struct limine_framebuffer_response *response;
|
||||
};
|
||||
|
||||
#define LIMINE_FRAMEBUFFER_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x9d5827dcd881dd75ULL, 0xa3148604f6fab11bULL }
|
||||
|
||||
#define LIMINE_MEMMAP_USABLE 0
|
||||
#define LIMINE_MEMMAP_RESERVED 1
|
||||
#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2
|
||||
#define LIMINE_MEMMAP_ACPI_NVS 3
|
||||
#define LIMINE_MEMMAP_BAD_MEMORY 4
|
||||
#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5
|
||||
#define LIMINE_MEMMAP_KERNEL_AND_MODULES 6
|
||||
#define LIMINE_MEMMAP_FRAMEBUFFER 7
|
||||
|
||||
struct limine_memmap_entry {
|
||||
u64 base;
|
||||
u64 length;
|
||||
u64 type;
|
||||
};
|
||||
|
||||
struct limine_memmap_response {
|
||||
u64 revision;
|
||||
u64 entry_count;
|
||||
struct limine_memmap_entry **entries;
|
||||
};
|
||||
|
||||
struct limine_memmap_request {
|
||||
u64 id[4];
|
||||
u64 revision;
|
||||
struct limine_memmap_response *response;
|
||||
};
|
||||
|
||||
#define LIMINE_MEMMAP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x67cf3d9d378a806fULL, 0xe304acdfc50c3c62ULL }
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
#include <utsm/types.h>
|
||||
|
||||
void outb(u16 port, u8 value);
|
||||
u8 inb(u16 port);
|
||||
|
||||
#define COM1 0x3F8
|
||||
|
||||
static int serial_ready(void) {
|
||||
return (inb(COM1 + 5) & 0x20) != 0;
|
||||
}
|
||||
|
||||
static int serial_wait_ready(void) {
|
||||
for (u64 spin = 0; spin < 1000000ULL; spin++) {
|
||||
if (serial_ready()) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void serial_init(void) {
|
||||
outb(COM1 + 1, 0x00);
|
||||
outb(COM1 + 3, 0x80);
|
||||
outb(COM1 + 0, 0x03);
|
||||
outb(COM1 + 1, 0x00);
|
||||
outb(COM1 + 3, 0x03);
|
||||
outb(COM1 + 2, 0xC7);
|
||||
outb(COM1 + 4, 0x0B);
|
||||
}
|
||||
|
||||
void serial_putc(char c) {
|
||||
if (c == '\n') {
|
||||
serial_putc('\r');
|
||||
}
|
||||
if (!serial_wait_ready()) {
|
||||
return;
|
||||
}
|
||||
outb(COM1, (u8)c);
|
||||
}
|
||||
|
||||
void serial_write(const char *s) {
|
||||
while (*s) {
|
||||
serial_putc(*s++);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,29 @@
|
||||
#include <utsm/capability.h>
|
||||
#include <utsm/segment.h>
|
||||
|
||||
int utsm_cap_validate(utsm_capability cap, u32 required_rights, u64 offset, u64 len, utsm_segment_desc **out_desc) {
|
||||
utsm_segment_desc *desc = utsm_get_segment(cap.segment_slot);
|
||||
if (!desc) {
|
||||
return UTSM_ERR_INVALID;
|
||||
}
|
||||
if (desc->state == UTSM_SEG_POISONED) {
|
||||
return UTSM_ERR_POISONED;
|
||||
}
|
||||
if (desc->state != UTSM_SEG_ACTIVE) {
|
||||
return UTSM_ERR_STATE;
|
||||
}
|
||||
if (desc->generation != cap.generation) {
|
||||
return UTSM_ERR_STALE_CAP;
|
||||
}
|
||||
if ((cap.rights & required_rights) != required_rights) {
|
||||
return UTSM_ERR_ACCESS;
|
||||
}
|
||||
if ((u32)desc->key_epoch != cap.epoch) {
|
||||
return UTSM_ERR_EPOCH;
|
||||
}
|
||||
if (offset > desc->cipher_length || len > desc->cipher_length || offset + len > desc->cipher_length) {
|
||||
return UTSM_ERR_BOUNDS;
|
||||
}
|
||||
*out_desc = desc;
|
||||
return UTSM_OK;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,47 @@
|
||||
#include <utsm/dirty.h>
|
||||
#include <utsm/segment.h>
|
||||
#include <utsm/arena.h>
|
||||
#include <utsm/config.h>
|
||||
|
||||
static void bitmap_set(u64 *bitmap, u64 bit) {
|
||||
bitmap[bit / 64] |= 1ULL << (bit % 64);
|
||||
}
|
||||
|
||||
static bool bitmap_test(u64 *bitmap, u64 bit) {
|
||||
return (bitmap[bit / 64] & (1ULL << (bit % 64))) != 0;
|
||||
}
|
||||
|
||||
void utsm_dirty_init(utsm_segment_desc *desc, u64 page_count) {
|
||||
desc->dirty_shard_count = 1;
|
||||
desc->dirty_shards = (utsm_dirty_shard *)kmem_alloc(sizeof(utsm_dirty_shard));
|
||||
if (!desc->dirty_shards) {
|
||||
return;
|
||||
}
|
||||
u64 words = (page_count + 63) / 64;
|
||||
desc->dirty_shards[0].dirty_count = 0;
|
||||
desc->dirty_shards[0].shard_id = 0;
|
||||
desc->dirty_shards[0].page_base = 0;
|
||||
desc->dirty_shards[0].page_count = page_count;
|
||||
desc->dirty_shards[0].last_checkpoint_epoch = 0;
|
||||
desc->dirty_shards[0].bitmap = (u64 *)kmem_alloc_aligned(words * sizeof(u64), 8);
|
||||
if (desc->dirty_shards[0].bitmap) {
|
||||
for (u64 i = 0; i < words; i++) {
|
||||
desc->dirty_shards[0].bitmap[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void utsm_mark_dirty(utsm_segment_desc *desc, u64 offset, u64 len) {
|
||||
if (!desc || !desc->dirty_shards || !desc->dirty_shards[0].bitmap || len == 0) {
|
||||
return;
|
||||
}
|
||||
u64 first = offset / UTSM_PAGE_SIZE;
|
||||
u64 last = (offset + len - 1) / UTSM_PAGE_SIZE;
|
||||
utsm_dirty_shard *shard = &desc->dirty_shards[0];
|
||||
for (u64 page = first; page <= last && page < shard->page_count; page++) {
|
||||
if (!bitmap_test(shard->bitmap, page)) {
|
||||
bitmap_set(shard->bitmap, page);
|
||||
shard->dirty_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
#include <utsm/dmp.h>
|
||||
#include <utsm/segment.h>
|
||||
|
||||
#define UTSM_DMP_MAGIC 0x5554534d444d5031ULL
|
||||
|
||||
void utsm_dmp_init(utsm_dmp *dmp, utsm_segment_desc *desc, u32 slot) {
|
||||
dmp->magic = UTSM_DMP_MAGIC;
|
||||
dmp->version = 1;
|
||||
dmp->segment_slot = slot;
|
||||
dmp->fast_base = (u64)desc->cipher_base;
|
||||
dmp->fast_limit = (u64)desc->cipher_base + desc->cipher_length;
|
||||
dmp->fast_tweak_seed = desc->tweak_seed;
|
||||
dmp->fast_key_epoch = desc->key_epoch;
|
||||
dmp->dirty_bitmap_base = desc->dirty_shards ? (u64)desc->dirty_shards[0].bitmap : 0;
|
||||
dmp->mac_table_base = (u64)desc->mac_table;
|
||||
dmp->last_writer_seq = desc->writer_seq;
|
||||
dmp->last_cpu = desc->last_cpu;
|
||||
dmp->flags = desc->flags;
|
||||
dmp->crc = dmp->magic ^ dmp->fast_base ^ dmp->fast_limit ^ dmp->fast_tweak_seed;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,11 @@
|
||||
#include <utsm/process.h>
|
||||
#include <utsm/drr.h>
|
||||
|
||||
void utsm_process_create_test(utsm_process_context *process, u64 seed) {
|
||||
process->process_uuid = uuid_make_test(seed);
|
||||
process->crypto_epoch = 1;
|
||||
process->recovery_generation = drr_recovery_generation();
|
||||
process->capability_table_slot = 0;
|
||||
process->capability_count = 0;
|
||||
process->flags = 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,80 @@
|
||||
#include <utsm/segment.h>
|
||||
#include <utsm/process.h>
|
||||
#include <utsm/arena.h>
|
||||
#include <utsm/dmp.h>
|
||||
#include <utsm/config.h>
|
||||
|
||||
u64 utsm_next_generation(void);
|
||||
|
||||
static u64 digest_uuid(uuid128_t id) {
|
||||
return id.hi ^ id.lo ^ (id.hi >> 32) ^ (id.lo << 17);
|
||||
}
|
||||
|
||||
static u64 make_tweak_seed(uuid128_t process_uuid, uuid128_t segment_uuid, u64 epoch) {
|
||||
return process_uuid.hi ^ process_uuid.lo ^ segment_uuid.hi ^ segment_uuid.lo ^ (epoch * 0x9e3779b97f4a7c15ULL);
|
||||
}
|
||||
|
||||
int utsm_create_segment(utsm_process_context *process, u64 size, u32 flags, utsm_capability *out_cap) {
|
||||
if (!process || !out_cap || size == 0) {
|
||||
return UTSM_ERR_INVALID;
|
||||
}
|
||||
|
||||
u32 slot = UTSM_MAX_SEGMENTS;
|
||||
utsm_segment_desc *desc = NULL;
|
||||
for (u32 i = 0; i < UTSM_MAX_SEGMENTS; i++) {
|
||||
utsm_segment_desc *candidate = utsm_get_segment(i);
|
||||
if (candidate->state == UTSM_SEG_FREE) {
|
||||
slot = i;
|
||||
desc = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!desc) {
|
||||
return UTSM_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
u64 length = utsm_align_up_u64(size, UTSM_CACHE_LINE_SIZE);
|
||||
u64 pages = utsm_align_up_u64(length, UTSM_PAGE_SIZE) / UTSM_PAGE_SIZE;
|
||||
u8 *cipher = (u8 *)kmem_alloc_page(pages);
|
||||
utsm_dmp *dmp = (utsm_dmp *)kmem_alloc_aligned(sizeof(utsm_dmp), 64);
|
||||
void *mac_table = kmem_alloc_aligned(pages * sizeof(u64), 8);
|
||||
if (!cipher || !dmp || !mac_table) {
|
||||
return UTSM_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < pages * UTSM_PAGE_SIZE; i++) {
|
||||
cipher[i] = 0;
|
||||
}
|
||||
|
||||
desc->segment_uuid = uuid_make_test(utsm_next_generation() + slot);
|
||||
desc->owner_process_uuid = process->process_uuid;
|
||||
desc->cipher_base = cipher;
|
||||
desc->cipher_length = length;
|
||||
desc->dmp_base = dmp;
|
||||
desc->key_epoch = process->crypto_epoch;
|
||||
desc->tweak_seed = make_tweak_seed(process->process_uuid, desc->segment_uuid, desc->key_epoch);
|
||||
desc->mac_table = mac_table;
|
||||
desc->generation++;
|
||||
desc->flags = flags;
|
||||
desc->state = UTSM_SEG_ACTIVE;
|
||||
desc->last_cpu = 0;
|
||||
desc->writer_seq = 0;
|
||||
desc->checkpoint_generation = process->recovery_generation;
|
||||
|
||||
utsm_dirty_init(desc, pages);
|
||||
utsm_dmp_init(dmp, desc, slot);
|
||||
|
||||
out_cap->segment_slot = slot;
|
||||
out_cap->generation = desc->generation;
|
||||
out_cap->rights = 0;
|
||||
if (flags & UTSM_SEG_F_READ) out_cap->rights |= UTSM_RIGHT_READ;
|
||||
if (flags & UTSM_SEG_F_WRITE) out_cap->rights |= UTSM_RIGHT_WRITE;
|
||||
if (flags & UTSM_SEG_F_EXEC) out_cap->rights |= UTSM_RIGHT_EXEC;
|
||||
if (flags & UTSM_SEG_F_DMA) out_cap->rights |= UTSM_RIGHT_DMA;
|
||||
out_cap->epoch = (u32)desc->key_epoch;
|
||||
out_cap->uuid_digest = digest_uuid(desc->segment_uuid);
|
||||
out_cap->auth_tag = out_cap->uuid_digest ^ digest_uuid(process->process_uuid) ^ desc->key_epoch;
|
||||
|
||||
process->capability_count++;
|
||||
return UTSM_OK;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,32 @@
|
||||
#include <utsm/utsm.h>
|
||||
#include <utsm/segment.h>
|
||||
#include <utsm/pckc.h>
|
||||
#include <utsm/log.h>
|
||||
|
||||
static utsm_segment_desc g_segments[UTSM_MAX_SEGMENTS];
|
||||
static u64 g_generation = 1;
|
||||
|
||||
void utsm_init(void) {
|
||||
log_info("[UTSM] segment table reset begin");
|
||||
for (u32 i = 0; i < UTSM_MAX_SEGMENTS; i++) {
|
||||
g_segments[i].state = UTSM_SEG_FREE;
|
||||
g_segments[i].generation = 1;
|
||||
}
|
||||
log_info("[UTSM] segment table reset ok");
|
||||
|
||||
g_generation = 1;
|
||||
log_info("[UTSM] pckc init begin");
|
||||
utsm_pckc_init();
|
||||
log_info("[UTSM] pckc init ok");
|
||||
}
|
||||
|
||||
utsm_segment_desc *utsm_get_segment(u32 slot) {
|
||||
if (slot >= UTSM_MAX_SEGMENTS) {
|
||||
return NULL;
|
||||
}
|
||||
return &g_segments[slot];
|
||||
}
|
||||
|
||||
u64 utsm_next_generation(void) {
|
||||
return g_generation++;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
#include <utsm/crypto.h>
|
||||
#include <utsm/drr.h>
|
||||
|
||||
static u64 mix64(u64 x) {
|
||||
x ^= x >> 30;
|
||||
x *= 0xbf58476d1ce4e5b9ULL;
|
||||
x ^= x >> 27;
|
||||
x *= 0x94d049bb133111ebULL;
|
||||
x ^= x >> 31;
|
||||
return x;
|
||||
}
|
||||
|
||||
void utsm_kdf_segment_key(uuid128_t process_uuid, uuid128_t segment_uuid, u64 key_epoch, utsm_key_material *out_key) {
|
||||
const u64 *root = drr_get_root_key();
|
||||
out_key->words[0] = mix64(root[0] ^ process_uuid.hi ^ segment_uuid.lo ^ key_epoch);
|
||||
out_key->words[1] = mix64(root[1] ^ process_uuid.lo ^ segment_uuid.hi ^ (key_epoch << 1));
|
||||
out_key->words[2] = mix64(root[2] ^ process_uuid.hi ^ segment_uuid.hi ^ (key_epoch << 7));
|
||||
out_key->words[3] = mix64(root[3] ^ process_uuid.lo ^ segment_uuid.lo ^ (key_epoch << 13));
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
#include <utsm/crypto.h>
|
||||
#include <utsm/config.h>
|
||||
|
||||
static u64 next_stream_word(u64 x) {
|
||||
x ^= x << 13;
|
||||
x ^= x >> 7;
|
||||
x ^= x << 17;
|
||||
return x;
|
||||
}
|
||||
|
||||
void utsm_crypt_line(const utsm_key_material *key, u64 tweak, const u8 *in, u8 *out) {
|
||||
u64 state = key->words[0] ^ key->words[1] ^ key->words[2] ^ key->words[3] ^ tweak;
|
||||
for (u64 i = 0; i < UTSM_CACHE_LINE_SIZE; i += 8) {
|
||||
state = next_stream_word(state + i + 0xa5a5a5a5a5a5a5a5ULL);
|
||||
for (u64 j = 0; j < 8; j++) {
|
||||
out[i + j] = in[i + j] ^ (u8)(state >> (j * 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
#include <utsm/crypto.h>
|
||||
|
||||
static u64 mix64_tweak(u64 x) {
|
||||
x ^= x >> 33;
|
||||
x *= 0xff51afd7ed558ccdULL;
|
||||
x ^= x >> 33;
|
||||
x *= 0xc4ceb9fe1a85ec53ULL;
|
||||
x ^= x >> 33;
|
||||
return x;
|
||||
}
|
||||
|
||||
u64 utsm_make_tweak(u64 tweak_seed, u64 line_index, u64 key_epoch) {
|
||||
return mix64_tweak(tweak_seed ^ (line_index * 0x9e3779b97f4a7c15ULL) ^ (key_epoch << 32));
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,444 @@
|
||||
#include <utsm/dkm.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/types.h>
|
||||
#include <utsm/arena.h>
|
||||
#include "../arch/x86_64/limine.h"
|
||||
|
||||
#define ELF_MAGIC0 0x7f
|
||||
#define ELF_MAGIC1 'E'
|
||||
#define ELF_MAGIC2 'L'
|
||||
#define ELF_MAGIC3 'F'
|
||||
#define ELFCLASS64 2
|
||||
#define ELFDATA2LSB 1
|
||||
#define ET_REL 1
|
||||
#define ET_DYN 3
|
||||
#define ET_EXEC 2
|
||||
#define EM_X86_64 62
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_RELA 4
|
||||
#define SHT_PROGBITS 1
|
||||
#define SHT_NOBITS 8
|
||||
|
||||
#define SHF_ALLOC 0x2
|
||||
#define SHF_WRITE 0x1
|
||||
#define SHF_EXECINSTR 0x4
|
||||
|
||||
#define R_X86_64_64 1
|
||||
#define R_X86_64_32 10
|
||||
#define R_X86_64_32S 11
|
||||
#define R_X86_64_PC32 2
|
||||
|
||||
void *memset(void *dst, int value, usize len);
|
||||
void *memcpy(void *dst, const void *src, usize len);
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile struct limine_module_request g_module_request = {
|
||||
.id = LIMINE_MODULE_REQUEST_ID,
|
||||
.revision = 0,
|
||||
.response = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".limine_requests_start")))
|
||||
static volatile u64 g_limine_requests_start[4] = { LIMINE_COMMON_MAGIC, 0xf6b8f4b39de7d1aeULL, 0xfab91a6940fcb9cfULL };
|
||||
|
||||
__attribute__((used, section(".limine_requests_end")))
|
||||
static volatile u64 g_limine_requests_end[2] = { 0, 0 };
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile struct limine_rsdp_request g_rsdp_request = {
|
||||
.id = LIMINE_RSDP_REQUEST_ID,
|
||||
.revision = 0,
|
||||
.response = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile struct limine_framebuffer_request g_fb_request = {
|
||||
.id = LIMINE_FRAMEBUFFER_REQUEST_ID,
|
||||
.revision = 0,
|
||||
.response = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile struct limine_hhdm_request g_hhdm_request = {
|
||||
.id = { LIMINE_COMMON_MAGIC, 0x48dcf1cb8ad2b852ULL, 0x63984e959a98244bULL },
|
||||
.revision = 0,
|
||||
.response = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile struct limine_kernel_address_request g_kernel_address_request = {
|
||||
.id = LIMINE_KERNEL_ADDRESS_REQUEST_ID,
|
||||
.revision = 0,
|
||||
.response = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile struct limine_memmap_request g_memmap_request = {
|
||||
.id = LIMINE_MEMMAP_REQUEST_ID,
|
||||
.revision = 0,
|
||||
.response = 0
|
||||
};
|
||||
|
||||
typedef struct elf64_ehdr {
|
||||
u8 ident[16];
|
||||
u16 type;
|
||||
u16 machine;
|
||||
u32 version;
|
||||
u64 entry;
|
||||
u64 phoff;
|
||||
u64 shoff;
|
||||
u32 flags;
|
||||
u16 ehsize;
|
||||
u16 phentsize;
|
||||
u16 phnum;
|
||||
u16 shentsize;
|
||||
u16 shnum;
|
||||
u16 shstrndx;
|
||||
} elf64_ehdr;
|
||||
|
||||
typedef struct elf64_shdr {
|
||||
u32 name;
|
||||
u32 type;
|
||||
u64 flags;
|
||||
u64 addr;
|
||||
u64 offset;
|
||||
u64 size;
|
||||
u32 link;
|
||||
u32 info;
|
||||
u64 addralign;
|
||||
u64 entsize;
|
||||
} elf64_shdr;
|
||||
|
||||
typedef struct elf64_sym {
|
||||
u32 name;
|
||||
u8 info;
|
||||
u8 other;
|
||||
u16 shndx;
|
||||
u64 value;
|
||||
u64 size;
|
||||
} elf64_sym;
|
||||
|
||||
typedef struct elf64_rela {
|
||||
u64 offset;
|
||||
u64 info;
|
||||
i64 addend;
|
||||
} elf64_rela;
|
||||
|
||||
static int streq(const char *a, const char *b) {
|
||||
usize i = 0;
|
||||
while (a[i] && b[i]) {
|
||||
if (a[i] != b[i]) {
|
||||
return 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return a[i] == b[i];
|
||||
}
|
||||
|
||||
int dkm_check_elf64(const void *address, u64 size) {
|
||||
if (!address || size < sizeof(elf64_ehdr)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const elf64_ehdr *ehdr = (const elf64_ehdr *)address;
|
||||
if (ehdr->ident[0] != ELF_MAGIC0 || ehdr->ident[1] != ELF_MAGIC1 || ehdr->ident[2] != ELF_MAGIC2 || ehdr->ident[3] != ELF_MAGIC3) {
|
||||
return -2;
|
||||
}
|
||||
if (ehdr->ident[4] != ELFCLASS64 || ehdr->ident[5] != ELFDATA2LSB) {
|
||||
return -3;
|
||||
}
|
||||
if (ehdr->machine != EM_X86_64) {
|
||||
return -4;
|
||||
}
|
||||
if (ehdr->type != ET_REL && ehdr->type != ET_DYN && ehdr->type != ET_EXEC) {
|
||||
return -5;
|
||||
}
|
||||
if (ehdr->ehsize < sizeof(elf64_ehdr)) {
|
||||
return -6;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int range_ok(u64 offset, u64 length, u64 size) {
|
||||
if (offset > size) {
|
||||
return 0;
|
||||
}
|
||||
if (length > size - offset) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dkm_scan_symbols(const void *address, u64 size, struct dkm_symbol_scan *out) {
|
||||
const elf64_ehdr *ehdr = (const elf64_ehdr *)address;
|
||||
out->driver_desc = 0;
|
||||
out->driver_init = 0;
|
||||
out->driver_exit = 0;
|
||||
|
||||
if (ehdr->shoff == 0 || ehdr->shnum == 0 || ehdr->shentsize < sizeof(elf64_shdr)) {
|
||||
log_error("[DKM] ELF has no section table");
|
||||
return -1;
|
||||
}
|
||||
if (!range_ok(ehdr->shoff, (u64)ehdr->shnum * ehdr->shentsize, size)) {
|
||||
log_error("[DKM] ELF section table out of range");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const elf64_shdr *sections = (const elf64_shdr *)((const u8 *)address + ehdr->shoff);
|
||||
const elf64_shdr *symtab = 0;
|
||||
const elf64_shdr *strtab = 0;
|
||||
|
||||
for (u16 i = 0; i < ehdr->shnum; i++) {
|
||||
const elf64_shdr *section = (const elf64_shdr *)((const u8 *)sections + (u64)i * ehdr->shentsize);
|
||||
if (section->type == SHT_SYMTAB) {
|
||||
symtab = section;
|
||||
if (section->link < ehdr->shnum) {
|
||||
strtab = (const elf64_shdr *)((const u8 *)sections + (u64)section->link * ehdr->shentsize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!symtab || !strtab || strtab->type != SHT_STRTAB) {
|
||||
log_error("[DKM] missing symtab/strtab");
|
||||
return -1;
|
||||
}
|
||||
if (symtab->entsize < sizeof(elf64_sym) || !range_ok(symtab->offset, symtab->size, size) || !range_ok(strtab->offset, strtab->size, size)) {
|
||||
log_error("[DKM] invalid symtab/strtab range");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_info("[DKM] symtab found");
|
||||
log_hex64("[DKM] symbol count=", symtab->size / symtab->entsize);
|
||||
|
||||
for (u64 off = 0; off + sizeof(elf64_sym) <= symtab->size; off += symtab->entsize) {
|
||||
const elf64_sym *sym = (const elf64_sym *)((const u8 *)address + symtab->offset + off);
|
||||
if (sym->name >= strtab->size) {
|
||||
continue;
|
||||
}
|
||||
const char *name = (const char *)address + strtab->offset + sym->name;
|
||||
if (streq(name, "driver_desc")) {
|
||||
out->driver_desc = sym;
|
||||
log_info("[DKM] found driver_desc");
|
||||
log_hex64("[DKM] driver_desc section=", sym->shndx);
|
||||
log_hex64("[DKM] driver_desc value=", sym->value);
|
||||
} else if (streq(name, "driver_init")) {
|
||||
out->driver_init = sym;
|
||||
log_info("[DKM] found driver_init");
|
||||
log_hex64("[DKM] driver_init section=", sym->shndx);
|
||||
log_hex64("[DKM] driver_init value=", sym->value);
|
||||
} else if (streq(name, "driver_exit")) {
|
||||
out->driver_exit = sym;
|
||||
log_info("[DKM] found driver_exit");
|
||||
log_hex64("[DKM] driver_exit section=", sym->shndx);
|
||||
log_hex64("[DKM] driver_exit value=", sym->value);
|
||||
}
|
||||
}
|
||||
|
||||
if (out->driver_desc && out->driver_init && out->driver_exit) {
|
||||
log_info("[DKM] required driver symbols ok");
|
||||
return 0;
|
||||
}
|
||||
log_error("[DKM] required driver symbols missing");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dkm_load_elf_rel(const void *address, u64 size, const struct dkm_symbol_scan *symbols) {
|
||||
const elf64_ehdr *ehdr = (const elf64_ehdr *)address;
|
||||
const elf64_shdr *sections = (const elf64_shdr *)((const u8 *)address + ehdr->shoff);
|
||||
u64 image_offset[64];
|
||||
u64 total_size = 0;
|
||||
u64 max_align = 16;
|
||||
u16 alloc_count = 0;
|
||||
|
||||
for (u16 i = 1; i < ehdr->shnum && alloc_count < 64; i++) {
|
||||
const elf64_shdr *sh = (const elf64_shdr *)((const u8 *)sections + (u64)i * ehdr->shentsize);
|
||||
if (!(sh->flags & SHF_ALLOC)) {
|
||||
continue;
|
||||
}
|
||||
if (sh->addralign > max_align) {
|
||||
max_align = sh->addralign;
|
||||
}
|
||||
total_size = utsm_align_up_u64(total_size, sh->addralign);
|
||||
image_offset[i] = total_size;
|
||||
total_size += sh->size;
|
||||
alloc_count++;
|
||||
}
|
||||
|
||||
if (total_size == 0) {
|
||||
log_error("[DKM] no allocatable sections");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u8 *image = (u8 *)kmem_alloc_aligned(total_size, max_align);
|
||||
if (!image) {
|
||||
log_error("[DKM] failed to allocate module memory");
|
||||
return -1;
|
||||
}
|
||||
memset(image, 0, total_size);
|
||||
|
||||
for (u16 i = 1; i < ehdr->shnum; i++) {
|
||||
const elf64_shdr *sh = (const elf64_shdr *)((const u8 *)sections + (u64)i * ehdr->shentsize);
|
||||
if (!(sh->flags & SHF_ALLOC)) {
|
||||
continue;
|
||||
}
|
||||
if (sh->type == SHT_PROGBITS && sh->size > 0 && range_ok(sh->offset, sh->size, size)) {
|
||||
memcpy(image + image_offset[i], (const u8 *)address + sh->offset, sh->size);
|
||||
}
|
||||
}
|
||||
|
||||
for (u16 i = 1; i < ehdr->shnum; i++) {
|
||||
const elf64_shdr *sh = (const elf64_shdr *)((const u8 *)sections + (u64)i * ehdr->shentsize);
|
||||
if (sh->type != SHT_RELA) {
|
||||
continue;
|
||||
}
|
||||
if (sh->entsize < sizeof(elf64_rela) || !range_ok(sh->offset, sh->size, size)) {
|
||||
continue;
|
||||
}
|
||||
if (sh->info >= ehdr->shnum) {
|
||||
continue;
|
||||
}
|
||||
const elf64_shdr *target = (const elf64_shdr *)((const u8 *)sections + (u64)sh->info * ehdr->shentsize);
|
||||
if (!(target->flags & SHF_ALLOC)) {
|
||||
continue;
|
||||
}
|
||||
u8 *target_base = image + image_offset[sh->info];
|
||||
|
||||
const elf64_shdr *rela_symtab = 0;
|
||||
if (sh->link < ehdr->shnum) {
|
||||
rela_symtab = (const elf64_shdr *)((const u8 *)sections + (u64)sh->link * ehdr->shentsize);
|
||||
}
|
||||
const elf64_shdr *rela_strtab = 0;
|
||||
if (rela_symtab && rela_symtab->link < ehdr->shnum) {
|
||||
rela_strtab = (const elf64_shdr *)((const u8 *)sections + (u64)rela_symtab->link * ehdr->shentsize);
|
||||
}
|
||||
(void)rela_strtab;
|
||||
|
||||
for (u64 off = 0; off + sizeof(elf64_rela) <= sh->size; off += sh->entsize) {
|
||||
const elf64_rela *rela = (const elf64_rela *)((const u8 *)address + sh->offset + off);
|
||||
u32 sym_idx = (u32)(rela->info >> 32);
|
||||
u32 reloc_type = (u32)(rela->info & 0xffffffff);
|
||||
|
||||
u64 sym_value = 0;
|
||||
u16 sym_shndx = 0;
|
||||
if (rela_symtab && rela_strtab &&
|
||||
rela_symtab->entsize >= sizeof(elf64_sym) &&
|
||||
range_ok(rela_symtab->offset, rela_symtab->size, size)) {
|
||||
u64 sym_entry_off = (u64)sym_idx * rela_symtab->entsize;
|
||||
if (sym_entry_off + sizeof(elf64_sym) <= rela_symtab->size) {
|
||||
const elf64_sym *sym = (const elf64_sym *)((const u8 *)address + rela_symtab->offset + sym_entry_off);
|
||||
sym_value = sym->value;
|
||||
sym_shndx = sym->shndx;
|
||||
}
|
||||
}
|
||||
|
||||
u64 S = sym_value;
|
||||
if (sym_shndx > 0 && sym_shndx < 64) {
|
||||
S = (u64)image + image_offset[sym_shndx] + sym_value;
|
||||
}
|
||||
u64 P = (u64)image + image_offset[sh->info] + rela->offset;
|
||||
u64 A = rela->addend;
|
||||
|
||||
u64 patch = 0;
|
||||
if (reloc_type == R_X86_64_64) {
|
||||
patch = S + A;
|
||||
} else if (reloc_type == R_X86_64_32 || reloc_type == R_X86_64_32S) {
|
||||
patch = (u64)((i64)(i32)(S + A));
|
||||
} else if (reloc_type == R_X86_64_PC32) {
|
||||
patch = (u64)((i64)(i32)(S + A - P));
|
||||
} else {
|
||||
log_error("[DKM] unsupported relocation type");
|
||||
log_hex64("[DKM] reloc type=", (u64)reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rela->offset + 8 <= target->size) {
|
||||
if (reloc_type == R_X86_64_32 || reloc_type == R_X86_64_32S || reloc_type == R_X86_64_PC32) {
|
||||
*(u32 *)(target_base + rela->offset) = (u32)patch;
|
||||
} else {
|
||||
*(u64 *)(target_base + rela->offset) = patch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const elf64_sym *desc_sym = (const elf64_sym *)symbols->driver_desc;
|
||||
const elf64_sym *init_sym = (const elf64_sym *)symbols->driver_init;
|
||||
const dkm_driver_desc *desc = (const dkm_driver_desc *)(image + image_offset[desc_sym->shndx] + desc_sym->value);
|
||||
if (desc->magic != DKM_DRIVER_MAGIC) {
|
||||
log_error("[DKM] external driver_desc magic mismatch");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_info("[DKM] external driver loaded");
|
||||
log_hex64("[DKM] desc ptr=", (u64)desc);
|
||||
log_hex64("[DKM] name ptr=", (u64)desc->name);
|
||||
log_info(desc->name);
|
||||
|
||||
dkm_driver_init_fn init = (dkm_driver_init_fn)(image + image_offset[init_sym->shndx] + init_sym->value);
|
||||
|
||||
dkm_driver_handle handle;
|
||||
handle.desc = desc;
|
||||
handle.state = DKM_STATE_INITING;
|
||||
handle.init_status = 0;
|
||||
handle.load_stage = desc->stage;
|
||||
handle.flags = desc->flags;
|
||||
|
||||
int result = init(dkm_get_kernel_api(), &handle);
|
||||
handle.init_status = result;
|
||||
if (result != 0) {
|
||||
handle.state = DKM_STATE_FAILED;
|
||||
log_error("[DKM] external driver init failed");
|
||||
return result;
|
||||
}
|
||||
handle.state = DKM_STATE_ACTIVE;
|
||||
log_info("[DKM] external driver active");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dkm_scan_boot_modules(void) {
|
||||
struct limine_module_response *response = g_module_request.response;
|
||||
if (!response) {
|
||||
log_warn("[DKM] no Limine module response");
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("[DKM] boot modules scan begin");
|
||||
log_hex64("[DKM] boot module count=", response->module_count);
|
||||
|
||||
for (u64 i = 0; i < response->module_count; i++) {
|
||||
struct limine_file *file = response->modules[i];
|
||||
if (!file) {
|
||||
log_warn("[DKM] null module entry");
|
||||
continue;
|
||||
}
|
||||
|
||||
log_info("[DKM] module path");
|
||||
if (file->path) {
|
||||
log_info(file->path);
|
||||
}
|
||||
if (file->cmdline) {
|
||||
log_info(file->cmdline);
|
||||
}
|
||||
log_hex64("[DKM] module size=", file->size);
|
||||
|
||||
int status = dkm_check_elf64(file->address, file->size);
|
||||
if (status == 0) {
|
||||
log_info("[DKM] module ELF64 x86_64 ok");
|
||||
struct dkm_symbol_scan symbols;
|
||||
if (dkm_scan_symbols(file->address, file->size, &symbols) == 0) {
|
||||
log_info("[DKM] loading external ELF driver");
|
||||
int load_result = dkm_load_elf_rel(file->address, file->size, &symbols);
|
||||
if (load_result != 0) {
|
||||
log_error("[DKM] external driver load failed");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_error("[DKM] module ELF64 rejected");
|
||||
log_hex64("[DKM] elf status=", (u64)(i64)status);
|
||||
}
|
||||
}
|
||||
|
||||
log_info("[DKM] boot modules scan end");
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,47 @@
|
||||
#include <utsm/dkm.h>
|
||||
|
||||
static const char *const console_early_provides[] = {
|
||||
"console",
|
||||
"early-log"
|
||||
};
|
||||
|
||||
static const dkm_driver_desc console_early_desc = {
|
||||
.magic = DKM_DRIVER_MAGIC,
|
||||
.abi_version = DKM_ABI_VERSION,
|
||||
.desc_size = sizeof(dkm_driver_desc),
|
||||
.name = "console_early",
|
||||
.version = "0.1.0",
|
||||
.vendor = "Deshab",
|
||||
.driver_class = DKM_CLASS_CONSOLE,
|
||||
.stage = 0,
|
||||
.flags = DKM_F_REQUIRED | DKM_F_BOOT_MODULE | DKM_F_NO_UNLOAD | DKM_F_EARLY_LOG,
|
||||
.priority = 0,
|
||||
.depends = 0,
|
||||
.depends_count = 0,
|
||||
.provides = console_early_provides,
|
||||
.provides_count = 2,
|
||||
.min_kernel_abi = DKM_KERNEL_API_VERSION,
|
||||
.feature_bits = 0,
|
||||
.reserved0 = 0,
|
||||
.reserved1 = 0
|
||||
};
|
||||
|
||||
static int console_early_init(const dkm_kernel_api *api, dkm_driver_handle *handle) {
|
||||
(void)handle;
|
||||
if (!api || !api->log || !api->log->info) {
|
||||
return -1;
|
||||
}
|
||||
api->log->info("[DKM:console_early] serial console online");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int console_early_exit(dkm_driver_handle *handle) {
|
||||
(void)handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const dkm_builtin_driver dkm_builtin_console_early = {
|
||||
.desc = &console_early_desc,
|
||||
.init = console_early_init,
|
||||
.exit = console_early_exit
|
||||
};
|
||||
Binary file not shown.
@@ -0,0 +1,67 @@
|
||||
#include <utsm/dkm.h>
|
||||
#include <utsm/log.h>
|
||||
|
||||
static int dkm_validate_desc(const dkm_driver_desc *desc) {
|
||||
if (!desc) {
|
||||
return -1;
|
||||
}
|
||||
if (desc->magic != DKM_DRIVER_MAGIC) {
|
||||
return -2;
|
||||
}
|
||||
if (desc->abi_version != DKM_ABI_VERSION) {
|
||||
return -3;
|
||||
}
|
||||
if (desc->desc_size < sizeof(dkm_driver_desc)) {
|
||||
return -4;
|
||||
}
|
||||
if (!desc->name || !desc->version) {
|
||||
return -5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dkm_init(void) {
|
||||
log_info("[DKM] init begin");
|
||||
int status = dkm_load_builtin(&dkm_builtin_console_early);
|
||||
if (status == 0) {
|
||||
log_info("[DKM] init ok");
|
||||
} else {
|
||||
log_error("[DKM] init failed");
|
||||
}
|
||||
}
|
||||
|
||||
int dkm_load_builtin(const dkm_builtin_driver *driver) {
|
||||
if (!driver || !driver->desc || !driver->init) {
|
||||
log_error("[DKM] invalid builtin driver");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int status = dkm_validate_desc(driver->desc);
|
||||
if (status != 0) {
|
||||
log_error("[DKM] driver_desc rejected");
|
||||
return status;
|
||||
}
|
||||
|
||||
dkm_driver_handle handle;
|
||||
handle.desc = driver->desc;
|
||||
handle.state = DKM_STATE_ABI_CHECKED;
|
||||
handle.init_status = 0;
|
||||
handle.load_stage = driver->desc->stage;
|
||||
handle.flags = driver->desc->flags;
|
||||
|
||||
log_info("[DKM] builtin driver init begin");
|
||||
log_info(driver->desc->name);
|
||||
handle.state = DKM_STATE_INITING;
|
||||
status = driver->init(dkm_get_kernel_api(), &handle);
|
||||
handle.init_status = status;
|
||||
|
||||
if (status != 0) {
|
||||
handle.state = DKM_STATE_FAILED;
|
||||
log_error("[DKM] builtin driver init failed");
|
||||
return status;
|
||||
}
|
||||
|
||||
handle.state = DKM_STATE_ACTIVE;
|
||||
log_info("[DKM] builtin driver active");
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,90 @@
|
||||
#include <utsm/dkm.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/idt.h>
|
||||
#include <utsm/net.h>
|
||||
|
||||
static void dkm_api_info(const char *msg) {
|
||||
log_info(msg);
|
||||
}
|
||||
|
||||
static void dkm_api_warn(const char *msg) {
|
||||
log_warn(msg);
|
||||
}
|
||||
|
||||
static void dkm_api_error(const char *msg) {
|
||||
log_error(msg);
|
||||
}
|
||||
|
||||
static void dkm_api_panic(const char *msg) {
|
||||
log_error(msg);
|
||||
for (;;) {
|
||||
__asm__ volatile("cli; hlt");
|
||||
}
|
||||
}
|
||||
|
||||
static const dkm_log_api g_log_api = {
|
||||
.info = dkm_api_info,
|
||||
.warn = dkm_api_warn,
|
||||
.error = dkm_api_error,
|
||||
.panic = dkm_api_panic
|
||||
};
|
||||
|
||||
static dkm_kernel_api g_kernel_api = {
|
||||
.version = DKM_KERNEL_API_VERSION,
|
||||
.size = sizeof(dkm_kernel_api),
|
||||
.feature_bits = 0,
|
||||
.log = &g_log_api,
|
||||
.mem = 0,
|
||||
.utsm = 0,
|
||||
.irq = 0,
|
||||
.pci = 0,
|
||||
.dma = 0,
|
||||
.vfs = 0,
|
||||
.net = 0,
|
||||
.timer = 0,
|
||||
.drr = 0,
|
||||
.rsdp_address = 0,
|
||||
.fb_address = 0,
|
||||
.fb_width = 0,
|
||||
.fb_height = 0,
|
||||
.fb_pitch = 0,
|
||||
.fb_bpp = 0,
|
||||
.boot_modules_response = 0,
|
||||
.irq_register = 0,
|
||||
.hhdm_offset = 0,
|
||||
.block = 0
|
||||
};
|
||||
|
||||
const dkm_kernel_api *dkm_get_kernel_api(void) {
|
||||
return &g_kernel_api;
|
||||
}
|
||||
|
||||
#include "../arch/x86_64/limine.h"
|
||||
extern volatile struct limine_rsdp_request g_rsdp_request;
|
||||
extern volatile struct limine_framebuffer_request g_fb_request;
|
||||
extern volatile struct limine_module_request g_module_request;
|
||||
extern volatile struct limine_hhdm_request g_hhdm_request;
|
||||
|
||||
void dkm_fill_platform_info(void) {
|
||||
g_kernel_api.dma = dma_get_api();
|
||||
g_kernel_api.net = net_get_api();
|
||||
g_kernel_api.block = block_get_api();
|
||||
if (g_rsdp_request.response && g_rsdp_request.response->address) {
|
||||
g_kernel_api.rsdp_address = g_rsdp_request.response->address;
|
||||
}
|
||||
if (g_fb_request.response && g_fb_request.response->framebuffer_count > 0) {
|
||||
struct limine_framebuffer *fb = g_fb_request.response->framebuffers[0];
|
||||
g_kernel_api.fb_address = fb->address;
|
||||
g_kernel_api.fb_width = fb->width;
|
||||
g_kernel_api.fb_height = fb->height;
|
||||
g_kernel_api.fb_pitch = fb->pitch;
|
||||
g_kernel_api.fb_bpp = fb->bpp;
|
||||
}
|
||||
if (g_module_request.response) {
|
||||
g_kernel_api.boot_modules_response = g_module_request.response;
|
||||
}
|
||||
g_kernel_api.irq_register = (int (*)(u8,void*))((u64)irq_register);
|
||||
if (g_hhdm_request.response) {
|
||||
g_kernel_api.hhdm_offset = g_hhdm_request.response->offset;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,359 @@
|
||||
#include <utsm/dkm.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/types.h>
|
||||
#include "../arch/x86_64/limine.h"
|
||||
|
||||
#define DSM_MAX_DRIVERS_PER_STAGE 8
|
||||
#define DSM_MAX_STAGES 4
|
||||
#define DSM_MAX_DEPENDS 4
|
||||
#define DSM_MAX_PROVIDES 4
|
||||
|
||||
typedef struct dsm_driver_entry {
|
||||
char name[32];
|
||||
char path[64];
|
||||
u32 class_id;
|
||||
u32 required;
|
||||
char depends[DSM_MAX_DEPENDS][32];
|
||||
u32 depend_count;
|
||||
char provides[DSM_MAX_PROVIDES][32];
|
||||
u32 provide_count;
|
||||
struct limine_file *boot_module;
|
||||
int loaded;
|
||||
} dsm_driver_entry;
|
||||
|
||||
typedef struct dsm_stage_entry {
|
||||
u32 id;
|
||||
char name[16];
|
||||
u32 required;
|
||||
dsm_driver_entry drivers[DSM_MAX_DRIVERS_PER_STAGE];
|
||||
u32 driver_count;
|
||||
} dsm_stage_entry;
|
||||
|
||||
static dsm_stage_entry g_stages[DSM_MAX_STAGES];
|
||||
static u32 g_stage_count;
|
||||
|
||||
extern volatile struct limine_module_request g_module_request;
|
||||
|
||||
static int dsm_skip_ws(const char **p) {
|
||||
while (**p == ' ' || **p == '\t' || **p == '\n' || **p == '\r') { (*p)++; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsm_expect(const char **p, char c) {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == c) { (*p)++; return 0; }
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int dsm_read_string(const char **p, char *out, u32 max_len) {
|
||||
dsm_skip_ws(p);
|
||||
if (**p != '"') return -1;
|
||||
(*p)++;
|
||||
u32 i = 0;
|
||||
while (**p && **p != '"' && i + 1 < max_len) {
|
||||
out[i++] = **p;
|
||||
(*p)++;
|
||||
}
|
||||
out[i] = 0;
|
||||
if (**p != '"') return -1;
|
||||
(*p)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsm_skip_value(const char **p) {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == '"') {
|
||||
char tmp[256];
|
||||
return dsm_read_string(p, tmp, sizeof(tmp));
|
||||
}
|
||||
if (**p == '{') {
|
||||
(*p)++;
|
||||
int depth = 1;
|
||||
while (depth > 0 && **p) {
|
||||
if (**p == '{') depth++;
|
||||
else if (**p == '}') depth--;
|
||||
else if (**p == '"') { (*p)++; while (**p && **p != '"') (*p)++; if (**p) (*p)++; continue; }
|
||||
if (depth > 0) (*p)++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (**p == '[') {
|
||||
(*p)++;
|
||||
int depth = 1;
|
||||
while (depth > 0 && **p) {
|
||||
if (**p == '[') depth++;
|
||||
else if (**p == ']') depth--;
|
||||
else if (**p == '"') { (*p)++; while (**p && **p != '"') (*p)++; if (**p) (*p)++; continue; }
|
||||
if (depth > 0) (*p)++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
while (**p && **p != ',' && **p != '}' && **p != ']') (*p)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct limine_file *dsm_find_boot_module(const char *path) {
|
||||
struct limine_module_response *rsp = g_module_request.response;
|
||||
if (!rsp) return 0;
|
||||
for (u64 i = 0; i < rsp->module_count; i++) {
|
||||
struct limine_file *f = rsp->modules[i];
|
||||
if (f && f->path) {
|
||||
const char *fp = f->path;
|
||||
while (*fp == '/') fp++;
|
||||
usize j = 0;
|
||||
usize k = 0;
|
||||
while (fp[j]) j++;
|
||||
while (path[k]) k++;
|
||||
if (j == k) {
|
||||
int match = 1;
|
||||
for (usize x = 0; x < j; x++) {
|
||||
if (fp[x] != path[x]) { match = 0; break; }
|
||||
}
|
||||
if (match) return f;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int streq_static(const char *a, const char *b) {
|
||||
usize i = 0;
|
||||
while (a[i] && b[i]) {
|
||||
if (a[i] != b[i]) return 0;
|
||||
i++;
|
||||
}
|
||||
return a[i] == b[i];
|
||||
}
|
||||
|
||||
static void dsm_parse_driver(const char **p, dsm_driver_entry *drv) {
|
||||
drv->depend_count = 0;
|
||||
drv->provide_count = 0;
|
||||
drv->required = 1;
|
||||
drv->boot_module = 0;
|
||||
drv->loaded = 0;
|
||||
drv->class_id = 0;
|
||||
|
||||
if (dsm_expect(p, '{') != 0) return;
|
||||
while (**p && **p != '}') {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == '}') break;
|
||||
char key[32];
|
||||
if (dsm_read_string(p, key, sizeof(key)) != 0) return;
|
||||
dsm_expect(p, ':');
|
||||
|
||||
if (streq_static(key, "name")) {
|
||||
dsm_read_string(p, drv->name, sizeof(drv->name));
|
||||
} else if (streq_static(key, "path")) {
|
||||
dsm_read_string(p, drv->path, sizeof(drv->path));
|
||||
} else if (streq_static(key, "class")) {
|
||||
char cls[32];
|
||||
dsm_read_string(p, cls, sizeof(cls));
|
||||
if (streq_static(cls, "platform")) drv->class_id = 1;
|
||||
else if (streq_static(cls, "bus")) drv->class_id = 2;
|
||||
else if (streq_static(cls, "interrupt")) drv->class_id = 3;
|
||||
else if (streq_static(cls, "timer")) drv->class_id = 4;
|
||||
else if (streq_static(cls, "console")) drv->class_id = 5;
|
||||
else if (streq_static(cls, "storage")) drv->class_id = 6;
|
||||
else if (streq_static(cls, "fs")) drv->class_id = 7;
|
||||
else if (streq_static(cls, "fs-core")) drv->class_id = 8;
|
||||
else if (streq_static(cls, "net")) drv->class_id = 9;
|
||||
else if (streq_static(cls, "input")) drv->class_id = 10;
|
||||
} else if (streq_static(key, "required")) {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == 't') { drv->required = 1; (*p) += 4; }
|
||||
else if (**p == 'f') { drv->required = 0; (*p) += 5; }
|
||||
} else if (streq_static(key, "depends")) {
|
||||
if (dsm_expect(p, '[') != 0) return;
|
||||
while (**p && **p != ']') {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ']') break;
|
||||
if (drv->depend_count < DSM_MAX_DEPENDS) {
|
||||
dsm_read_string(p, drv->depends[drv->depend_count], 32);
|
||||
drv->depend_count++;
|
||||
} else { dsm_skip_value(p); }
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ',') { (*p)++; continue; }
|
||||
if (**p == ']') break;
|
||||
}
|
||||
dsm_expect(p, ']');
|
||||
} else if (streq_static(key, "provides")) {
|
||||
if (dsm_expect(p, '[') != 0) return;
|
||||
while (**p && **p != ']') {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ']') break;
|
||||
if (drv->provide_count < DSM_MAX_PROVIDES) {
|
||||
dsm_read_string(p, drv->provides[drv->provide_count], 32);
|
||||
drv->provide_count++;
|
||||
} else { dsm_skip_value(p); }
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ',') { (*p)++; continue; }
|
||||
if (**p == ']') break;
|
||||
}
|
||||
dsm_expect(p, ']');
|
||||
} else {
|
||||
dsm_skip_value(p);
|
||||
}
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ',') (*p)++;
|
||||
}
|
||||
dsm_expect(p, '}');
|
||||
}
|
||||
|
||||
static void dsm_parse_stage(const char **p, dsm_stage_entry *stage) {
|
||||
stage->driver_count = 0;
|
||||
if (dsm_expect(p, '{') != 0) return;
|
||||
while (**p && **p != '}') {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == '}') break;
|
||||
char key[32];
|
||||
if (dsm_read_string(p, key, sizeof(key)) != 0) return;
|
||||
dsm_expect(p, ':');
|
||||
|
||||
if (streq_static(key, "id")) {
|
||||
dsm_skip_ws(p);
|
||||
u32 val = 0;
|
||||
while (**p >= '0' && **p <= '9') { val = val * 10 + (u32)(**p - '0'); (*p)++; }
|
||||
stage->id = val;
|
||||
} else if (streq_static(key, "name")) {
|
||||
dsm_read_string(p, stage->name, sizeof(stage->name));
|
||||
} else if (streq_static(key, "required")) {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == 't') { stage->required = 1; (*p) += 4; }
|
||||
else if (**p == 'f') { stage->required = 0; (*p) += 5; }
|
||||
} else if (streq_static(key, "drivers")) {
|
||||
if (dsm_expect(p, '[') != 0) return;
|
||||
while (**p && **p != ']') {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ']') break;
|
||||
if (stage->driver_count < DSM_MAX_DRIVERS_PER_STAGE) {
|
||||
dsm_parse_driver(p, &stage->drivers[stage->driver_count]);
|
||||
stage->driver_count++;
|
||||
} else {
|
||||
dsm_skip_value(p);
|
||||
}
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ',') { (*p)++; continue; }
|
||||
if (**p == ']') break;
|
||||
}
|
||||
dsm_expect(p, ']');
|
||||
} else {
|
||||
dsm_skip_value(p);
|
||||
}
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ',') (*p)++;
|
||||
}
|
||||
dsm_expect(p, '}');
|
||||
}
|
||||
|
||||
static int dsm_parse_manifest(const char *text, u64 size) {
|
||||
g_stage_count = 0;
|
||||
const char *p = text;
|
||||
const char *end = text + size;
|
||||
|
||||
while (p < end && *p) {
|
||||
dsm_skip_ws(&p);
|
||||
if (p >= end || !*p) break;
|
||||
if (*p == '{' || *p == '}') { p++; continue; }
|
||||
if (*p == ',' || *p == ':') { p++; continue; }
|
||||
if (*p == '[' || *p == ']') { p++; continue; }
|
||||
|
||||
char key[32];
|
||||
if (dsm_read_string(&p, key, sizeof(key)) != 0) break;
|
||||
dsm_expect(&p, ':');
|
||||
|
||||
if (streq_static(key, "stages")) {
|
||||
if (dsm_expect(&p, '[') != 0) return -1;
|
||||
while (p < end && *p) {
|
||||
dsm_skip_ws(&p);
|
||||
if (*p == ']') { p++; break; }
|
||||
if (g_stage_count < DSM_MAX_STAGES) {
|
||||
dsm_parse_stage(&p, &g_stages[g_stage_count]);
|
||||
g_stage_count++;
|
||||
}
|
||||
dsm_skip_ws(&p);
|
||||
if (*p == ',') p++;
|
||||
}
|
||||
} else {
|
||||
dsm_skip_value(&p);
|
||||
}
|
||||
dsm_skip_ws(&p);
|
||||
if (*p == ',' || *p == '}' || *p == ']') p++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dsm_load_by_manifest(void) {
|
||||
struct limine_module_response *rsp = g_module_request.response;
|
||||
if (!rsp) {
|
||||
log_warn("[DSM] no Limine module response");
|
||||
return;
|
||||
}
|
||||
|
||||
struct limine_file *manifest_file = 0;
|
||||
for (u64 i = 0; i < rsp->module_count; i++) {
|
||||
struct limine_file *f = rsp->modules[i];
|
||||
if (f && f->path && f->cmdline && streq_static(f->cmdline, "dkm:manifest")) {
|
||||
manifest_file = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!manifest_file) {
|
||||
log_warn("[DSM] manifest not found in boot modules");
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("[DSM] parsing manifest");
|
||||
dsm_parse_manifest((const char *)manifest_file->address, manifest_file->size);
|
||||
log_info("[DSM] manifest parsed");
|
||||
log_hex64("[DSM] stages=", (u64)g_stage_count);
|
||||
|
||||
for (u32 si = 0; si < g_stage_count; si++) {
|
||||
dsm_stage_entry *stage = &g_stages[si];
|
||||
log_info("[DSM] stage begin");
|
||||
log_info(stage->name);
|
||||
log_hex64("[DSM] driver count=", stage->driver_count);
|
||||
|
||||
for (u32 di = 0; di < stage->driver_count; di++) {
|
||||
dsm_driver_entry *drv = &stage->drivers[di];
|
||||
|
||||
drv->boot_module = dsm_find_boot_module(drv->path);
|
||||
if (!drv->boot_module) {
|
||||
log_info("[DSM] module not found");
|
||||
log_info(drv->name);
|
||||
if (drv->required && stage->required) {
|
||||
log_error("[DSM] required module missing, abort stage");
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
struct limine_file *f = drv->boot_module;
|
||||
log_info("[DSM] loading driver");
|
||||
log_info(drv->name);
|
||||
|
||||
if (dkm_check_elf64(f->address, f->size) != 0) {
|
||||
log_error("[DSM] ELF check failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
struct dkm_symbol_scan symbols;
|
||||
if (dkm_scan_symbols(f->address, f->size, &symbols) != 0) {
|
||||
log_error("[DSM] symbol scan failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
int result = dkm_load_elf_rel(f->address, f->size, &symbols);
|
||||
if (result != 0) {
|
||||
log_error("[DSM] load failed");
|
||||
if (drv->required && stage->required) {
|
||||
log_error("[DSM] required driver failed, abort stage");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
drv->loaded = 1;
|
||||
}
|
||||
}
|
||||
log_info("[DSM] stage end");
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,37 @@
|
||||
#include <utsm/drr.h>
|
||||
#include <utsm/log.h>
|
||||
|
||||
static const u64 g_root_key[4] = {
|
||||
0x4452525554534d31ULL,
|
||||
0xfeedfacecafebeefULL,
|
||||
0x0123456789abcdefULL,
|
||||
0xfedcba9876543210ULL
|
||||
};
|
||||
|
||||
void drr_stub_init(void) {
|
||||
}
|
||||
|
||||
const u64 *drr_get_root_key(void) {
|
||||
return g_root_key;
|
||||
}
|
||||
|
||||
u64 drr_recovery_generation(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void drr_report_fault(const char *reason) {
|
||||
log_error("[DRR] fault reported");
|
||||
log_error(reason);
|
||||
}
|
||||
|
||||
void drr_log_write_intent(u32 segment_slot, u64 offset, u64 len) {
|
||||
UTSM_UNUSED(segment_slot);
|
||||
UTSM_UNUSED(offset);
|
||||
UTSM_UNUSED(len);
|
||||
}
|
||||
|
||||
void drr_log_write_commit(u32 segment_slot, u64 offset, u64 len) {
|
||||
UTSM_UNUSED(segment_slot);
|
||||
UTSM_UNUSED(offset);
|
||||
UTSM_UNUSED(len);
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,13 @@
|
||||
#ifndef UTSM_ARENA_H
|
||||
#define UTSM_ARENA_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
void arena_init(void);
|
||||
void *kmem_alloc(u64 size);
|
||||
void *kmem_alloc_aligned(u64 size, u64 alignment);
|
||||
void *kmem_alloc_page(u64 page_count);
|
||||
u64 kmem_arena_virtual_base(void);
|
||||
u64 kmem_arena_virtual_end(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef UTSM_ASSERT_H
|
||||
#define UTSM_ASSERT_H
|
||||
|
||||
#include <utsm/log.h>
|
||||
|
||||
#define UTSM_ASSERT(cond) do { if (!(cond)) { panic("assertion failed: " #cond); } } while (0)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef UTSM_BLOCK_H
|
||||
#define UTSM_BLOCK_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
#define DKM_BLOCK_MAX_DEVICES 8u
|
||||
|
||||
typedef int (*dkm_block_read_fn)(void *ctx, u64 lba, u32 count, void *buffer);
|
||||
|
||||
typedef struct dkm_block_device_desc {
|
||||
const char *name;
|
||||
u64 sector_size;
|
||||
u64 sector_count;
|
||||
void *ctx;
|
||||
dkm_block_read_fn read;
|
||||
} dkm_block_device_desc;
|
||||
|
||||
typedef struct dkm_block_api {
|
||||
int (*register_device)(const dkm_block_device_desc *desc);
|
||||
u32 (*device_count)(void);
|
||||
int (*read)(u32 index, u64 lba, u32 count, void *buffer);
|
||||
u64 (*sector_size)(u32 index);
|
||||
const char *(*device_name)(u32 index);
|
||||
} dkm_block_api;
|
||||
|
||||
void block_init(void);
|
||||
const dkm_block_api *block_get_api(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef UTSM_CAPABILITY_H
|
||||
#define UTSM_CAPABILITY_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
#include <utsm/status.h>
|
||||
|
||||
#define UTSM_RIGHT_READ (1U << 0)
|
||||
#define UTSM_RIGHT_WRITE (1U << 1)
|
||||
#define UTSM_RIGHT_EXEC (1U << 2)
|
||||
#define UTSM_RIGHT_SHARE (1U << 3)
|
||||
#define UTSM_RIGHT_DMA (1U << 4)
|
||||
|
||||
struct utsm_segment_desc;
|
||||
|
||||
typedef struct {
|
||||
u32 segment_slot;
|
||||
u32 generation;
|
||||
u32 rights;
|
||||
u32 epoch;
|
||||
u64 uuid_digest;
|
||||
u64 auth_tag;
|
||||
} utsm_capability;
|
||||
|
||||
int utsm_cap_validate(utsm_capability cap, u32 required_rights, u64 offset, u64 len, struct utsm_segment_desc **out_desc);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef UTSM_CONFIG_H
|
||||
#define UTSM_CONFIG_H
|
||||
|
||||
#define UTSM_CACHE_LINE_SIZE 64ULL
|
||||
#define UTSM_PAGE_SIZE 4096ULL
|
||||
#define UTSM_MAX_SEGMENTS 1024U
|
||||
#define UTSM_MAX_CAPABILITIES 256U
|
||||
#define UTSM_MAX_PCKC_KEYS 8U
|
||||
#define UTSM_ARENA_SIZE (16ULL * 1024ULL * 1024ULL)
|
||||
#define UTSM_DIRTY_SHARD_PAGES 1024ULL
|
||||
#define UTSM_KERNEL_STACK_SIZE 16384ULL
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef UTSM_CRYPTO_H
|
||||
#define UTSM_CRYPTO_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
#include <utsm/uuid.h>
|
||||
|
||||
struct utsm_segment_desc;
|
||||
|
||||
typedef struct {
|
||||
u64 words[4];
|
||||
} utsm_key_material;
|
||||
|
||||
void utsm_kdf_segment_key(uuid128_t process_uuid, uuid128_t segment_uuid, u64 key_epoch, utsm_key_material *out_key);
|
||||
u64 utsm_make_tweak(u64 tweak_seed, u64 line_index, u64 key_epoch);
|
||||
void utsm_crypt_line(const utsm_key_material *key, u64 tweak, const u8 *in, u8 *out);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef UTSM_DIRTY_H
|
||||
#define UTSM_DIRTY_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
typedef struct {
|
||||
u32 dirty_count;
|
||||
u32 shard_id;
|
||||
u64 page_base;
|
||||
u64 page_count;
|
||||
u64 last_checkpoint_epoch;
|
||||
u64 *bitmap;
|
||||
} utsm_dirty_shard;
|
||||
|
||||
struct utsm_segment_desc;
|
||||
|
||||
void utsm_dirty_init(struct utsm_segment_desc *desc, u64 page_count);
|
||||
void utsm_mark_dirty(struct utsm_segment_desc *desc, u64 offset, u64 len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,141 @@
|
||||
#ifndef UTSM_DKM_H
|
||||
#define UTSM_DKM_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
#include <utsm/dma.h>
|
||||
#include <utsm/block.h>
|
||||
#include <utsm/net.h>
|
||||
|
||||
#define DKM_DRIVER_MAGIC 0x444B4D31u
|
||||
#define DKM_ABI_VERSION 1u
|
||||
#define DKM_KERNEL_API_VERSION 1u
|
||||
|
||||
#define DKM_CLASS_PLATFORM 1u
|
||||
#define DKM_CLASS_BUS 2u
|
||||
#define DKM_CLASS_INTERRUPT 3u
|
||||
#define DKM_CLASS_TIMER 4u
|
||||
#define DKM_CLASS_CONSOLE 5u
|
||||
#define DKM_CLASS_STORAGE 6u
|
||||
#define DKM_CLASS_FS 7u
|
||||
#define DKM_CLASS_NET 8u
|
||||
#define DKM_CLASS_INPUT 9u
|
||||
#define DKM_CLASS_GPU 10u
|
||||
#define DKM_CLASS_MISC 11u
|
||||
|
||||
#define DKM_F_REQUIRED (1u << 0)
|
||||
#define DKM_F_BOOT_MODULE (1u << 1)
|
||||
#define DKM_F_NO_UNLOAD (1u << 2)
|
||||
#define DKM_F_STRONG_RECOVERY (1u << 3)
|
||||
#define DKM_F_DMA_REQUIRED (1u << 4)
|
||||
#define DKM_F_EARLY_LOG (1u << 5)
|
||||
|
||||
struct dkm_kernel_api;
|
||||
struct dkm_driver_handle;
|
||||
|
||||
typedef struct dkm_driver_desc {
|
||||
u32 magic;
|
||||
u16 abi_version;
|
||||
u16 desc_size;
|
||||
|
||||
const char *name;
|
||||
const char *version;
|
||||
const char *vendor;
|
||||
|
||||
u32 driver_class;
|
||||
u32 stage;
|
||||
u32 flags;
|
||||
u32 priority;
|
||||
|
||||
const char *const *depends;
|
||||
u32 depends_count;
|
||||
|
||||
const char *const *provides;
|
||||
u32 provides_count;
|
||||
|
||||
u64 min_kernel_abi;
|
||||
u64 feature_bits;
|
||||
|
||||
u64 reserved0;
|
||||
u64 reserved1;
|
||||
} dkm_driver_desc;
|
||||
|
||||
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);
|
||||
|
||||
typedef struct dkm_log_api {
|
||||
void (*info)(const char *msg);
|
||||
void (*warn)(const char *msg);
|
||||
void (*error)(const char *msg);
|
||||
void (*panic)(const char *msg);
|
||||
} dkm_log_api;
|
||||
|
||||
typedef struct dkm_kernel_api {
|
||||
u32 version;
|
||||
u32 size;
|
||||
u64 feature_bits;
|
||||
|
||||
const dkm_log_api *log;
|
||||
const void *mem;
|
||||
const void *utsm;
|
||||
const void *irq;
|
||||
const void *pci;
|
||||
const dkm_dma_api *dma;
|
||||
const void *vfs;
|
||||
const dkm_net_api *net;
|
||||
const void *timer;
|
||||
const void *drr;
|
||||
|
||||
const void *rsdp_address; /* ACPI RSDP physical address */
|
||||
const void *fb_address; /* framebuffer base */
|
||||
u64 fb_width;
|
||||
u64 fb_height;
|
||||
u64 fb_pitch;
|
||||
u16 fb_bpp;
|
||||
const void *boot_modules_response; /* limine_module_response* */
|
||||
int (*irq_register)(u8 irq, void *handler); /* kernel irq_register */
|
||||
u64 hhdm_offset; /* physical → virtual */
|
||||
const dkm_block_api *block; /* block provider registry */
|
||||
} dkm_kernel_api;
|
||||
|
||||
typedef enum dkm_driver_state {
|
||||
DKM_STATE_DISCOVERED = 0,
|
||||
DKM_STATE_ABI_CHECKED,
|
||||
DKM_STATE_INITING,
|
||||
DKM_STATE_ACTIVE,
|
||||
DKM_STATE_FAILED
|
||||
} dkm_driver_state;
|
||||
|
||||
typedef struct dkm_driver_handle {
|
||||
const dkm_driver_desc *desc;
|
||||
dkm_driver_state state;
|
||||
i32 init_status;
|
||||
u32 load_stage;
|
||||
u32 flags;
|
||||
} dkm_driver_handle;
|
||||
|
||||
typedef struct dkm_builtin_driver {
|
||||
const dkm_driver_desc *desc;
|
||||
dkm_driver_init_fn init;
|
||||
dkm_driver_exit_fn exit;
|
||||
} dkm_builtin_driver;
|
||||
|
||||
void dkm_init(void);
|
||||
int dkm_load_builtin(const dkm_builtin_driver *driver);
|
||||
void dkm_scan_boot_modules(void);
|
||||
void dsm_load_by_manifest(void);
|
||||
void dkm_fill_platform_info(void);
|
||||
const dkm_kernel_api *dkm_get_kernel_api(void);
|
||||
|
||||
/* exposed for manifest parser */
|
||||
struct dkm_symbol_scan {
|
||||
const void *driver_desc;
|
||||
const void *driver_init;
|
||||
const void *driver_exit;
|
||||
};
|
||||
int dkm_check_elf64(const void *address, u64 size);
|
||||
int dkm_scan_symbols(const void *address, u64 size, struct dkm_symbol_scan *out);
|
||||
int dkm_load_elf_rel(const void *address, u64 size, const struct dkm_symbol_scan *symbols);
|
||||
|
||||
extern const dkm_builtin_driver dkm_builtin_console_early;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef UTSM_DMA_H
|
||||
#define UTSM_DMA_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
typedef struct dkm_dma_buffer {
|
||||
void *virt;
|
||||
u64 phys;
|
||||
u64 size;
|
||||
} dkm_dma_buffer;
|
||||
|
||||
typedef struct dkm_dma_api {
|
||||
int (*alloc_pages)(u64 page_count, u64 alignment, u64 max_phys, dkm_dma_buffer *out);
|
||||
} dkm_dma_api;
|
||||
|
||||
void dma_init(void);
|
||||
int dma_alloc_pages(u64 page_count, u64 alignment, u64 max_phys, dkm_dma_buffer *out);
|
||||
const dkm_dma_api *dma_get_api(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef UTSM_DMP_H
|
||||
#define UTSM_DMP_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
typedef struct {
|
||||
u64 magic;
|
||||
u32 version;
|
||||
u32 segment_slot;
|
||||
u64 fast_base;
|
||||
u64 fast_limit;
|
||||
u64 fast_tweak_seed;
|
||||
u64 fast_key_epoch;
|
||||
u64 dirty_bitmap_base;
|
||||
u64 mac_table_base;
|
||||
u64 last_writer_seq;
|
||||
u32 last_cpu;
|
||||
u32 flags;
|
||||
u64 crc;
|
||||
} utsm_dmp;
|
||||
|
||||
struct utsm_segment_desc;
|
||||
|
||||
void utsm_dmp_init(utsm_dmp *dmp, struct utsm_segment_desc *desc, u32 slot);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef UTSM_DRR_H
|
||||
#define UTSM_DRR_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
void drr_stub_init(void);
|
||||
const u64 *drr_get_root_key(void);
|
||||
u64 drr_recovery_generation(void);
|
||||
void drr_report_fault(const char *reason);
|
||||
void drr_log_write_intent(u32 segment_slot, u64 offset, u64 len);
|
||||
void drr_log_write_commit(u32 segment_slot, u64 offset, u64 len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef UTSM_DSK_H
|
||||
#define UTSM_DSK_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
#define DSK_BOOT_MAGIC 0x44534B31424F4F54ULL /* "DSK1BOOT" */
|
||||
#define DSK_BOOT_ABI_VERSION 1u
|
||||
|
||||
#define DSK_BOOT_FLAG_FROM_UTSM (1ULL << 0)
|
||||
#define DSK_BOOT_FLAG_DKM_READY (1ULL << 1)
|
||||
#define DSK_BOOT_FLAG_FAT32_PATH (1ULL << 2)
|
||||
|
||||
typedef struct dsk_boot_context {
|
||||
u64 magic;
|
||||
u32 abi_version;
|
||||
u32 size;
|
||||
|
||||
u64 flags;
|
||||
|
||||
u64 hhdm_offset;
|
||||
u64 rsdp_address;
|
||||
|
||||
u64 framebuffer_address;
|
||||
u64 framebuffer_width;
|
||||
u64 framebuffer_height;
|
||||
u64 framebuffer_pitch;
|
||||
u32 framebuffer_bpp;
|
||||
u32 reserved_fb;
|
||||
|
||||
u64 boot_modules_response;
|
||||
|
||||
u64 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;
|
||||
u64 reserved[8];
|
||||
} dsk_boot_context;
|
||||
|
||||
typedef void (*dsk_entry_fn)(const dsk_boot_context *context);
|
||||
|
||||
int dsk_load_and_jump(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef UTSM_IDT_H
|
||||
#define UTSM_IDT_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
void idt_init(void);
|
||||
|
||||
/* IRQ handler: return 1 to suppress default ACK, 0 for normal EOI */
|
||||
typedef int (*irq_handler_t)(u8 irq);
|
||||
int irq_register(u8 irq, irq_handler_t handler);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef UTSM_LOG_H
|
||||
#define UTSM_LOG_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
void serial_init(void);
|
||||
void serial_putc(char c);
|
||||
void serial_write(const char *s);
|
||||
|
||||
void log_info(const char *msg);
|
||||
void log_warn(const char *msg);
|
||||
void log_error(const char *msg);
|
||||
void log_hex64(const char *prefix, u64 value);
|
||||
void panic(const char *msg);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef UTSM_NET_H
|
||||
#define UTSM_NET_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
#define DKM_NET_MAX_DEVICES 8u
|
||||
|
||||
/* 网卡链路/能力标志。 */
|
||||
#define DKM_NET_F_LINK_UP (1u << 0)
|
||||
#define DKM_NET_F_TX_READY (1u << 1)
|
||||
#define DKM_NET_F_RX_READY (1u << 2)
|
||||
|
||||
typedef int (*dkm_net_tx_fn)(void *ctx, const void *packet, u32 length);
|
||||
typedef int (*dkm_net_rx_poll_fn)(void *ctx, void *buffer, u32 capacity, u32 *out_length);
|
||||
|
||||
typedef struct dkm_net_device_desc {
|
||||
const char *name;
|
||||
u8 mac[6];
|
||||
u32 flags;
|
||||
void *ctx;
|
||||
dkm_net_tx_fn tx;
|
||||
dkm_net_rx_poll_fn rx_poll;
|
||||
} dkm_net_device_desc;
|
||||
|
||||
typedef struct dkm_net_device_info {
|
||||
const char *name;
|
||||
u8 mac[6];
|
||||
u32 flags;
|
||||
} dkm_net_device_info;
|
||||
|
||||
typedef struct dkm_net_api {
|
||||
int (*register_device)(const dkm_net_device_desc *desc);
|
||||
u32 (*device_count)(void);
|
||||
int (*device_info)(u32 index, dkm_net_device_info *out);
|
||||
int (*tx)(u32 index, const void *packet, u32 length);
|
||||
int (*rx_poll)(u32 index, void *buffer, u32 capacity, u32 *out_length);
|
||||
} dkm_net_api;
|
||||
|
||||
void net_init(void);
|
||||
const dkm_net_api *net_get_api(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef UTSM_PCKC_H
|
||||
#define UTSM_PCKC_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
#include <utsm/config.h>
|
||||
#include <utsm/uuid.h>
|
||||
#include <utsm/crypto.h>
|
||||
|
||||
struct utsm_segment_desc;
|
||||
|
||||
typedef struct {
|
||||
bool valid;
|
||||
u32 segment_slot;
|
||||
u64 key_epoch;
|
||||
utsm_key_material key;
|
||||
} utsm_pckc_entry;
|
||||
|
||||
typedef struct {
|
||||
uuid128_t current_process_uuid;
|
||||
utsm_pckc_entry entries[UTSM_MAX_PCKC_KEYS];
|
||||
u64 hit_count;
|
||||
u64 miss_count;
|
||||
u32 next_replace;
|
||||
} utsm_pckc;
|
||||
|
||||
void utsm_pckc_init(void);
|
||||
int utsm_pckc_get_or_derive(u32 segment_slot, struct utsm_segment_desc *desc, utsm_key_material *out_key);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef UTSM_PROCESS_H
|
||||
#define UTSM_PROCESS_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
#include <utsm/uuid.h>
|
||||
|
||||
typedef struct utsm_process_context {
|
||||
uuid128_t process_uuid;
|
||||
u64 crypto_epoch;
|
||||
u64 recovery_generation;
|
||||
u32 capability_table_slot;
|
||||
u32 capability_count;
|
||||
u32 flags;
|
||||
} utsm_process_context;
|
||||
|
||||
void utsm_process_create_test(utsm_process_context *process, u64 seed);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef UTSM_SEGMENT_H
|
||||
#define UTSM_SEGMENT_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
#include <utsm/uuid.h>
|
||||
#include <utsm/status.h>
|
||||
#include <utsm/capability.h>
|
||||
#include <utsm/dirty.h>
|
||||
|
||||
typedef enum {
|
||||
UTSM_SEG_FREE = 0,
|
||||
UTSM_SEG_ACTIVE,
|
||||
UTSM_SEG_CHECKPOINTING,
|
||||
UTSM_SEG_SEALED,
|
||||
UTSM_SEG_RECOVERING,
|
||||
UTSM_SEG_POISONED,
|
||||
UTSM_SEG_DESTROYED
|
||||
} utsm_segment_state;
|
||||
|
||||
#define UTSM_SEG_F_READ (1U << 0)
|
||||
#define UTSM_SEG_F_WRITE (1U << 1)
|
||||
#define UTSM_SEG_F_EXEC (1U << 2)
|
||||
#define UTSM_SEG_F_DMA (1U << 3)
|
||||
#define UTSM_SEG_F_STRONG_RECOVERY (1U << 4)
|
||||
|
||||
typedef struct utsm_segment_desc {
|
||||
uuid128_t segment_uuid;
|
||||
uuid128_t owner_process_uuid;
|
||||
u8 *cipher_base;
|
||||
u64 cipher_length;
|
||||
void *dmp_base;
|
||||
u64 key_epoch;
|
||||
u64 tweak_seed;
|
||||
utsm_dirty_shard *dirty_shards;
|
||||
u32 dirty_shard_count;
|
||||
void *mac_table;
|
||||
u32 generation;
|
||||
u32 flags;
|
||||
u32 state;
|
||||
u32 last_cpu;
|
||||
volatile u64 writer_seq;
|
||||
u64 checkpoint_generation;
|
||||
} utsm_segment_desc;
|
||||
|
||||
struct utsm_process_context;
|
||||
|
||||
int utsm_create_segment(struct utsm_process_context *process, u64 size, u32 flags, utsm_capability *out_cap);
|
||||
utsm_segment_desc *utsm_get_segment(u32 slot);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef UTSM_STATUS_H
|
||||
#define UTSM_STATUS_H
|
||||
|
||||
typedef enum {
|
||||
UTSM_OK = 0,
|
||||
UTSM_ERR_INVALID = -1,
|
||||
UTSM_ERR_NO_MEMORY = -2,
|
||||
UTSM_ERR_ACCESS = -3,
|
||||
UTSM_ERR_BOUNDS = -4,
|
||||
UTSM_ERR_STALE_CAP = -5,
|
||||
UTSM_ERR_EPOCH = -6,
|
||||
UTSM_ERR_KEY_MISS = -7,
|
||||
UTSM_ERR_STATE = -8,
|
||||
UTSM_ERR_POISONED = -9,
|
||||
UTSM_ERR_RETRY = -10
|
||||
} utsm_status;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef UTSM_TYPES_H
|
||||
#define UTSM_TYPES_H
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
|
||||
typedef signed char i8;
|
||||
typedef signed short i16;
|
||||
typedef signed int i32;
|
||||
typedef signed long long i64;
|
||||
|
||||
typedef u64 usize;
|
||||
typedef i64 isize;
|
||||
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#define UTSM_UNUSED(x) ((void)(x))
|
||||
#define UTSM_ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
static inline u64 utsm_align_up_u64(u64 value, u64 alignment) {
|
||||
return (value + alignment - 1ULL) & ~(alignment - 1ULL);
|
||||
}
|
||||
|
||||
static inline void *utsm_align_up_ptr(void *ptr, u64 alignment) {
|
||||
return (void *)utsm_align_up_u64((u64)ptr, alignment);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef UTSM_UTRW_H
|
||||
#define UTSM_UTRW_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
#include <utsm/status.h>
|
||||
#include <utsm/capability.h>
|
||||
|
||||
int utsm_read(utsm_capability cap, u64 offset, void *dst, u64 len);
|
||||
int utsm_write(utsm_capability cap, u64 offset, const void *src, u64 len);
|
||||
int utsm_slow_path(int reason);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef UTSM_H
|
||||
#define UTSM_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
#include <utsm/status.h>
|
||||
#include <utsm/config.h>
|
||||
#include <utsm/uuid.h>
|
||||
#include <utsm/process.h>
|
||||
#include <utsm/segment.h>
|
||||
#include <utsm/capability.h>
|
||||
#include <utsm/utrw.h>
|
||||
|
||||
void utsm_init(void);
|
||||
int utsm_selftest_run(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef UTSM_UUID_H
|
||||
#define UTSM_UUID_H
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
typedef struct {
|
||||
u64 hi;
|
||||
u64 lo;
|
||||
} uuid128_t;
|
||||
|
||||
static inline uuid128_t uuid_make_test(u64 seed) {
|
||||
uuid128_t id;
|
||||
id.hi = 0x5554534d00000000ULL ^ (seed * 0x9e3779b97f4a7c15ULL);
|
||||
id.lo = 0x4453484200000000ULL ^ (seed + 0xd1b54a32d192ed03ULL);
|
||||
return id;
|
||||
}
|
||||
|
||||
static inline bool uuid_equal(uuid128_t a, uuid128_t b) {
|
||||
return a.hi == b.hi && a.lo == b.lo;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
#include <utsm/block.h>
|
||||
#include <utsm/log.h>
|
||||
|
||||
static dkm_block_device_desc g_devices[DKM_BLOCK_MAX_DEVICES];
|
||||
static u32 g_device_count;
|
||||
|
||||
void block_init(void) {
|
||||
g_device_count = 0;
|
||||
log_info("[BLOCK] registry init");
|
||||
}
|
||||
|
||||
static int block_register_device_impl(const dkm_block_device_desc *desc) {
|
||||
if (!desc || !desc->read || !desc->sector_size) return -1;
|
||||
if (g_device_count >= DKM_BLOCK_MAX_DEVICES) return -2;
|
||||
|
||||
u32 index = g_device_count++;
|
||||
g_devices[index] = *desc;
|
||||
|
||||
log_info("[BLOCK] device registered");
|
||||
if (desc->name) log_info(desc->name);
|
||||
log_hex64("[BLOCK] index=", index);
|
||||
log_hex64("[BLOCK] sector_size=", desc->sector_size);
|
||||
log_hex64("[BLOCK] sector_count=", desc->sector_count);
|
||||
return (int)index;
|
||||
}
|
||||
|
||||
static u32 block_device_count_impl(void) {
|
||||
return g_device_count;
|
||||
}
|
||||
|
||||
static int block_read_impl(u32 index, u64 lba, u32 count, void *buffer) {
|
||||
if (index >= g_device_count || !buffer || count == 0) return -1;
|
||||
dkm_block_device_desc *dev = &g_devices[index];
|
||||
if (!dev->read) return -2;
|
||||
return dev->read(dev->ctx, lba, count, buffer);
|
||||
}
|
||||
|
||||
static u64 block_sector_size_impl(u32 index) {
|
||||
if (index >= g_device_count) return 0;
|
||||
return g_devices[index].sector_size;
|
||||
}
|
||||
|
||||
static const char *block_device_name_impl(u32 index) {
|
||||
if (index >= g_device_count) return 0;
|
||||
return g_devices[index].name;
|
||||
}
|
||||
|
||||
static const dkm_block_api g_block_api = {
|
||||
.register_device = block_register_device_impl,
|
||||
.device_count = block_device_count_impl,
|
||||
.read = block_read_impl,
|
||||
.sector_size = block_sector_size_impl,
|
||||
.device_name = block_device_name_impl
|
||||
};
|
||||
|
||||
const dkm_block_api *block_get_api(void) {
|
||||
return &g_block_api;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,377 @@
|
||||
#include <utsm/dsk.h>
|
||||
#include <utsm/arena.h>
|
||||
#include <utsm/dkm.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/types.h>
|
||||
#include "../arch/x86_64/limine.h"
|
||||
|
||||
#define DSK_PATH "/system/deshab64/deshab.elf"
|
||||
#define DSK_CMDLINE "dsk:main"
|
||||
|
||||
#define ELF_MAGIC0 0x7f
|
||||
#define ELF_MAGIC1 'E'
|
||||
#define ELF_MAGIC2 'L'
|
||||
#define ELF_MAGIC3 'F'
|
||||
#define ELFCLASS64 2
|
||||
#define ELFDATA2LSB 1
|
||||
#define ET_DYN 3
|
||||
#define ET_EXEC 2
|
||||
#define EM_X86_64 62
|
||||
#define PT_LOAD 1
|
||||
|
||||
void *memset(void *dst, int value, usize len);
|
||||
void *memcpy(void *dst, const void *src, usize len);
|
||||
|
||||
extern volatile struct limine_module_request g_module_request;
|
||||
extern volatile struct limine_rsdp_request g_rsdp_request;
|
||||
extern volatile struct limine_framebuffer_request g_fb_request;
|
||||
extern volatile struct limine_hhdm_request g_hhdm_request;
|
||||
|
||||
typedef struct elf64_ehdr {
|
||||
u8 ident[16];
|
||||
u16 type;
|
||||
u16 machine;
|
||||
u32 version;
|
||||
u64 entry;
|
||||
u64 phoff;
|
||||
u64 shoff;
|
||||
u32 flags;
|
||||
u16 ehsize;
|
||||
u16 phentsize;
|
||||
u16 phnum;
|
||||
u16 shentsize;
|
||||
u16 shnum;
|
||||
u16 shstrndx;
|
||||
} elf64_ehdr;
|
||||
|
||||
typedef struct elf64_phdr {
|
||||
u32 type;
|
||||
u32 flags;
|
||||
u64 offset;
|
||||
u64 vaddr;
|
||||
u64 paddr;
|
||||
u64 filesz;
|
||||
u64 memsz;
|
||||
u64 align;
|
||||
} elf64_phdr;
|
||||
|
||||
/* ---- minimal FAT32 parser ---- */
|
||||
typedef struct __attribute__((packed)) {
|
||||
u8 jmp[3];
|
||||
char oem[8];
|
||||
u16 bytes_per_sector;
|
||||
u8 sectors_per_cluster;
|
||||
u16 reserved_sector_count;
|
||||
u8 fat_count;
|
||||
u16 root_entry_count;
|
||||
u16 total_sectors_16;
|
||||
u8 media;
|
||||
u16 sectors_per_fat_16;
|
||||
u16 sectors_per_track;
|
||||
u16 heads;
|
||||
u32 hidden_sectors;
|
||||
u32 total_sectors_32;
|
||||
u32 sectors_per_fat;
|
||||
u16 flags;
|
||||
u16 version;
|
||||
u32 root_cluster;
|
||||
u16 fsinfo_sector;
|
||||
u16 backup_boot;
|
||||
u8 reserved[12];
|
||||
u8 drive;
|
||||
u8 nt_flags;
|
||||
u8 signature;
|
||||
u32 serial;
|
||||
char label[11];
|
||||
char type[8];
|
||||
u8 code[420];
|
||||
u16 boot_sig;
|
||||
} fat32_bpb;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
char name[11];
|
||||
u8 attr;
|
||||
u8 nt_reserved;
|
||||
u8 creation_tenth;
|
||||
u16 creation_time;
|
||||
u16 creation_date;
|
||||
u16 access_date;
|
||||
u16 cluster_high;
|
||||
u16 write_time;
|
||||
u16 write_date;
|
||||
u16 cluster_low;
|
||||
u32 file_size;
|
||||
} fat32_dir_entry;
|
||||
|
||||
static u32 fat32_read_u32(const u8 *p) {
|
||||
return (u32)p[0] | ((u32)p[1] << 8) | ((u32)p[2] << 16) | ((u32)p[3] << 24);
|
||||
}
|
||||
|
||||
static u16 fat32_read_u16(const u8 *p) {
|
||||
return (u16)p[0] | ((u16)p[1] << 8);
|
||||
}
|
||||
|
||||
static int fat32_name11_eq(const char *n, const char *s) {
|
||||
for (int i = 0; i < 11; i++) {
|
||||
if (n[i] != s[i]) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* core helpers reused from earlier loader */
|
||||
static int streq(const char *a, const char *b) {
|
||||
if (!a || !b) return 0;
|
||||
while (*a && *b) {
|
||||
if (*a != *b) return 0;
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
static int range_ok(u64 offset, u64 length, u64 size) {
|
||||
if (offset > size) return 0;
|
||||
if (length > size - offset) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct limine_file *dsk_find_module(void) {
|
||||
struct limine_module_response *rsp = g_module_request.response;
|
||||
if (!rsp) return 0;
|
||||
|
||||
for (u64 i = 0; i < rsp->module_count; i++) {
|
||||
struct limine_file *file = rsp->modules[i];
|
||||
if (!file) continue;
|
||||
if (streq(file->path, DSK_PATH) || streq(file->cmdline, DSK_CMDLINE)) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---- FAT32 block-provider file reader ---- */
|
||||
static u8 g_dsk_fat32_disk[65536]; /* 128-sector BPB+FAT+root dir buffer */
|
||||
static u8 g_dsk_fat32_cluster[4096]; /* 8-sector cluster buffer */
|
||||
static u8 g_dsk_fat32_filedata[65536]; /* file data buffer */
|
||||
|
||||
static int dsk_load_from_block_fat32(const void **out_addr, u64 *out_size) {
|
||||
const dkm_kernel_api *api = dkm_get_kernel_api();
|
||||
if (!api || !api->block || !api->block->device_count) return -1;
|
||||
u32 count = api->block->device_count();
|
||||
if (count == 0 || api->block->sector_size(0) != 512) return -1;
|
||||
|
||||
/* Read first 128 sectors: BPB + FAT + root dir */
|
||||
u8 *disk = g_dsk_fat32_disk;
|
||||
int st = api->block->read(0, 0, 128, disk);
|
||||
if (st != 0) return -1;
|
||||
|
||||
const fat32_bpb *bpb = (const fat32_bpb *)disk;
|
||||
if (bpb->boot_sig != 0xAA55 || bpb->bytes_per_sector != 512) return -1;
|
||||
|
||||
u32 fat_start = bpb->reserved_sector_count * 512;
|
||||
u32 data_start_sec = bpb->reserved_sector_count + (u32)bpb->fat_count * bpb->sectors_per_fat;
|
||||
|
||||
u32 clus = bpb->root_cluster;
|
||||
u32 found_clus = 0;
|
||||
u32 found_size = 0;
|
||||
const char *target = "DESHAB ELF";
|
||||
|
||||
while (clus >= 2 && clus < 0x0FFFFFF8) {
|
||||
u32 clus_lba = data_start_sec + (clus - 2) * bpb->sectors_per_cluster;
|
||||
u32 cls_sec = bpb->sectors_per_cluster;
|
||||
u8 *cb = g_dsk_fat32_cluster;
|
||||
st = api->block->read(0, clus_lba, cls_sec, cb);
|
||||
if (st != 0) return -1;
|
||||
|
||||
const fat32_dir_entry *dir = (const fat32_dir_entry *)cb;
|
||||
for (u32 e = 0; e * 32 < cls_sec * 512; e++) {
|
||||
if (dir[e].name[0] == 0) break;
|
||||
if ((u8)dir[e].name[0] == 0xE5) continue;
|
||||
if (dir[e].attr == 0x0F) continue;
|
||||
if (dir[e].attr & 0x08) continue;
|
||||
if (fat32_name11_eq(dir[e].name, target)) {
|
||||
found_size = dir[e].file_size;
|
||||
found_clus = fat32_read_u16((const u8 *)&dir[e].cluster_low);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found_clus) break;
|
||||
u32 fat_ent = fat_start + clus * 4;
|
||||
if (fat_ent + 4 > 65536) break;
|
||||
clus = fat32_read_u32(disk + fat_ent) & 0x0FFFFFFF;
|
||||
}
|
||||
|
||||
if (!found_clus || found_size == 0) return -1;
|
||||
|
||||
if (found_size > sizeof(g_dsk_fat32_filedata)) return -1;
|
||||
u8 *dst = g_dsk_fat32_filedata;
|
||||
u32 remaining = found_size;
|
||||
u32 fc = found_clus;
|
||||
|
||||
while (fc >= 2 && fc < 0x0FFFFFF8 && remaining > 0) {
|
||||
u32 fc_lba = data_start_sec + (fc - 2) * bpb->sectors_per_cluster;
|
||||
u32 fc_sec = bpb->sectors_per_cluster;
|
||||
u32 fc_bytes = fc_sec * 512;
|
||||
if (fc_bytes > remaining) fc_bytes = remaining;
|
||||
|
||||
u8 *chunk = g_dsk_fat32_cluster;
|
||||
st = api->block->read(0, fc_lba, fc_sec, chunk);
|
||||
if (st != 0) return -1;
|
||||
for (u32 b = 0; b < fc_bytes; b++) dst[b] = chunk[b];
|
||||
dst += fc_bytes;
|
||||
remaining -= fc_bytes;
|
||||
|
||||
u32 fat_ent = fat_start + fc * 4;
|
||||
if (fat_ent + 4 > 65536) { fc = 0x0FFFFFFF; break; }
|
||||
fc = fat32_read_u32(disk + fat_ent) & 0x0FFFFFFF;
|
||||
}
|
||||
|
||||
/* Copy to arena for ELF loader */
|
||||
u8 *file_buf = (u8 *)kmem_alloc_aligned(found_size, 16);
|
||||
if (!file_buf) return -1;
|
||||
for (u32 i = 0; i < found_size; i++) file_buf[i] = g_dsk_fat32_filedata[i];
|
||||
|
||||
*out_addr = file_buf;
|
||||
*out_size = found_size;
|
||||
log_hex64("[UTSM] FAT32 file size=", found_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---- ELF checks ---- */
|
||||
static int dsk_check_elf(const void *address, u64 size) {
|
||||
if (!address || size < sizeof(elf64_ehdr)) return -1;
|
||||
const elf64_ehdr *eh = (const elf64_ehdr *)address;
|
||||
if (eh->ident[0] != ELF_MAGIC0 || eh->ident[1] != ELF_MAGIC1 ||
|
||||
eh->ident[2] != ELF_MAGIC2 || eh->ident[3] != ELF_MAGIC3) return -2;
|
||||
if (eh->ident[4] != ELFCLASS64 || eh->ident[5] != ELFDATA2LSB) return -3;
|
||||
if (eh->machine != EM_X86_64) return -4;
|
||||
if (eh->type != ET_DYN && eh->type != ET_EXEC) return -5;
|
||||
if (eh->phoff == 0 || eh->phnum == 0 || eh->phentsize < sizeof(elf64_phdr)) return -6;
|
||||
if (!range_ok(eh->phoff, (u64)eh->phnum * eh->phentsize, size)) return -7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsk_load_elf_image(const void *address, u64 size, dsk_entry_fn *entry_out) {
|
||||
const elf64_ehdr *eh = (const elf64_ehdr *)address;
|
||||
const u8 *base = (const u8 *)address;
|
||||
|
||||
u64 min_vaddr = ~0ULL;
|
||||
u64 max_vaddr = 0;
|
||||
u64 max_align = 0x1000;
|
||||
u32 load_count = 0;
|
||||
|
||||
for (u16 i = 0; i < eh->phnum; i++) {
|
||||
const elf64_phdr *ph = (const elf64_phdr *)(base + eh->phoff + (u64)i * eh->phentsize);
|
||||
if (ph->type != PT_LOAD) continue;
|
||||
if (ph->filesz > ph->memsz) return -1;
|
||||
if (!range_ok(ph->offset, ph->filesz, size)) return -2;
|
||||
if (ph->vaddr < min_vaddr) min_vaddr = ph->vaddr;
|
||||
if (ph->vaddr + ph->memsz > max_vaddr) max_vaddr = ph->vaddr + ph->memsz;
|
||||
if (ph->align > max_align) max_align = ph->align;
|
||||
load_count++;
|
||||
}
|
||||
|
||||
if (load_count == 0 || min_vaddr == ~0ULL || max_vaddr <= min_vaddr) return -3;
|
||||
if (eh->entry < min_vaddr || eh->entry >= max_vaddr) return -4;
|
||||
|
||||
u64 image_size = utsm_align_up_u64(max_vaddr - min_vaddr, 0x1000);
|
||||
u8 *image = (u8 *)kmem_alloc_aligned(image_size, max_align);
|
||||
if (!image) return -5;
|
||||
memset(image, 0, image_size);
|
||||
|
||||
for (u16 i = 0; i < eh->phnum; i++) {
|
||||
const elf64_phdr *ph = (const elf64_phdr *)(base + eh->phoff + (u64)i * eh->phentsize);
|
||||
if (ph->type != PT_LOAD) continue;
|
||||
u64 dst_off = ph->vaddr - min_vaddr;
|
||||
if (dst_off + ph->memsz > image_size) return -6;
|
||||
memcpy(image + dst_off, base + ph->offset, ph->filesz);
|
||||
}
|
||||
|
||||
*entry_out = (dsk_entry_fn)(image + (eh->entry - min_vaddr));
|
||||
log_hex64("[UTSM] DSK image base=", (u64)image);
|
||||
log_hex64("[UTSM] DSK image size=", image_size);
|
||||
log_hex64("[UTSM] DSK entry=", (u64)*entry_out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dsk_fill_boot_context(dsk_boot_context *ctx) {
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->magic = DSK_BOOT_MAGIC;
|
||||
ctx->abi_version = DSK_BOOT_ABI_VERSION;
|
||||
ctx->size = sizeof(*ctx);
|
||||
ctx->flags = DSK_BOOT_FLAG_FROM_UTSM | DSK_BOOT_FLAG_DKM_READY | DSK_BOOT_FLAG_FAT32_PATH;
|
||||
|
||||
if (g_hhdm_request.response) {
|
||||
ctx->hhdm_offset = g_hhdm_request.response->offset;
|
||||
}
|
||||
if (g_rsdp_request.response) {
|
||||
ctx->rsdp_address = (u64)g_rsdp_request.response->address;
|
||||
}
|
||||
if (g_fb_request.response && g_fb_request.response->framebuffer_count > 0) {
|
||||
struct limine_framebuffer *fb = g_fb_request.response->framebuffers[0];
|
||||
ctx->framebuffer_address = (u64)fb->address;
|
||||
ctx->framebuffer_width = fb->width;
|
||||
ctx->framebuffer_height = fb->height;
|
||||
ctx->framebuffer_pitch = fb->pitch;
|
||||
ctx->framebuffer_bpp = fb->bpp;
|
||||
}
|
||||
ctx->boot_modules_response = (u64)g_module_request.response;
|
||||
ctx->dkm_kernel_api = (u64)dkm_get_kernel_api();
|
||||
|
||||
u64 rsp;
|
||||
__asm__ volatile ("movq %%rsp, %0" : "=r"(rsp));
|
||||
ctx->kernel_stack_top = rsp;
|
||||
}
|
||||
|
||||
int dsk_load_and_jump(void) {
|
||||
log_info("[UTSM] loading DSK");
|
||||
log_info(DSK_PATH);
|
||||
|
||||
const void *data = 0;
|
||||
u64 data_size = 0;
|
||||
|
||||
/* 1) try FAT32 block provider */
|
||||
int fat32_ok = dsk_load_from_block_fat32(&data, &data_size);
|
||||
if (fat32_ok == 0) {
|
||||
log_info("[UTSM] DSK loaded from FAT32 block provider");
|
||||
} else {
|
||||
/* 2) fallback: Limine boot module */
|
||||
log_info("[UTSM] FAT32 block path unavailable; trying Limine module");
|
||||
struct limine_file *file = dsk_find_module();
|
||||
if (!file) {
|
||||
log_error("[UTSM] DSK module not found (neither FAT32 nor Limine)");
|
||||
return -1;
|
||||
}
|
||||
data = file->address;
|
||||
data_size = file->size;
|
||||
log_hex64("[UTSM] DSK module size=", data_size);
|
||||
}
|
||||
|
||||
int status = dsk_check_elf(data, data_size);
|
||||
if (status != 0) {
|
||||
log_error("[UTSM] DSK ELF rejected");
|
||||
log_hex64("[UTSM] DSK ELF status=", (u64)(i64)status);
|
||||
return status;
|
||||
}
|
||||
|
||||
dsk_entry_fn entry = 0;
|
||||
status = dsk_load_elf_image(data, data_size, &entry);
|
||||
if (status != 0) {
|
||||
log_error("[UTSM] DSK load failed");
|
||||
log_hex64("[UTSM] DSK load status=", (u64)(i64)status);
|
||||
return status;
|
||||
}
|
||||
|
||||
dsk_boot_context *ctx = (dsk_boot_context *)kmem_alloc_aligned(sizeof(dsk_boot_context), 16);
|
||||
if (!ctx) {
|
||||
log_error("[UTSM] DSK context allocation failed");
|
||||
return -1;
|
||||
}
|
||||
dsk_fill_boot_context(ctx);
|
||||
|
||||
log_info("[UTSM] jumping to DSK");
|
||||
entry(ctx);
|
||||
|
||||
log_error("[UTSM] DSK returned unexpectedly");
|
||||
return -1;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,34 @@
|
||||
#include <utsm/log.h>
|
||||
|
||||
static void log_line(const char *level, const char *msg) {
|
||||
serial_write(level);
|
||||
serial_write(" ");
|
||||
serial_write(msg);
|
||||
serial_write("\n");
|
||||
}
|
||||
|
||||
void log_info(const char *msg) {
|
||||
log_line("[INFO]", msg);
|
||||
}
|
||||
|
||||
void log_warn(const char *msg) {
|
||||
log_line("[WARN]", msg);
|
||||
}
|
||||
|
||||
void log_error(const char *msg) {
|
||||
log_line("[ERR ]", msg);
|
||||
}
|
||||
|
||||
void log_hex64(const char *prefix, u64 value) {
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
char buf[19];
|
||||
buf[0] = '0';
|
||||
buf[1] = 'x';
|
||||
for (int i = 0; i < 16; i++) {
|
||||
buf[2 + i] = hex[(value >> ((15 - i) * 4)) & 0xf];
|
||||
}
|
||||
buf[18] = 0;
|
||||
serial_write(prefix);
|
||||
serial_write(buf);
|
||||
serial_write("\n");
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,54 @@
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/arena.h>
|
||||
#include <utsm/utsm.h>
|
||||
#include <utsm/drr.h>
|
||||
#include <utsm/dkm.h>
|
||||
#include <utsm/idt.h>
|
||||
#include <utsm/dsk.h>
|
||||
#include <utsm/block.h>
|
||||
#include <utsm/net.h>
|
||||
|
||||
void arch_halt_forever(void);
|
||||
|
||||
void kernel_main(void) {
|
||||
serial_init();
|
||||
log_info("[UTSM] boot");
|
||||
|
||||
idt_init();
|
||||
|
||||
log_info("[UTSM] arena init begin");
|
||||
arena_init();
|
||||
log_info("[UTSM] arena init ok");
|
||||
|
||||
log_info("[UTSM] dma init begin");
|
||||
dma_init();
|
||||
log_info("[UTSM] dma init ok");
|
||||
|
||||
log_info("[UTSM] net registry init begin");
|
||||
net_init();
|
||||
log_info("[UTSM] net registry init ok");
|
||||
|
||||
log_info("[UTSM] drr stub init begin");
|
||||
drr_stub_init();
|
||||
log_info("[UTSM] drr stub init ok");
|
||||
|
||||
log_info("[UTSM] core init begin");
|
||||
utsm_init();
|
||||
log_info("[UTSM] init ok");
|
||||
|
||||
dkm_init();
|
||||
dkm_fill_platform_info();
|
||||
dsm_load_by_manifest();
|
||||
|
||||
int result = utsm_selftest_run();
|
||||
if (result == 0) {
|
||||
log_info("[UTSM] SELFTEST PASS");
|
||||
if (dsk_load_and_jump() != 0) {
|
||||
log_error("[UTSM] DSK jump failed");
|
||||
}
|
||||
} else {
|
||||
log_error("[UTSM] SELFTEST FAIL");
|
||||
}
|
||||
|
||||
arch_halt_forever();
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,73 @@
|
||||
#include <utsm/net.h>
|
||||
#include <utsm/log.h>
|
||||
|
||||
/*
|
||||
* 最小 netdev 注册表:
|
||||
* - 早期 DKM 驱动加载路径是单线程顺序执行,当前无需引入锁,避免在网络底座阶段扩大复杂度。
|
||||
* - 后续进入多核/热插拔后,应在 register/device_info 外围加自旋锁或 RCU 风格只读快照。
|
||||
*/
|
||||
static dkm_net_device_desc g_net_devices[DKM_NET_MAX_DEVICES];
|
||||
static u32 g_net_device_count;
|
||||
|
||||
void net_init(void) {
|
||||
g_net_device_count = 0;
|
||||
log_info("[NET] registry init");
|
||||
}
|
||||
|
||||
static int net_register_device_impl(const dkm_net_device_desc *desc) {
|
||||
if (!desc || !desc->name) return -1;
|
||||
if (g_net_device_count >= DKM_NET_MAX_DEVICES) return -2;
|
||||
|
||||
u32 index = g_net_device_count++;
|
||||
g_net_devices[index] = *desc;
|
||||
|
||||
log_info("[NET] device registered");
|
||||
log_info(desc->name);
|
||||
log_hex64("[NET] index=", index);
|
||||
log_hex64("[NET] flags=", desc->flags);
|
||||
return (int)index;
|
||||
}
|
||||
|
||||
static u32 net_device_count_impl(void) {
|
||||
return g_net_device_count;
|
||||
}
|
||||
|
||||
static int net_device_info_impl(u32 index, dkm_net_device_info *out) {
|
||||
if (!out) return -1;
|
||||
if (index >= g_net_device_count) return -2;
|
||||
|
||||
const dkm_net_device_desc *dev = &g_net_devices[index];
|
||||
out->name = dev->name;
|
||||
for (u32 i = 0; i < 6; i++) {
|
||||
out->mac[i] = dev->mac[i];
|
||||
}
|
||||
out->flags = dev->flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int net_tx_impl(u32 index, const void *packet, u32 length) {
|
||||
if (index >= g_net_device_count) return -2;
|
||||
const dkm_net_device_desc *dev = &g_net_devices[index];
|
||||
if (!dev->tx) return -3;
|
||||
log_hex64("[NET] tx dispatch fn=", (u64)dev->tx);
|
||||
return dev->tx(dev->ctx, packet, length);
|
||||
}
|
||||
|
||||
static int net_rx_poll_impl(u32 index, void *buffer, u32 capacity, u32 *out_length) {
|
||||
if (index >= g_net_device_count) return -2;
|
||||
const dkm_net_device_desc *dev = &g_net_devices[index];
|
||||
if (!dev->rx_poll) return -3;
|
||||
return dev->rx_poll(dev->ctx, buffer, capacity, out_length);
|
||||
}
|
||||
|
||||
static const dkm_net_api g_net_api = {
|
||||
.register_device = net_register_device_impl,
|
||||
.device_count = net_device_count_impl,
|
||||
.device_info = net_device_info_impl,
|
||||
.tx = net_tx_impl,
|
||||
.rx_poll = net_rx_poll_impl
|
||||
};
|
||||
|
||||
const dkm_net_api *net_get_api(void) {
|
||||
return &g_net_api;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,9 @@
|
||||
#include <utsm/log.h>
|
||||
|
||||
void arch_halt_forever(void);
|
||||
|
||||
void panic(const char *msg) {
|
||||
log_error("[PANIC]");
|
||||
log_error(msg);
|
||||
arch_halt_forever();
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
ENTRY(_start)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(5); /* R-X */
|
||||
rodata PT_LOAD FLAGS(4); /* R-- */
|
||||
data PT_LOAD FLAGS(7); /* RWX (SAS-R0) */
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xffffffff80000000;
|
||||
|
||||
.text : ALIGN(4K) {
|
||||
*(.text*)
|
||||
} :text
|
||||
|
||||
.rodata : ALIGN(4K) {
|
||||
*(.limine_requests_start*)
|
||||
*(.limine_requests*)
|
||||
*(.limine_requests_end*)
|
||||
*(.rodata*)
|
||||
} :rodata
|
||||
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <utsm/arena.h>
|
||||
#include <utsm/config.h>
|
||||
#include <utsm/log.h>
|
||||
|
||||
static u8 arena[UTSM_ARENA_SIZE] __attribute__((aligned(UTSM_PAGE_SIZE)));
|
||||
static u64 arena_offset;
|
||||
|
||||
void arena_init(void) {
|
||||
arena_offset = 0;
|
||||
}
|
||||
|
||||
void *kmem_alloc_aligned(u64 size, u64 alignment) {
|
||||
u64 current = (u64)&arena[0] + arena_offset;
|
||||
u64 aligned = utsm_align_up_u64(current, alignment);
|
||||
u64 new_offset = (aligned - (u64)&arena[0]) + size;
|
||||
if (new_offset > UTSM_ARENA_SIZE) {
|
||||
log_error("[UTSM] arena out of memory");
|
||||
return NULL;
|
||||
}
|
||||
arena_offset = new_offset;
|
||||
return (void *)aligned;
|
||||
}
|
||||
|
||||
void *kmem_alloc(u64 size) {
|
||||
return kmem_alloc_aligned(size, 16);
|
||||
}
|
||||
|
||||
void *kmem_alloc_page(u64 page_count) {
|
||||
return kmem_alloc_aligned(page_count * UTSM_PAGE_SIZE, UTSM_PAGE_SIZE);
|
||||
}
|
||||
|
||||
u64 kmem_arena_virtual_base(void) {
|
||||
return (u64)&arena[0];
|
||||
}
|
||||
|
||||
u64 kmem_arena_virtual_end(void) {
|
||||
return (u64)&arena[0] + UTSM_ARENA_SIZE;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,141 @@
|
||||
#include <utsm/dma.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/types.h>
|
||||
#include "../arch/x86_64/limine.h"
|
||||
|
||||
#define PAGE_SIZE 4096ULL
|
||||
#define DMA_LOW_MAX_PHYS 0x100000000ULL /* 只在低 4G 物理内存做 DMA 分配 */
|
||||
#define DMA_BITMAP_PAGES (DMA_LOW_MAX_PHYS / PAGE_SIZE) /* 1,048,576 页 */
|
||||
#define DMA_BITMAP_WORDS (DMA_BITMAP_PAGES / 64ULL) /* 每 word 覆盖 64 页 */
|
||||
|
||||
extern volatile struct limine_memmap_request g_memmap_request;
|
||||
extern volatile struct limine_hhdm_request g_hhdm_request;
|
||||
|
||||
/*
|
||||
* 真实物理页分配器:
|
||||
* - 以 memmap 中低 4G 内的 USABLE 区域构建 page bitmap(bit=1 表示可用)。
|
||||
* - Limine 保证 USABLE 区域不含 kernel/modules/framebuffer/bootloader 结构,
|
||||
* 因此无需手动避让,标记为可用的页一定是安全的独立物理页。
|
||||
* - alloc 返回的 virt 使用 HHDM 直映射(hhdm_offset + phys),
|
||||
* 保证 CPU 访问的虚拟地址与设备 bus-master 使用的物理地址指向同一页。
|
||||
*/
|
||||
static u64 g_hhdm_offset;
|
||||
static u64 g_bitmap[DMA_BITMAP_WORDS]; /* 1 bit/页,1=free */
|
||||
static u64 g_free_pages;
|
||||
static u64 g_lowest_free_index; /* 分配起点提示,减少扫描 */
|
||||
static int g_dma_ready;
|
||||
|
||||
static u64 align_up(u64 value, u64 alignment) {
|
||||
if (alignment < PAGE_SIZE) alignment = PAGE_SIZE;
|
||||
return (value + alignment - 1ULL) & ~(alignment - 1ULL);
|
||||
}
|
||||
|
||||
static void bitmap_mark_free(u64 index) {
|
||||
g_bitmap[index >> 6] |= (1ULL << (index & 63ULL));
|
||||
}
|
||||
|
||||
static void bitmap_mark_used(u64 index) {
|
||||
g_bitmap[index >> 6] &= ~(1ULL << (index & 63ULL));
|
||||
}
|
||||
|
||||
static int bitmap_is_free(u64 index) {
|
||||
return (g_bitmap[index >> 6] >> (index & 63ULL)) & 1ULL;
|
||||
}
|
||||
|
||||
void dma_init(void) {
|
||||
g_hhdm_offset = 0;
|
||||
g_free_pages = 0;
|
||||
g_lowest_free_index = DMA_BITMAP_PAGES;
|
||||
g_dma_ready = 0;
|
||||
for (u64 i = 0; i < DMA_BITMAP_WORDS; i++) g_bitmap[i] = 0;
|
||||
|
||||
if (g_hhdm_request.response) {
|
||||
g_hhdm_offset = g_hhdm_request.response->offset;
|
||||
}
|
||||
if (!g_hhdm_offset || !g_memmap_request.response) {
|
||||
log_warn("[DMA] missing HHDM or memmap response");
|
||||
return;
|
||||
}
|
||||
|
||||
struct limine_memmap_response *rsp = g_memmap_request.response;
|
||||
for (u64 i = 0; i < rsp->entry_count; i++) {
|
||||
struct limine_memmap_entry *e = rsp->entries[i];
|
||||
if (!e || e->type != LIMINE_MEMMAP_USABLE) continue;
|
||||
|
||||
u64 base = align_up(e->base, PAGE_SIZE);
|
||||
u64 end = e->base + e->length;
|
||||
if (end <= base) continue;
|
||||
|
||||
/* 保留最低 1MiB,避免 legacy/实模式结构;限制在低 4G 内。 */
|
||||
if (base < 0x100000ULL) base = 0x100000ULL;
|
||||
if (end > DMA_LOW_MAX_PHYS) end = DMA_LOW_MAX_PHYS;
|
||||
if (end <= base) continue;
|
||||
|
||||
u64 start_index = base / PAGE_SIZE;
|
||||
u64 end_index = end / PAGE_SIZE;
|
||||
for (u64 idx = start_index; idx < end_index; idx++) {
|
||||
if (!bitmap_is_free(idx)) {
|
||||
bitmap_mark_free(idx);
|
||||
g_free_pages++;
|
||||
if (idx < g_lowest_free_index) g_lowest_free_index = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (g_free_pages == 0) {
|
||||
log_warn("[DMA] no usable low pages found");
|
||||
return;
|
||||
}
|
||||
|
||||
g_dma_ready = 1;
|
||||
log_info("[DMA] init ok");
|
||||
log_hex64("[DMA] free pages=", g_free_pages);
|
||||
log_hex64("[DMA] first free phys=", g_lowest_free_index * PAGE_SIZE);
|
||||
}
|
||||
|
||||
int dma_alloc_pages(u64 page_count, u64 alignment, u64 max_phys, dkm_dma_buffer *out) {
|
||||
if (!out || page_count == 0 || !g_dma_ready) return -1;
|
||||
if (page_count > DMA_BITMAP_PAGES) return -3;
|
||||
if (max_phys == 0 || max_phys > DMA_LOW_MAX_PHYS) max_phys = DMA_LOW_MAX_PHYS;
|
||||
|
||||
if (alignment < PAGE_SIZE) alignment = PAGE_SIZE;
|
||||
u64 align_pages = alignment / PAGE_SIZE;
|
||||
if (align_pages == 0) align_pages = 1;
|
||||
|
||||
u64 max_index = max_phys / PAGE_SIZE;
|
||||
u64 start = g_lowest_free_index;
|
||||
start = (start / align_pages) * align_pages;
|
||||
|
||||
for (u64 base = start; base + page_count <= max_index; base += align_pages) {
|
||||
int ok = 1;
|
||||
for (u64 j = 0; j < page_count; j++) {
|
||||
if (!bitmap_is_free(base + j)) { ok = 0; break; }
|
||||
}
|
||||
if (!ok) continue;
|
||||
|
||||
for (u64 j = 0; j < page_count; j++) bitmap_mark_used(base + j);
|
||||
g_free_pages -= page_count;
|
||||
|
||||
u64 phys = base * PAGE_SIZE;
|
||||
out->phys = phys;
|
||||
out->virt = (void *)(g_hhdm_offset + phys);
|
||||
out->size = page_count * PAGE_SIZE;
|
||||
|
||||
u8 *p = (u8 *)out->virt;
|
||||
for (u64 i = 0; i < out->size; i++) p[i] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_warn("[DMA] alloc failed");
|
||||
log_hex64("[DMA] req pages=", page_count);
|
||||
log_hex64("[DMA] free pages=", g_free_pages);
|
||||
return -2;
|
||||
}
|
||||
|
||||
static const dkm_dma_api g_dma_api = {
|
||||
.alloc_pages = dma_alloc_pages
|
||||
};
|
||||
|
||||
const dkm_dma_api *dma_get_api(void) {
|
||||
return &g_dma_api;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,36 @@
|
||||
#include <utsm/pckc.h>
|
||||
#include <utsm/segment.h>
|
||||
#include <utsm/config.h>
|
||||
|
||||
static utsm_pckc g_pckc;
|
||||
|
||||
void utsm_pckc_init(void) {
|
||||
g_pckc.current_process_uuid = uuid_make_test(0);
|
||||
g_pckc.hit_count = 0;
|
||||
g_pckc.miss_count = 0;
|
||||
g_pckc.next_replace = 0;
|
||||
for (u32 i = 0; i < UTSM_MAX_PCKC_KEYS; i++) {
|
||||
g_pckc.entries[i].valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
int utsm_pckc_get_or_derive(u32 segment_slot, utsm_segment_desc *desc, utsm_key_material *out_key) {
|
||||
for (u32 i = 0; i < UTSM_MAX_PCKC_KEYS; i++) {
|
||||
utsm_pckc_entry *entry = &g_pckc.entries[i];
|
||||
if (entry->valid && entry->segment_slot == segment_slot && entry->key_epoch == desc->key_epoch) {
|
||||
*out_key = entry->key;
|
||||
g_pckc.hit_count++;
|
||||
return UTSM_OK;
|
||||
}
|
||||
}
|
||||
|
||||
g_pckc.miss_count++;
|
||||
u32 idx = g_pckc.next_replace++ % UTSM_MAX_PCKC_KEYS;
|
||||
utsm_pckc_entry *entry = &g_pckc.entries[idx];
|
||||
entry->valid = true;
|
||||
entry->segment_slot = segment_slot;
|
||||
entry->key_epoch = desc->key_epoch;
|
||||
utsm_kdf_segment_key(desc->owner_process_uuid, desc->segment_uuid, desc->key_epoch, &entry->key);
|
||||
*out_key = entry->key;
|
||||
return UTSM_OK;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
#include <utsm/assert.h>
|
||||
Binary file not shown.
@@ -0,0 +1,37 @@
|
||||
#include <utsm/types.h>
|
||||
|
||||
void *memset(void *dst, int value, usize len) {
|
||||
u8 *d = (u8 *)dst;
|
||||
for (usize i = 0; i < len; i++) {
|
||||
d[i] = (u8)value;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *memcpy(void *dst, const void *src, usize len) {
|
||||
u8 *d = (u8 *)dst;
|
||||
const u8 *s = (const u8 *)src;
|
||||
for (usize i = 0; i < len; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
int memcmp(const void *a, const void *b, usize len) {
|
||||
const u8 *x = (const u8 *)a;
|
||||
const u8 *y = (const u8 *)b;
|
||||
for (usize i = 0; i < len; i++) {
|
||||
if (x[i] != y[i]) {
|
||||
return (int)x[i] - (int)y[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
usize strlen(const char *s) {
|
||||
usize len = 0;
|
||||
while (s[len]) {
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,50 @@
|
||||
#include <utsm/utsm.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/segment.h>
|
||||
|
||||
int memcmp(const void *a, const void *b, usize len);
|
||||
usize strlen(const char *s);
|
||||
|
||||
int utsm_selftest_run(void) {
|
||||
utsm_process_context process;
|
||||
utsm_process_create_test(&process, 1);
|
||||
|
||||
utsm_capability cap;
|
||||
int status = utsm_create_segment(&process, UTSM_PAGE_SIZE, UTSM_SEG_F_READ | UTSM_SEG_F_WRITE | UTSM_SEG_F_STRONG_RECOVERY, &cap);
|
||||
if (status != UTSM_OK) {
|
||||
log_error("[UTSM] selftest create segment failed");
|
||||
return status;
|
||||
}
|
||||
|
||||
const char *message = "deshab utsm sealed memory selftest";
|
||||
u64 len = strlen(message) + 1;
|
||||
status = utsm_write(cap, 128, message, len);
|
||||
if (status != UTSM_OK) {
|
||||
log_error("[UTSM] selftest write failed");
|
||||
return status;
|
||||
}
|
||||
log_info("[UTSM] selftest write ok");
|
||||
|
||||
utsm_segment_desc *desc = utsm_get_segment(cap.segment_slot);
|
||||
if (!desc) {
|
||||
return UTSM_ERR_INVALID;
|
||||
}
|
||||
if (memcmp(desc->cipher_base + 128, message, len) == 0) {
|
||||
log_error("[UTSM] raw cipher equals plaintext");
|
||||
return UTSM_ERR_INVALID;
|
||||
}
|
||||
log_info("[UTSM] raw cipher check ok");
|
||||
|
||||
char readback[64];
|
||||
status = utsm_read(cap, 128, readback, len);
|
||||
if (status != UTSM_OK) {
|
||||
log_error("[UTSM] selftest read failed");
|
||||
return status;
|
||||
}
|
||||
if (memcmp(readback, message, len) != 0) {
|
||||
log_error("[UTSM] selftest read mismatch");
|
||||
return UTSM_ERR_INVALID;
|
||||
}
|
||||
log_info("[UTSM] selftest read ok");
|
||||
return UTSM_OK;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,56 @@
|
||||
#include <utsm/utrw.h>
|
||||
#include <utsm/segment.h>
|
||||
#include <utsm/pckc.h>
|
||||
#include <utsm/crypto.h>
|
||||
#include <utsm/config.h>
|
||||
|
||||
void *memcpy(void *dst, const void *src, usize len);
|
||||
|
||||
int utsm_read(utsm_capability cap, u64 offset, void *dst, u64 len) {
|
||||
if (!dst && len != 0) {
|
||||
return UTSM_ERR_INVALID;
|
||||
}
|
||||
if (len == 0) {
|
||||
return UTSM_OK;
|
||||
}
|
||||
|
||||
utsm_segment_desc *desc = NULL;
|
||||
int status = utsm_cap_validate(cap, UTSM_RIGHT_READ, offset, len, &desc);
|
||||
if (status != UTSM_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
utsm_key_material key;
|
||||
status = utsm_pckc_get_or_derive(cap.segment_slot, desc, &key);
|
||||
if (status != UTSM_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
u8 line_plain[UTSM_CACHE_LINE_SIZE];
|
||||
u64 seq_before = desc->writer_seq;
|
||||
if (seq_before & 1ULL) {
|
||||
return UTSM_ERR_RETRY;
|
||||
}
|
||||
|
||||
u64 copied = 0;
|
||||
while (copied < len) {
|
||||
u64 absolute = offset + copied;
|
||||
u64 line_start = (absolute / UTSM_CACHE_LINE_SIZE) * UTSM_CACHE_LINE_SIZE;
|
||||
u64 in_line = absolute - line_start;
|
||||
u64 chunk = UTSM_CACHE_LINE_SIZE - in_line;
|
||||
if (chunk > len - copied) {
|
||||
chunk = len - copied;
|
||||
}
|
||||
u64 line_index = line_start / UTSM_CACHE_LINE_SIZE;
|
||||
u64 tweak = utsm_make_tweak(desc->tweak_seed, line_index, desc->key_epoch);
|
||||
utsm_crypt_line(&key, tweak, desc->cipher_base + line_start, line_plain);
|
||||
memcpy((u8 *)dst + copied, line_plain + in_line, chunk);
|
||||
copied += chunk;
|
||||
}
|
||||
|
||||
u64 seq_after = desc->writer_seq;
|
||||
if (seq_before != seq_after) {
|
||||
return UTSM_ERR_RETRY;
|
||||
}
|
||||
return UTSM_OK;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
#include <utsm/utrw.h>
|
||||
|
||||
int utsm_slow_path(int reason) {
|
||||
return reason;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,63 @@
|
||||
#include <utsm/utrw.h>
|
||||
#include <utsm/segment.h>
|
||||
#include <utsm/pckc.h>
|
||||
#include <utsm/crypto.h>
|
||||
#include <utsm/config.h>
|
||||
#include <utsm/drr.h>
|
||||
|
||||
void *memcpy(void *dst, const void *src, usize len);
|
||||
|
||||
int utsm_write(utsm_capability cap, u64 offset, const void *src, u64 len) {
|
||||
if (!src && len != 0) {
|
||||
return UTSM_ERR_INVALID;
|
||||
}
|
||||
if (len == 0) {
|
||||
return UTSM_OK;
|
||||
}
|
||||
|
||||
utsm_segment_desc *desc = NULL;
|
||||
int status = utsm_cap_validate(cap, UTSM_RIGHT_WRITE, offset, len, &desc);
|
||||
if (status != UTSM_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
utsm_key_material key;
|
||||
status = utsm_pckc_get_or_derive(cap.segment_slot, desc, &key);
|
||||
if (status != UTSM_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
drr_log_write_intent(cap.segment_slot, offset, len);
|
||||
desc->writer_seq++;
|
||||
|
||||
u8 line_plain[UTSM_CACHE_LINE_SIZE];
|
||||
u8 line_cipher[UTSM_CACHE_LINE_SIZE];
|
||||
u64 written = 0;
|
||||
while (written < len) {
|
||||
u64 absolute = offset + written;
|
||||
u64 line_start = (absolute / UTSM_CACHE_LINE_SIZE) * UTSM_CACHE_LINE_SIZE;
|
||||
u64 in_line = absolute - line_start;
|
||||
u64 chunk = UTSM_CACHE_LINE_SIZE - in_line;
|
||||
if (chunk > len - written) {
|
||||
chunk = len - written;
|
||||
}
|
||||
u64 line_index = line_start / UTSM_CACHE_LINE_SIZE;
|
||||
u64 tweak = utsm_make_tweak(desc->tweak_seed, line_index, desc->key_epoch);
|
||||
|
||||
if (chunk == UTSM_CACHE_LINE_SIZE && in_line == 0) {
|
||||
memcpy(line_plain, (const u8 *)src + written, UTSM_CACHE_LINE_SIZE);
|
||||
} else {
|
||||
utsm_crypt_line(&key, tweak, desc->cipher_base + line_start, line_plain);
|
||||
memcpy(line_plain + in_line, (const u8 *)src + written, chunk);
|
||||
}
|
||||
|
||||
utsm_crypt_line(&key, tweak, line_plain, line_cipher);
|
||||
memcpy(desc->cipher_base + line_start, line_cipher, UTSM_CACHE_LINE_SIZE);
|
||||
written += chunk;
|
||||
}
|
||||
|
||||
utsm_mark_dirty(desc, offset, len);
|
||||
desc->writer_seq++;
|
||||
drr_log_write_commit(cap.segment_slot, offset, len);
|
||||
return UTSM_OK;
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user