#include #include #include #include #include #include #include // 汇编函数:context_switch(UINT64* old_rsp, UINT64 new_rsp) extern "C" void context_switch(UINT64* old_rsp, UINT64 new_rsp); static task_t g_tasks[TASK_MAX]; static UINT32 g_task_count = 0; static task_t* g_current = NULL; static task_t* g_task_list = NULL; // 循环链表头 // 跳板函数:新任务在 context_switch 后首先执行的函数 static void (*g_task_entries[TASK_MAX])(void); extern "C" void task_entry_trampoline() { ASM("sti"); task_t* cur = scheduler_current(); if (cur && g_task_entries[cur->id]) { g_task_entries[cur->id](); } task_exit(); } task_t* task_create(const char* name, void (*entry)(void)) { if (g_task_count >= TASK_MAX) { serial_write("SCHED: task limit reached\n"); return NULL; } UINT32 id = g_task_count++; task_t* task = &g_tasks[id]; g_task_entries[id] = entry; // 分配内核栈 UINTN stack_pages = TASK_STACK_SIZE / PAGE_SIZE; void* stack = pmm_alloc_pages(stack_pages); if (!stack) { serial_write("SCHED: stack alloc failed for task "); serial_write(name); serial_write("\n"); return NULL; } task->id = id; task->state = TASK_STATE_READY; task->stack_base = stack; task->time_slice = TIME_SLICE_DEFAULT; // 复制任务名称 str_copy(task->name, name, TASK_NAME_LEN); // 设置首次 context_switch 时的初始栈 // 栈向下增长。context_switch 会弹出 6 个寄存器然后 ret。 // // 布局(高地址 → 低地址): // [stack + TASK_STACK_SIZE] <- 栈顶 // 返回地址 = task_entry_trampoline(ret 跳转到这里) // rbx = 0 // rbp = 0 // r12 = 0 // r13 = 0 // r14 = 0 // r15 = 0 <- RSP 初始指向这里 // UINT64* sp = (UINT64*)((UINT8*)stack + TASK_STACK_SIZE); *--sp = (UINT64)task_entry_trampoline; *--sp = 0; // rbx *--sp = 0; // rbp *--sp = 0; // r12 *--sp = 0; // r13 *--sp = 0; // r14 *--sp = 0; // r15 task->rsp = (UINT64)sp; // 插入循环链表 if (g_task_list == NULL) { task->next = task; g_task_list = task; } else { task->next = g_task_list->next; g_task_list->next = task; g_task_list = task; } serial_write("SCHED: created task '"); serial_write(task->name); serial_write("' id="); serial_write_hex(id); serial_write("\n"); return task; } // 在循环链表中查找下一个就绪任务 static task_t* find_next_ready(void) { if (g_current == NULL || g_task_list == NULL) return NULL; task_t* next = g_current->next; task_t* start = next; do { if (next->state == TASK_STATE_READY) { return next; } next = next->next; } while (next != start); return NULL; // 没有就绪任务 } void yield(void) { if (g_current == NULL || g_task_list == NULL) return; task_t* cur = g_current; task_t* next = find_next_ready(); if (next == NULL || next == cur) return; if (cur->state != TASK_STATE_TERMINATED) cur->state = TASK_STATE_READY; next->state = TASK_STATE_RUNNING; next->time_slice = TIME_SLICE_DEFAULT; g_current = next; context_switch(&cur->rsp, next->rsp); } // 定时器 tick 处理 — 由 PIT IRQ 0 调用 void scheduler_tick(void) { if (g_current == NULL) return; // 递减时间片 if (g_current->time_slice > 0) { g_current->time_slice--; } // 时间片用完则抢占 if (g_current->time_slice == 0) { task_t* cur = g_current; task_t* next = find_next_ready(); if (next == NULL || next == cur) { // 没有其他就绪任务,或仅此一个 — 重置时间片 cur->time_slice = TIME_SLICE_DEFAULT; return; } // 抢占 cur->state = TASK_STATE_READY; cur->time_slice = TIME_SLICE_DEFAULT; next->state = TASK_STATE_RUNNING; next->time_slice = TIME_SLICE_DEFAULT; g_current = next; context_switch(&cur->rsp, next->rsp); } } void scheduler_run(void) { if (g_task_list == NULL) { serial_write("SCHED: no tasks to run\n"); return; } // 查找第一个就绪任务 task_t* start = g_task_list->next; task_t* t = start; do { if (t->state == TASK_STATE_READY) { break; } t = t->next; } while (t != start); if (t->state != TASK_STATE_READY) { serial_write("SCHED: no READY tasks\n"); return; } g_current = t; t->state = TASK_STATE_RUNNING; t->time_slice = TIME_SLICE_DEFAULT; serial_write("SCHED: starting task '"); serial_write(t->name); serial_write("'\n"); // 首次上下文切换 — 切换到任务栈 // 此后不会返回(直到所有任务终止) UINT64 dummy_rsp; context_switch(&dummy_rsp, t->rsp); // 只有所有任务终止后才会返回到这里 serial_write("SCHED: all tasks finished\n"); while (1) ASM ("hlt"); } void task_exit(void) { if (g_current == NULL) return; serial_write("SCHED: task '"); serial_write(g_current->name); serial_write("' exited\n"); g_current->state = TASK_STATE_TERMINATED; // 让出 CPU 给下一个任务 — 不会回来 yield(); // 不应到达此处 while (1) ASM ("hlt"); } task_t* scheduler_current(void) { return g_current; }