11 KiB
11 KiB
UTSM 算法记录
UTSM = UUID-Tuned Sealed Memory
中文名:UUID 调谐封缄内存
本文记录 UTSM v1 的核心算法。
1. 段创建算法
目标:为任务创建一个只存密文的连续内存段,并返回 capability。
utsm_create_segment(process, size, flags)
1. size 按 64B / 4KB 对齐。
2. 从 buddy/slab 分配 cipher data pages。
3. 从 DMP pool 分配 DMP。
4. 生成 segment_uuid。
5. key_epoch = process.crypto_epoch。
6. tweak_seed = hash(process_uuid, segment_uuid, key_epoch)。
7. 初始化 dirty_bitmap。
8. 初始化 mac_table。
9. 填写 utsm_segment_desc。
10. 填写 utsm_dmp。
11. generation++。
12. 生成 utsm_capability。
13. 将 capability 写入任务 capability table。
14. 返回 capability。
复杂度:
段元数据初始化:O(1)
数据页分配:O(page_count)
热路径访问定位:O(1)
2. 密钥派生算法
UUID 不作为明文密钥,而是作为调谐因子。
segment_key = KDF(
DRR_root_key,
process_uuid,
segment_uuid,
key_epoch
)
每 64B cache line 生成 tweak:
line_index = offset / 64
tweak = hash(tweak_seed, line_index, key_epoch)
加密和解密对称:
ciphertext = plaintext XOR stream(segment_key, tweak)
plaintext = ciphertext XOR stream(segment_key, tweak)
设计理由:
1. 避免十进制 UUID 解析。
2. 避免 UUID 孔洞破坏连续内存。
3. 以 64B cache line 为单位,适合 CPU cache 和 SIMD。
4. key_epoch 可用于快速作废旧段。
3. UTRW Fast Read 算法
UTRW_READ_FAST(cap, offset, len, dst)
1. desc = SEGMENT_TABLE[cap.segment_slot]。
2. 检查 desc.generation == cap.generation。
3. 检查 cap.rights 包含 READ。
4. 检查 cap.epoch == desc.key_epoch。
5. 检查 offset + len <= desc.cipher_length。
6. 检查 desc.state == ACTIVE。
7. key = PCKC_LOOKUP(desc.segment_slot, desc.key_epoch)。
8. 如果 key miss,进入 slow path。
9. 读取 writer_seq_before。
10. 如果 writer_seq_before 为奇数,重试或 slow path。
11. 对访问范围涉及的每个 64B line:
a. 计算 line_index。
b. 生成 tweak。
c. 读取密文 line。
d. 解密成明文 line。
e. 拷贝目标字节到 dst。
12. 读取 writer_seq_after。
13. 如果 before != after,重试。
14. 返回 OK。
复杂度:
段定位:O(1)
读写长度 n:O(n / 64)
4. UTRW Fast Write 算法
UTRW_WRITE_FAST(cap, offset, len, src)
1. desc = SEGMENT_TABLE[cap.segment_slot]。
2. 检查 desc.generation == cap.generation。
3. 检查 cap.rights 包含 WRITE。
4. 检查 cap.epoch == desc.key_epoch。
5. 检查 offset + len <= desc.cipher_length。
6. 检查 desc.state == ACTIVE。
7. key = PCKC_LOOKUP(desc.segment_slot, desc.key_epoch)。
8. 如果 key miss,进入 slow path。
9. 如果是强恢复段,写 WRITE_INTENT log。
10. writer_seq++,进入奇数写入状态。
11. 对访问范围涉及的每个 64B line:
a. 计算 line_index。
b. 生成 tweak。
c. 如果覆盖完整 line,直接使用 src 明文。
d. 如果部分覆盖 line,读取旧密文,解密旧明文,合并新明文。
e. 加密成新密文。
f. 写回 cipher data。
12. 标记 dirty_bitmap。
13. writer_seq++,回到偶数稳定状态。
14. 如果是强恢复段,写 WRITE_COMMIT log。
15. 返回 OK。
部分写规则:
UTSM 的加密单位是 64B line。
如果只写 line 的一部分,必须读旧密文、解密、合并、重新加密整条 line。
5. UTRW Slow Path 算法
Slow Path 触发条件:
PCKC key miss
generation mismatch
epoch mismatch
state != ACTIVE
checkpoint busy
recovery busy
MAC failed
segment poisoned
out of bounds
access denied
处理策略:
KEY_MISS
-> 派生 segment_key
-> 生成 key_schedule
-> 写入 PCKC
-> 回到 fast path
STALE_CAPABILITY
-> 尝试从 capability table 刷新
-> 失败则返回错误
EPOCH_EXPIRED
-> 刷新 cap.epoch 和 auth_tag
-> 清除旧 PCKC key
-> 回到 fast path
CHECKPOINT_BUSY
-> 短暂等待或写 side log
RECOVERING
-> 阻塞任务,等待 DRR 完成恢复
MAC_FAILED
-> 标记 suspicious page
-> 通知 DRR
-> 尝试 page rollback
SEGMENT_POISONED
-> 拒绝访问
-> 交给 DRR 决定回滚、重建或 kill task
6. PCKC 查找算法
每 CPU 保存少量热段 key。
PCKC_LOOKUP(slot, epoch)
1. 检查 current hot slot。
2. 检查 hot_segment_slot[0..N]。
3. 如果 slot 和 epoch 均匹配,返回 key_schedule。
4. 否则返回 MISS。
替换策略:
第一版使用小型 LRU 或替换最冷 slot。
建议槽数:
8 个 key slot 起步。
高并发或服务型任务可扩展到 16 个。
7. Checkpoint 算法
7.1 Dirty Shard 标记算法
Dirty Bitmap 分片为 Dirty Shard,避免 checkpoint 扫描整块大 bitmap。
UTSM_MARK_DIRTY(desc, page_index)
1. shard = desc.dirty_shards[page_index / PAGES_PER_SHARD]。
2. bit = page_index % PAGES_PER_SHARD。
3. 如果 bit 原来是 0:
a. 设置 bitmap bit。
b. shard.dirty_count++。
c. 如果 shard.dirty_count 从 0 变为 1,加入 per-cpu dirty_shard_list。
4. 返回。
复杂度:
Dirty 标记:O(1)
Checkpoint 扫描:O(number_of_dirty_shards + number_of_dirty_pages)
7.2 A/B Checkpoint Metadata 提交算法
CHECKPOINT_METADATA_COMMIT(gen)
1. active = checkpoint.active_slot。
2. inactive = opposite(active)。
3. 清理 inactive slot 的临时状态。
4. 写 inactive.metadata_header。
5. 写 segment desc snapshot。
6. 写 DMP snapshot。
7. 写 dirty shard summary。
8. 写 MAC root。
9. 写 generation。
10. 计算并写 CRC。
11. flush inactive slot。
12. 原子切换 checkpoint.active_slot = inactive。
13. 写 CHECKPOINT_COMMIT log。
恢复时:
1. 读取 active slot。
2. 校验 generation 和 CRC。
3. 如果 active 有效,使用 active。
4. 如果 active 无效,校验 fallback slot。
5. 如果 fallback 有效,使用 fallback。
6. 如果双槽都无效,进入 system rollback。
7.3 Dirty Page Checkpoint 算法
DRR_CHECKPOINT()
1. checkpoint_generation++。
2. 写 CHECKPOINT_BEGIN log。
3. inactive_slot = opposite(active_slot)。
4. 遍历 per-cpu dirty_shard_list。
5. 跳过 dirty_count == 0 的 shard。
6. 对每个 dirty shard:
a. 找到关联 segment。
b. desc.state = CHECKPOINTING。
c. 冻结 writer。
d. flush PWC / per-CPU dirty buffer。
e. 只扫描 shard 内 dirty bit。
f. 复制 dirty ciphertext page 到 checkpoint region。
g. 计算 page MAC。
h. 写 dirty shard summary。
i. 清 shard bitmap。
j. shard.dirty_count = 0。
k. desc.state = ACTIVE。
7. 写 segment desc snapshot。
8. 写 DMP snapshot。
9. CHECKPOINT_METADATA_COMMIT(checkpoint_generation)。
提交规则:
只有存在 CHECKPOINT_COMMIT 且 CRC 正确的 checkpoint 才是稳定点。
中途崩溃的 checkpoint 直接丢弃。
A/B metadata 至少保留一个旧稳定点。
7.4 DRR Emergency Pool 分配算法
DRR Recovery 路径不能依赖普通 allocator。
DRR_EMERGENCY_ALLOC(size, class)
1. 从 DRR emergency pool 的 class freelist 取对象。
2. 如果 freelist 非空,返回对象。
3. 如果 freelist 为空,从 emergency pages 切分。
4. 如果 emergency pages 不足:
a. 写 EMERGENCY_POOL_EXHAUSTED。
b. 进入 system rollback。
Emergency Pool 包含:
DRR private stack
recovery log buffer
checkpoint metadata buffer
crash buffer
metadata slab
emergency pages
规则:
普通 allocator 不可使用 Emergency Pool。
Emergency Pool 不参与普通内存回收。
DRR OOM 直接视为不可恢复故障。
8. Rollback 算法
分三级。
8.1 Page Rollback
1. 定位最近稳定 checkpoint。
2. 校验 checkpoint page MAC。
3. 将旧密文页复制回 cipher data。
4. 恢复 page MAC。
5. 清 dirty bit。
6. 段保持 ACTIVE。
8.2 Segment Rollback
1. desc.state = RECOVERING。
2. 恢复 segment desc snapshot。
3. 恢复 DMP snapshot。
4. 恢复 key_epoch。
5. 恢复 dirty bitmap。
6. 恢复 mac_table。
7. 清除对应 PCKC key。
8. desc.state = ACTIVE。
8.3 System Rollback
1. DRR 写 crash reason。
2. 标记 boot attempt failed。
3. 触发 reboot。
4. bootloader 读取 BCB。
5. 如果失败次数超限,切换 last_good_slot。
9. 任务创建算法
task_create(entry, priority, flags)
1. 分配 TCB。
2. 生成 tid。
3. 生成 process_uuid。
4. 创建 utsm_process_context。
5. 创建 stack segment。
6. 创建 heap segment。
7. 可选创建 ipc segment。
8. 初始化 capability table。
9. cap[0] = stack。
10. cap[1] = heap。
11. 初始化 CPU context。
12. 通过 UTRW_WRITE 写入 task_start_packet。
13. hot_segment_hint = stack.segment_slot。
14. state = READY。
15. enqueue_task(current_cpu)。
10. 调度切换算法
schedule()
1. old = current。
2. utsm_switch_out(old)。
3. next = pick_next_task()。
4. utsm_switch_in(next)。
5. context_switch(old, next)。
utsm_switch_out:
1. 如果 old 有 PWC dirty,登记 flush pending。
2. 保存 old.hot_segment_hint。
3. 更新 old.recovery_generation。
4. 更新 heartbeat。
utsm_switch_in:
1. 如果 next.state == RECOVERING,跳过。
2. PCKC.current_process_uuid = next.crypto.process_uuid。
3. PCKC.current_crypto_epoch = next.crypto.crypto_epoch。
4. 预热 next.hot_segment_hint。
调度路径禁止:
扫描段
扫描 capability table
计算 MAC
写 checkpoint
重加密整段
11. 任务异常处理算法
UTRW_DETECT_FAULT(task, segment, error)
1. task.fault_segment_slot = segment.slot。
2. task.state = FAULTED。
3. 从 runqueue 移除。
4. 写 DRR fault event。
5. DRR 判断:
a. 刷新 capability。
b. page rollback。
c. segment rollback。
d. kill task。
e. system rollback。
任务 kill:
task_kill(task)
1. task.state = ZOMBIE。
2. 从 runqueue 移除。
3. revoke capability table。
4. owned segment key_epoch++。
5. desc.state = DESTROYED。
6. 加入 deferred free。
7. 写 TASK_KILL recovery log。
12. 复杂度总结
段定位:O(1)
UTRW 读写:O(n / 64)
PCKC 命中:O(1)
PCKC miss:O(KDF + key schedule)
Dirty 标记:O(1)
Checkpoint:O(number_of_dirty_shards + number_of_dirty_pages)
A/B metadata 切换:O(1)
DRR emergency alloc:O(1)
Page rollback:O(1 page)
Segment rollback:O(segment_dirty_pages + metadata)
调度切换额外成本:O(1)