Files
Deshab-OS/CODE/UTSM/sched/sched.c
T
Linehu dda0cc9dd0 feat: sealed memory early init + verify - UTSM-E01..E04 very-early panic
- NEW core/sealed.c: utsm_sealed_early_init() runs right after utsm_init:
  empty .sealed section -> UTSM-E01 panic; no root key -> UTSM-E02;
  establishes BLAKE2b(root_key) MAC over [__sealed_start,__sealed_end).
- utsm_sealed_verify(): MAC mismatch -> UTSM-E03; verify-before-init ->
  UTSM-E04. Wired into utsm_selftest (U3+ step).
- .sealed region now non-empty by construction: sealed brand record
  "DESHAB-SEALED-MEMORY-V1-DEAICUP" lives in section(".sealed").
- Before this commit nothing ever referenced __sealed_start/__sealed_end:
  the sealed section was never registered, MACed or verified.
- QEMU verify: [SEAL] region=0x20 bytes, MAC established, selftest OK,
  boot reaches wizard, zero spurious panics.

[STUB] P0/UTSM/core/sealed.c | 剩余STUB命中=101(违规=0) | “封缄即落款,空区即自爆” | 已提交=<this>
2026-10-03 15:40:00 +08:00

760 lines
29 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* sched.c — SAS-R0-PCQ 调度器实现(ROADMAP Phase 7)
*
* 冻结 ABI(include/utsm/sched.h)9 个 API 的真实现 + 内核扩展层
* (include/utsm/sched_ext.h)。
*
* 设计要点:
* - O(1) 热路径:ready_bitmap ctz 选最高优先级(0 最高),head[] 取出
* 即出队;enqueue/dequeue 均为 O(1) 侵入式 FIFO(slot 索引非指针)。
* - 抢占 = xv6 式栈驱动切换:IRQ 帧落在被抢占任务自己的栈上,切换只换
* rsp(arch.rsp);恢复时沿原栈 iretq。TCB arch.rip/rflags 占位零。
* - tick 源 = LAPIC timer(宿主自持,见 arch/x86_64/lapic_timer.c)。
* - 本迭代 BSP-only:runqueue 数组结构就位,仅用 cpu0。
* - 切换路径只触碰 crypto_context 指针;禁止扫描 capability / 计算
* MAC / 写 checkpoint(设计约束,见 docs/RE/UTSM_算法记录.md §10)。
*/
#include <utsm/sched.h>
#include <utsm/sched_ext.h>
#include <utsm/log.h>
#include <utsm/panic.h>
#include <utsm/arena.h>
#include <utsm/config.h>
#include <utsm/process.h>
#include <utsm/idt.h>
#include <utsm/drr.h>
#include <utsm/lapic_timer.h>
#include <utsm/dkm.h>
void utsm_sched_switch(utsm_sched_tcb *prev, utsm_sched_tcb *next); /* switch.S */
void utsm_task_trampoline(void); /* switch.S */
#define UTSM_SCHED_MAX_TASKS 64
#define UTSM_SCHED_MAX_CPUS 8
#define UTSM_SCHED_NO_PROCESS 0xFFFFFFFFu
struct task_aux {
void (*entry)(void *);
void *arg;
u64 stack_base;
u64 run_start_ns;
};
static utsm_sched_tcb g_task_table[UTSM_SCHED_MAX_TASKS];
static utsm_sched_run_queue g_runqueues[UTSM_SCHED_MAX_CPUS];
static utsm_sched_run_queue *g_rq_ptrs[UTSM_SCHED_MAX_CPUS];
static struct task_aux g_task_aux[UTSM_SCHED_MAX_TASKS];
static volatile int g_sched_enabled = 0;
static volatile int g_switch_lock = 0;
static u64 g_uptime_ns = 0;
static u64 g_tick_ns = 10ULL * 1000ULL * 1000ULL; /* 100Hz */
static u64 g_timeslice_ns = 10ULL * 1000ULL * 1000ULL; /* 10ms */
static u32 g_cfg_tick_hz = 100;
static u32 g_demo_ms = 1000;
static int g_demo_fault = 0;
static int g_wake_pending = 0;
static u32 g_bootstrap_slot = UTSM_SCHED_INVALID_SLOT;
/* ---- switch.S 依赖的 TCB/arch 布局断言 ---- */
#define OFFS(t, m) ((u32)__builtin_offsetof(t, m))
_Static_assert(OFFS(utsm_sched_tcb, arch) == 80, "switch.S: arch@80");
_Static_assert(OFFS(utsm_sched_arch_context, rsp) == 0, "switch.S: rsp@0");
_Static_assert(OFFS(utsm_sched_arch_context, rbx) == 24, "switch.S: rbx@24");
_Static_assert(OFFS(utsm_sched_arch_context, rbp) == 32, "switch.S: rbp@32");
_Static_assert(OFFS(utsm_sched_arch_context, r12) == 40, "switch.S: r12@40");
_Static_assert(OFFS(utsm_sched_arch_context, r15) == 64, "switch.S: r15@64");
_Static_assert(UTSM_SCHED_PRIORITY_LOWEST == 63, "switch/bitmap: 64 prio");
static u32 task_slot_of(const utsm_sched_tcb *t) {
return (u32)(t - g_task_table);
}
/* ===================================================================
* 冻结 ABI 实现(sched.h)
* =================================================================== */
int utsm_sched_init(void) {
for (u32 i = 0; i < UTSM_SCHED_MAX_TASKS; i++) {
utsm_sched_tcb *t = &g_task_table[i];
u64 *w = (u64 *)t;
for (u64 k = 0; k < sizeof(*t) / sizeof(u64); k++) w[k] = 0;
t->abi_version = UTSM_SCHED_ABI_VERSION;
t->struct_size = (u32)sizeof(utsm_sched_tcb);
t->state = UTSM_SCHED_TASK_UNUSED;
t->runq_prev = UTSM_SCHED_INVALID_SLOT;
t->runq_next = UTSM_SCHED_INVALID_SLOT;
g_task_aux[i].entry = 0;
g_task_aux[i].arg = 0;
g_task_aux[i].stack_base = 0;
g_task_aux[i].run_start_ns = 0;
}
for (u32 c = 0; c < UTSM_SCHED_MAX_CPUS; c++) g_rq_ptrs[c] = &g_runqueues[c];
g_sched_enabled = 0;
g_uptime_ns = 0;
g_bootstrap_slot = UTSM_SCHED_INVALID_SLOT;
return UTSM_SCHED_OK;
}
int utsm_sched_cpu_init(u32 cpu_id, utsm_sched_run_queue *queue) {
if (cpu_id >= UTSM_SCHED_MAX_CPUS) return UTSM_SCHED_ERR_INVALID;
utsm_sched_run_queue *rq = queue ? queue : &g_runqueues[cpu_id];
u64 *w = (u64 *)rq;
for (u64 k = 0; k < sizeof(*rq) / sizeof(u64); k++) w[k] = 0;
rq->abi_version = UTSM_SCHED_ABI_VERSION;
rq->struct_size = (u32)sizeof(utsm_sched_run_queue);
rq->cpu_id = cpu_id;
for (u32 p = 0; p < UTSM_SCHED_PRIORITY_COUNT; p++) {
rq->head[p] = UTSM_SCHED_INVALID_SLOT;
rq->tail[p] = UTSM_SCHED_INVALID_SLOT;
}
rq->current_task_slot = UTSM_SCHED_INVALID_SLOT;
rq->idle_task_slot = UTSM_SCHED_INVALID_SLOT;
rq->ready_count = 0;
g_rq_ptrs[cpu_id] = rq;
return UTSM_SCHED_OK;
}
int utsm_sched_task_init(utsm_sched_tcb *task, u64 task_id,
u32 process_slot, u32 priority, u64 affinity_mask) {
if (!task || priority >= UTSM_SCHED_PRIORITY_COUNT) return UTSM_SCHED_ERR_INVALID;
u32 slot = task_slot_of(task);
if (slot >= UTSM_SCHED_MAX_TASKS) return UTSM_SCHED_ERR_INVALID;
if (task->state != UTSM_SCHED_TASK_UNUSED) return UTSM_SCHED_ERR_STATE;
task->task_id = task_id;
task->process_slot = process_slot;
task->flags = 0;
task->state = UTSM_SCHED_TASK_NEW;
task->priority = priority;
task->assigned_cpu = 0;
task->last_cpu = 0;
task->affinity_mask = affinity_mask;
task->timeslice_ns = 0;
task->wake_deadline_ns = 0;
task->crypto_context = 0;
task->runq_prev = UTSM_SCHED_INVALID_SLOT;
task->runq_next = UTSM_SCHED_INVALID_SLOT;
task->arch.rsp = 0;
task->arch.rip = 0;
task->arch.rflags = 0;
task->arch.rbx = 0;
task->arch.rbp = 0;
task->arch.r12 = 0;
task->arch.r13 = 0;
task->arch.r14 = 0;
task->arch.r15 = 0;
return UTSM_SCHED_OK;
}
static void rq_link(utsm_sched_run_queue *rq, utsm_sched_tcb *t) {
u32 slot = task_slot_of(t);
u32 p = t->priority;
t->runq_next = UTSM_SCHED_INVALID_SLOT;
if (rq->head[p] == UTSM_SCHED_INVALID_SLOT) {
t->runq_prev = UTSM_SCHED_INVALID_SLOT;
rq->head[p] = slot;
rq->tail[p] = slot;
rq->ready_bitmap |= 1ULL << p;
} else {
u32 tail = rq->tail[p];
t->runq_prev = tail;
g_task_table[tail].runq_next = slot;
rq->tail[p] = slot;
}
rq->ready_count++;
}
static void rq_unlink(utsm_sched_run_queue *rq, utsm_sched_tcb *t) {
u32 slot = task_slot_of(t);
u32 p = t->priority;
u32 prev = t->runq_prev;
u32 next = t->runq_next;
if (prev != UTSM_SCHED_INVALID_SLOT) g_task_table[prev].runq_next = next;
if (next != UTSM_SCHED_INVALID_SLOT) g_task_table[next].runq_prev = prev;
if (rq->head[p] == slot) rq->head[p] = next;
if (rq->tail[p] == slot) rq->tail[p] = prev;
if (rq->head[p] == UTSM_SCHED_INVALID_SLOT) {
rq->ready_bitmap &= ~(1ULL << p);
}
t->runq_prev = UTSM_SCHED_INVALID_SLOT;
t->runq_next = UTSM_SCHED_INVALID_SLOT;
if (rq->ready_count > 0) rq->ready_count--;
}
int utsm_sched_enqueue(u32 cpu_id, utsm_sched_tcb *task) {
if (!task || cpu_id >= UTSM_SCHED_MAX_CPUS) return UTSM_SCHED_ERR_INVALID;
if (task->state == UTSM_SCHED_TASK_READY ||
task->state == UTSM_SCHED_TASK_RUNNING) {
return UTSM_SCHED_ERR_STATE;
}
task->assigned_cpu = cpu_id;
task->state = UTSM_SCHED_TASK_READY;
rq_link(g_rq_ptrs[cpu_id], task);
return UTSM_SCHED_OK;
}
int utsm_sched_dequeue(utsm_sched_tcb *task) {
if (!task) return UTSM_SCHED_ERR_INVALID;
if (task->state != UTSM_SCHED_TASK_READY) return UTSM_SCHED_OK; /* 幂等 */
rq_unlink(g_rq_ptrs[task->assigned_cpu], task);
return UTSM_SCHED_OK;
}
int utsm_sched_block(utsm_sched_tcb *task, u32 blocked_state) {
if (!task) return UTSM_SCHED_ERR_INVALID;
if (blocked_state != UTSM_SCHED_TASK_BLOCKED &&
blocked_state != UTSM_SCHED_TASK_SLEEPING) {
return UTSM_SCHED_ERR_INVALID;
}
if (task->state == UTSM_SCHED_TASK_READY) {
rq_unlink(g_rq_ptrs[task->assigned_cpu], task);
} else if (task->state != UTSM_SCHED_TASK_RUNNING) {
return UTSM_SCHED_ERR_STATE;
}
task->state = blocked_state;
return UTSM_SCHED_OK;
}
int utsm_sched_wake(utsm_sched_tcb *task) {
if (!task) return UTSM_SCHED_ERR_INVALID;
if (task->state != UTSM_SCHED_TASK_BLOCKED &&
task->state != UTSM_SCHED_TASK_SLEEPING) {
return UTSM_SCHED_ERR_STATE;
}
return utsm_sched_enqueue(task->assigned_cpu, task);
}
/* pick 即出队;纯队列操作,不改 current_task_slot(selftest 依赖此语义) */
int utsm_sched_pick_next(u32 cpu_id, utsm_sched_tcb **out_task) {
if (!out_task || cpu_id >= UTSM_SCHED_MAX_CPUS) return UTSM_SCHED_ERR_INVALID;
utsm_sched_run_queue *rq = g_rq_ptrs[cpu_id];
if (rq->ready_bitmap == 0) {
*out_task = 0;
return UTSM_SCHED_ERR_NO_TASK;
}
u32 p = (u32)__builtin_ctzll(rq->ready_bitmap); /* 0 = 最高优先级 */
u32 slot = rq->head[p];
if (slot >= UTSM_SCHED_MAX_TASKS) {
*out_task = 0;
return UTSM_SCHED_ERR_NO_TASK;
}
utsm_sched_tcb *t = &g_task_table[slot];
rq_unlink(rq, t);
t->state = UTSM_SCHED_TASK_RUNNING;
t->last_cpu = cpu_id;
g_task_aux[slot].run_start_ns = g_uptime_ns;
*out_task = t;
return UTSM_SCHED_OK;
}
int utsm_sched_tick(u32 cpu_id, u64 elapsed_ns, utsm_sched_tcb **out_preempted_task) {
if (out_preempted_task) *out_preempted_task = 0;
g_wake_pending = 0;
g_uptime_ns += elapsed_ns;
/* 唤醒到期 sleeper(非热路径:任务数 <= 64 线性扫描) */
for (u32 i = 0; i < UTSM_SCHED_MAX_TASKS; i++) {
utsm_sched_tcb *t = &g_task_table[i];
if (t->state == UTSM_SCHED_TASK_SLEEPING &&
t->wake_deadline_ns != 0 && t->wake_deadline_ns <= g_uptime_ns) {
t->wake_deadline_ns = 0;
utsm_sched_wake(t);
g_wake_pending = 1;
}
}
utsm_sched_run_queue *rq = g_rq_ptrs[cpu_id];
u32 cur_slot = rq->current_task_slot;
if (cur_slot == UTSM_SCHED_INVALID_SLOT) return UTSM_SCHED_OK;
utsm_sched_tcb *cur = &g_task_table[cur_slot];
if (cur->state != UTSM_SCHED_TASK_RUNNING) return UTSM_SCHED_OK;
u64 ran = g_uptime_ns - g_task_aux[cur_slot].run_start_ns;
if (ran >= g_timeslice_ns && out_preempted_task) {
*out_preempted_task = cur;
}
return UTSM_SCHED_OK;
}
/* ===================================================================
* 内核扩展层(sched_ext.h)
* =================================================================== */
void utsm_sched_config(u32 tick_hz, u32 timeslice_ms, u32 demo_ms, int demo_fault) {
g_cfg_tick_hz = tick_hz ? tick_hz : 100;
if (timeslice_ms) g_timeslice_ns = (u64)timeslice_ms * 1000000ULL;
g_demo_ms = demo_ms;
g_demo_fault = demo_fault;
}
int utsm_sched_bootstrap_init(void) {
utsm_sched_init();
utsm_sched_cpu_init(0, 0);
u32 slot = UTSM_SCHED_MAX_TASKS;
for (u32 i = 0; i < UTSM_SCHED_MAX_TASKS; i++) {
if (g_task_table[i].state == UTSM_SCHED_TASK_UNUSED) { slot = i; break; }
}
if (slot == UTSM_SCHED_MAX_TASKS) return UTSM_SCHED_ERR_NO_TASK;
utsm_sched_tcb *t = &g_task_table[slot];
utsm_sched_task_init(t, 1, UTSM_SCHED_NO_PROCESS,
UTSM_SCHED_PRIORITY_LOWEST, ~0ULL);
t->flags = UTSM_SCHED_TASK_F_KERNEL | UTSM_SCHED_TASK_F_NO_MIGRATE;
t->state = UTSM_SCHED_TASK_RUNNING;
u64 rsp;
__asm__ volatile("mov %%rsp, %0" : "=r"(rsp));
t->arch.rsp = rsp; /* bootstrap 复用 boot.S kernel_stack,不迁移栈 */
g_task_aux[slot].entry = 0;
g_task_aux[slot].arg = 0;
g_task_aux[slot].stack_base = 0;
g_task_aux[slot].run_start_ns = 0;
g_rq_ptrs[0]->current_task_slot = slot;
g_bootstrap_slot = slot;
log_info("[SCHED] bootstrap bound");
log_hex64("[SCHED] slot=", slot);
return (int)slot;
}
int utsm_task_create(u32 process_slot, u32 priority, void (*entry)(void *), void *arg) {
if (!entry || priority >= UTSM_SCHED_PRIORITY_COUNT) return UTSM_SCHED_ERR_INVALID;
u32 slot = UTSM_SCHED_MAX_TASKS;
for (u32 i = 0; i < UTSM_SCHED_MAX_TASKS; i++) {
if (g_task_table[i].state == UTSM_SCHED_TASK_UNUSED) { slot = i; break; }
}
if (slot == UTSM_SCHED_MAX_TASKS) return UTSM_SCHED_ERR_NO_TASK;
void *stack = kmem_alloc_page(4); /* 16KB 任务栈(arena,非 DMA 资源) */
if (!stack) return UTSM_SCHED_ERR_NO_TASK;
u64 top = ((u64)stack + 4 * UTSM_PAGE_SIZE) & ~15ULL;
utsm_sched_tcb *t = &g_task_table[slot];
int rc = utsm_sched_task_init(t, 0x1000ULL + slot, process_slot, priority, ~0ULL);
if (rc != UTSM_SCHED_OK) return rc;
t->flags = UTSM_SCHED_TASK_F_KERNEL;
/* crypto_context 指针:切换路径唯一触碰的加密状态 */
if (process_slot != UTSM_SCHED_NO_PROCESS) {
utsm_process_context *proc = utsm_process_get(process_slot);
if (proc) t->crypto_context = &proc->crypto_ctx;
}
/* 伪造初始栈帧(与 switch.S 的 push/pop 布局逐字节对应):
* sp[0]=r15 sp[1]=r14 sp[2]=r13 sp[3]=r12 sp[4]=rbx(slot) sp[5]=rbp
* sp[6]=&trampoline;ret 后 rsp=top(16 对齐,满足 call ABI) */
u64 *sp = (u64 *)(top - 56);
sp[0] = 0;
sp[1] = 0;
sp[2] = 0;
sp[3] = 0;
sp[4] = (u64)slot;
sp[5] = 0;
sp[6] = (u64)&utsm_task_trampoline;
t->arch.rsp = (u64)sp;
g_task_aux[slot].entry = entry;
g_task_aux[slot].arg = arg;
g_task_aux[slot].stack_base = (u64)stack;
g_task_aux[slot].run_start_ns = 0;
rc = utsm_sched_enqueue(0, t);
if (rc != UTSM_SCHED_OK) return rc;
return (int)slot;
}
void utsm_task_main(u64 slot) {
if (slot >= UTSM_SCHED_MAX_TASKS) {
drr_system_rollback("scheduler: trampoline bad slot");
}
struct task_aux *aux = &g_task_aux[slot];
void (*entry)(void *) = aux->entry;
void *arg = aux->arg;
if (entry) entry(arg);
utsm_sched_task_exit();
for (;;) { __asm__ volatile("cli; hlt"); }
}
void utsm_sched_schedule(void) {
utsm_sched_run_queue *rq = g_rq_ptrs[0];
u32 cur_slot = rq->current_task_slot;
if (cur_slot == UTSM_SCHED_INVALID_SLOT) return;
utsm_sched_tcb *cur = &g_task_table[cur_slot];
u64 flags;
__asm__ volatile("pushfq; popq %0; cli" : "=r"(flags) :: "memory");
g_switch_lock = 1;
if (cur->state == UTSM_SCHED_TASK_RUNNING) {
cur->state = UTSM_SCHED_TASK_READY;
rq_link(rq, cur);
}
utsm_sched_tcb *next = 0;
int rc = utsm_sched_pick_next(0, &next);
if (rc != UTSM_SCHED_OK || !next) {
if (cur->state == UTSM_SCHED_TASK_READY) {
/* 仅当前任务可运行:取回继续 */
rq_unlink(rq, cur);
cur->state = UTSM_SCHED_TASK_RUNNING;
g_task_aux[cur_slot].run_start_ns = g_uptime_ns;
g_switch_lock = 0;
__asm__ volatile("pushq %0; popfq" :: "r"(flags) : "memory");
return;
}
/* 当前任务不可运行且无任务可切换 → 恢复根接管 */
g_switch_lock = 0;
drr_system_rollback("scheduler: no runnable task");
for (;;) { __asm__ volatile("cli; hlt"); }
}
if (next == cur) {
cur->state = UTSM_SCHED_TASK_RUNNING;
g_task_aux[cur_slot].run_start_ns = g_uptime_ns;
g_switch_lock = 0;
__asm__ volatile("pushq %0; popfq" :: "r"(flags) : "memory");
return;
}
rq->current_task_slot = task_slot_of(next);
g_switch_lock = 0;
utsm_sched_switch(cur, next); /* 切走;恢复点在下一行 */
__asm__ volatile("pushq %0; popfq" :: "r"(flags) : "memory");
}
void utsm_sched_yield(void) {
utsm_sched_schedule();
}
void utsm_sched_sleep_ms(u32 ms) {
utsm_sched_run_queue *rq = g_rq_ptrs[0];
u32 cur_slot = rq->current_task_slot;
if (cur_slot == UTSM_SCHED_INVALID_SLOT) return;
utsm_sched_tcb *cur = &g_task_table[cur_slot];
cur->wake_deadline_ns = g_uptime_ns + (u64)ms * 1000000ULL;
utsm_sched_block(cur, UTSM_SCHED_TASK_SLEEPING);
utsm_sched_schedule();
}
void utsm_sched_task_exit(void) {
utsm_sched_run_queue *rq = g_rq_ptrs[0];
u32 cur_slot = rq->current_task_slot;
if (cur_slot == UTSM_SCHED_INVALID_SLOT) {
for (;;) { __asm__ volatile("cli; hlt"); }
}
utsm_sched_tcb *cur = &g_task_table[cur_slot];
/* crypto erase:推进纪元使该进程旧密文全部失效 */
utsm_crypto_context *cc = (utsm_crypto_context *)cur->crypto_context;
if (cc) cc->crypto_epoch++;
drr_watchdog_unregister(cur_slot); /* 防止看门狗对已退出任务误报 */
cur->state = UTSM_SCHED_TASK_ZOMBIE;
__asm__ volatile("cli" ::: "memory");
utsm_sched_tcb *next = 0;
if (utsm_sched_pick_next(0, &next) != UTSM_SCHED_OK || !next) {
drr_system_rollback("scheduler: no task after exit");
for (;;) { __asm__ volatile("cli; hlt"); }
}
rq->current_task_slot = task_slot_of(next);
utsm_sched_switch(cur, next); /* 不返回 */
for (;;) { __asm__ volatile("cli; hlt"); }
}
int utsm_sched_task_kill(u32 task_slot) {
if (task_slot >= UTSM_SCHED_MAX_TASKS) return UTSM_SCHED_ERR_INVALID;
if (task_slot == g_bootstrap_slot) return UTSM_SCHED_ERR_STATE;
utsm_sched_tcb *t = &g_task_table[task_slot];
if (t->state == UTSM_SCHED_TASK_UNUSED || t->state == UTSM_SCHED_TASK_ZOMBIE) {
return UTSM_SCHED_OK;
}
if (t->state == UTSM_SCHED_TASK_RUNNING) return UTSM_SCHED_ERR_STATE;
utsm_crypto_context *cc = (utsm_crypto_context *)t->crypto_context;
if (cc) cc->crypto_epoch++;
drr_watchdog_unregister(task_slot);
utsm_sched_dequeue(t);
t->state = UTSM_SCHED_TASK_ZOMBIE;
return UTSM_SCHED_OK;
}
void utsm_sched_fault_task(u32 task_slot) {
if (task_slot >= UTSM_SCHED_MAX_TASKS) return;
utsm_sched_tcb *t = &g_task_table[task_slot];
if (t->state == UTSM_SCHED_TASK_UNUSED || t->state == UTSM_SCHED_TASK_ZOMBIE) return;
utsm_crypto_context *cc = (utsm_crypto_context *)t->crypto_context;
if (cc) cc->crypto_epoch++;
drr_watchdog_unregister(task_slot);
t->state = UTSM_SCHED_TASK_FAULTED;
utsm_sched_dequeue(t);
utsm_sched_run_queue *rq = g_rq_ptrs[0];
if (rq->current_task_slot == task_slot) {
/* fault 任务是当前任务(tick/异常上下文):杀掉并切走,不返回 */
t->state = UTSM_SCHED_TASK_ZOMBIE;
__asm__ volatile("cli" ::: "memory");
utsm_sched_tcb *next = 0;
if (utsm_sched_pick_next(0, &next) != UTSM_SCHED_OK || !next) {
drr_system_rollback("scheduler: no task after fault");
for (;;) { __asm__ volatile("cli; hlt"); }
}
rq->current_task_slot = task_slot_of(next);
utsm_sched_switch(t, next);
for (;;) { __asm__ volatile("cli; hlt"); }
}
t->state = UTSM_SCHED_TASK_ZOMBIE;
}
u32 utsm_sched_current_slot(void) {
return g_rq_ptrs[0]->current_task_slot;
}
/* ===================================================================
* tick / 异常钩子 / enable / quiesce / demo
* =================================================================== */
static int utsm_tick_handler(u8 vector) {
(void)vector;
lapic_timer_eoi(); /* EOI 先行:切换不得悬挂 in-service 位 */
drr_heartbeat_tick();
if (!g_sched_enabled) return 1;
drr_watchdog_check(); /* 可能杀当前任务并切换(不返回) */
utsm_sched_tcb *preempted = 0;
utsm_sched_tick(0, g_tick_ns, &preempted);
if (preempted || g_wake_pending) {
utsm_sched_schedule();
}
return 1; /* 自负 EOI 全责(idt.c 约定) */
}
static int utsm_sched_exc_hook(u64 vector, u64 err, u64 rip) {
(void)err;
if (!g_sched_enabled) return 0; /* 原路径:全量日志 + 停机 */
u32 cur = g_rq_ptrs[0]->current_task_slot;
if (cur == UTSM_SCHED_INVALID_SLOT || cur == g_bootstrap_slot) return 0;
/* 任务级 fault:DRR 接管(页级回滚 + 杀任务 + 切换),本函数不返回 */
log_error("[SCHED] task fault");
log_hex64("[SCHED] vector=", vector);
log_hex64("[SCHED] rip=", rip);
drr_handle_task_fault(cur, "cpu exception");
return 1; /* 不可达:fault 路径已切换任务或 system rollback */
}
int utsm_sched_enable(u32 tick_hz) {
if (tick_hz == 0) tick_hz = g_cfg_tick_hz;
g_tick_ns = 1000000000ULL / tick_hz;
if (lapic_timer_init(tick_hz) != 0) {
log_error("[SCHED] lapic timer init failed, stays cooperative");
return -1;
}
int vec = lapic_timer_vector();
if (vec < 0 || irq_register((u8)vec, utsm_tick_handler) != 0) {
lapic_timer_stop();
log_error("[SCHED] tick handler registration failed");
return -2;
}
idt_set_exception_hook(utsm_sched_exc_hook);
drr_set_sched_fault_cb(utsm_sched_fault_task);
lapic_timer_start(); /* handler 就位后再放开投递 */
g_sched_enabled = 1;
log_info("[SCHED] enable (LAPIC timer)");
log_hex64("[SCHED] tick_hz=", tick_hz);
return 0;
}
void utsm_sched_quiesce(void) {
__asm__ volatile("cli" ::: "memory");
g_sched_enabled = 0;
idt_set_exception_hook(0); /* 恢复 DSK 阶段异常诊断行为 */
drr_set_sched_fault_cb(0);
lapic_timer_stop();
for (u32 i = 0; i < UTSM_SCHED_MAX_TASKS; i++) {
if (i == g_bootstrap_slot) continue;
utsm_sched_tcb *t = &g_task_table[i];
if (t->state == UTSM_SCHED_TASK_UNUSED || t->state == UTSM_SCHED_TASK_ZOMBIE) continue;
utsm_crypto_context *cc = (utsm_crypto_context *)t->crypto_context;
if (cc) cc->crypto_epoch++;
utsm_sched_dequeue(t);
t->state = UTSM_SCHED_TASK_ZOMBIE;
}
log_info("[SCHED] quiesce");
log_info("[SCHED] timer stopped");
/* BUG-GP-IRET: 保持 IF=0 交接不变式(恢复漂移前行为)。
* VM-exit 后 host RFLAGS=0x2(IF=0),DSM/selftest/DSK 交接全程 IF=0;
* 此处 sti 会让 apic_route_legacy=1 放开的 IRQ1/11/12 在 LAPIC IRR
* 挂起的中断于 dsk_load_and_jump 首条日志(log_emit popfq 恢复 IF=1)
* 之后立即投递,其 handler 返回的 iretq 触发 #GP(err=0)。DSK 加载
* 失败路径的日志在 IF=0 下同样可用(log_emit 不依赖 IF)。 */
__asm__ volatile("cli" ::: "memory");
}
/* ---- demo 任务(抢占证据:日志交错 + 看门狗负向演练) ---- */
static void demo_task_body(void *arg) {
u64 id = (u64)arg; /* 1=A, 2=B, 3=C */
static const char *const born_msg[4] = { "", "[TASK A] born", "[TASK B] born", "[TASK C] born" };
static const char *const iter_msg[4] = { "", "[TASK A] iter=", "[TASK B] iter=", "[TASK C] iter=" };
static const char *const prio_msg[4] = { "", "[TASK A] prio=", "[TASK B] prio=", "[TASK C] prio=" };
static const char *const exit_msg[4] = { "", "[TASK A] exit", "[TASK B] exit", "[TASK C] exit" };
u32 idx = (id < 4) ? (u32)id : 0;
u32 slot = utsm_sched_current_slot();
u32 prio = g_task_table[slot].priority;
log_info(born_msg[idx]);
log_hex64(prio_msg[idx], prio);
drr_watchdog_register(slot, 40); /* 400ms @100Hz */
for (u64 iter = 1; iter <= 3; iter++) {
drr_watchdog_kick(slot);
log_hex64(iter_msg[idx], iter);
utsm_sched_sleep_ms(50);
if (g_demo_fault && id == 3) {
/* 负向演练:停止 kick + 忙循环 → 看门狗 400ms 后捕获本任务 */
for (;;) { __asm__ volatile("pause"); }
}
}
log_info(exit_msg[idx]);
/* entry 返回 → trampoline 自动 task_exit */
}
void utsm_sched_demo_window(void) {
if (g_demo_ms == 0) {
log_info("[SCHED] demo disabled (demo_ms=0)");
return;
}
log_hex64("[SCHED] demo window enter, demo_ms=", g_demo_ms);
int a = utsm_task_create(UTSM_SCHED_NO_PROCESS, 1, demo_task_body, (void *)1ULL);
int b = utsm_task_create(UTSM_SCHED_NO_PROCESS, 20, demo_task_body, (void *)2ULL);
int c = utsm_task_create(UTSM_SCHED_NO_PROCESS, 40, demo_task_body, (void *)3ULL);
log_hex64("[SCHED] demo tasks=", (u64)((a >= 0) + (b >= 0) + (c >= 0)));
if (a < 0 || b < 0 || c < 0) {
/* 严格错误策略插桩:demo 任务建不全 = 调度器内部状态损坏,panic(SCH-E03) */
panic_full("SCH-E03 DEMO TASK CREATE FAILED",
"utsm_task_create failed inside demo window", 0);
}
if (utsm_sched_enable(0) != 0) {
/* 严格错误策略插桩:enable 失败不允许静默跳过演示窗口继续启动 */
panic_full("SCH-E02 SCHED ENABLE FAILED",
"utsm_sched_enable failed; skipping demo window is forbidden", 0);
return;
}
/* bootstrap 忙等窗口:bootstrap 优先级最低(63),每个时间片被
* tick 抢占后 demo 任务优先获得 CPU → 日志交错 = 抢占证据。
* 失速兜底:若心跳长时间无进展(tick 源失效/未投递),立即中止
* 窗口继续启动,绝不卡死 bootstrap。 */
u64 start = drr_heartbeat_get();
u64 ticks_needed = ((u64)g_demo_ms * 1000000ULL) / g_tick_ns + 2;
u64 last_hb = start;
u64 spin = 0;
while (drr_heartbeat_get() - start < ticks_needed) {
__asm__ volatile("pause");
if (++spin >= 20000000ULL) { /* ~0.1-0.5s 无进展即复查 */
u64 now = drr_heartbeat_get();
if (now == last_hb) {
log_warn("[SCHED] tick stall detected, abort demo window");
log_hex64("[SCHED] heartbeat=", now);
break;
}
last_hb = now;
spin = 0;
}
}
log_info("[SCHED] demo window done");
}
/* ===================================================================
* kernel_api 服务表 + selftest 钩子
* =================================================================== */
static u64 sched_api_uptime_ns(void) { return g_uptime_ns; }
static const utsm_sched_api g_sched_api = {
.uptime_ns = sched_api_uptime_ns,
.yield = utsm_sched_yield,
.current_task_slot = utsm_sched_current_slot,
.task_create = utsm_task_create,
.sleep_ms = utsm_sched_sleep_ms
};
const utsm_sched_api *utsm_sched_get_api(void) {
return &g_sched_api;
}
/* ---- selftest(协作式,无 tick) ---- */
static u32 st_alloc_slot(void) {
for (u32 i = 0; i < UTSM_SCHED_MAX_TASKS; i++) {
if (g_task_table[i].state == UTSM_SCHED_TASK_UNUSED) return i;
}
return UTSM_SCHED_MAX_TASKS;
}
int utsm_sched_selftest_runqueue(void) {
utsm_sched_tcb *t[3];
const u32 prios[3] = { 5, 10, 63 };
for (int k = 0; k < 3; k++) {
u32 slot = st_alloc_slot();
if (slot == UTSM_SCHED_MAX_TASKS) return -1;
t[k] = &g_task_table[slot];
if (utsm_sched_task_init(t[k], 0x9000ULL + k, UTSM_SCHED_NO_PROCESS,
prios[k], ~0ULL) != UTSM_SCHED_OK) return -1;
t[k]->flags = UTSM_SCHED_TASK_F_KERNEL;
if (utsm_sched_enqueue(0, t[k]) != UTSM_SCHED_OK) return -1;
}
/* 三轮:pick 顺序必须 5,10,63(pick 即出队,不重排 → 下一优先级) */
for (int round = 0; round < 3; round++) {
for (int k = 0; k < 3; k++) {
utsm_sched_tcb *p = 0;
if (utsm_sched_pick_next(0, &p) != UTSM_SCHED_OK || p != t[k]) return -2;
p->state = UTSM_SCHED_TASK_NEW; /* 模拟"不在队列" */
}
for (int k = 0; k < 3; k++) {
if (utsm_sched_enqueue(0, t[k]) != UTSM_SCHED_OK) return -3;
}
}
for (int k = 0; k < 3; k++) {
utsm_sched_dequeue(t[k]);
t[k]->state = UTSM_SCHED_TASK_UNUSED;
}
return 0;
}
int utsm_sched_selftest_blockwake(void) {
u32 sa = st_alloc_slot();
if (sa == UTSM_SCHED_MAX_TASKS) return -1;
utsm_sched_tcb *a = &g_task_table[sa];
if (utsm_sched_task_init(a, 0xA001, UTSM_SCHED_NO_PROCESS, 20, ~0ULL) != UTSM_SCHED_OK) return -1;
u32 sb = st_alloc_slot(); /* a 已 init(NEW),不会重复分配同一 slot */
if (sb == UTSM_SCHED_MAX_TASKS) return -1;
utsm_sched_tcb *b = &g_task_table[sb];
if (utsm_sched_task_init(b, 0xA002, UTSM_SCHED_NO_PROCESS, 30, ~0ULL) != UTSM_SCHED_OK) return -1;
utsm_sched_enqueue(0, a);
utsm_sched_enqueue(0, b);
/* block a → pick 跳过 a 取 b */
utsm_sched_block(a, UTSM_SCHED_TASK_BLOCKED);
utsm_sched_tcb *p = 0;
if (utsm_sched_pick_next(0, &p) != UTSM_SCHED_OK || p != b) return -2;
p->state = UTSM_SCHED_TASK_NEW;
/* wake a → 回到队列 → pick 取 a */
utsm_sched_wake(a);
if (utsm_sched_pick_next(0, &p) != UTSM_SCHED_OK || p != a) return -3;
p->state = UTSM_SCHED_TASK_NEW;
utsm_sched_dequeue(a);
utsm_sched_dequeue(b);
a->state = UTSM_SCHED_TASK_UNUSED;
b->state = UTSM_SCHED_TASK_UNUSED;
return 0;
}
int utsm_sched_debug_ready_count(u32 cpu_id) {
if (cpu_id >= UTSM_SCHED_MAX_CPUS) return -1;
return (int)g_rq_ptrs[cpu_id]->ready_count;
}