ableos/ableos/src/arch/x86_64/task_switcher.rs

100 lines
2.5 KiB
Rust

use crate::scheduler::{Task, SCHEDULER};
/// Saves task's state onto stack
macro_rules! save_tasks_state {
() => {
"
// Copy task's state
push [rsp + 32] // SS
push [rsp + 32] // RSP
push [rsp + 32] // RFLAGS
push [rsp + 32] // CS
push [rsp + 32] // RIP
// Save task's registers
push r15
push r14
push r13
push r12
push r11
push r10
push r9
push r8
push rdi
push rsi
push rdx
push rcx
push rbx
push rax
"
};
}
pub(super) use save_tasks_state;
/// Save provided stack pointer into scheduler's queue
pub extern "C" fn save_and_enqueue(sp: u64) {
SCHEDULER.lock().enqueue_suspended(sp);
}
// Fetch and load next task
pub unsafe extern "C" fn switch_to_next() -> ! {
// Fetch next task
let next = SCHEDULER.lock().pop().expect("no task in the task queue");
match next {
Task::Suspended(sp) => asm!(
// Restore task's registers
"mov rsp, {}",
"pop rax",
"pop rbx",
"pop rcx",
"pop rdx",
"pop rsi",
"pop rdi",
"pop r8",
"pop r9",
"pop r10",
"pop r11",
"pop r12",
"pop r13",
"pop r14",
"pop r15",
// Copy things up the stack
"add rsp, 80", // Move 8 bytes above exception stack frame
"push [rsp - 48]", // SS
"push [rsp - 48]", // RSP
"push [rsp - 48]", // RFLAGS
"push [rsp - 48]", // CS
"push [rsp - 48]", // RIP
// Signalise end of the interrupt and return
"push rax",
"mov al, 32",
"out 20h, al",
"pop rax",
"iretq",
in(reg) sp,
options(noreturn),
),
Task::Spawn {
function,
stack_start,
} => asm!(
"add rsp, 160", // Move above saved registries
"mov [rsp], {ip}", // Set task's instruction pointer
"mov [rsp + 24], {sp}", // Set task's stack pointer
// Signalise the end of the interrupt and return
"mov al, 32",
"out 20h, al",
"iretq",
ip = in(reg) function,
sp = in(reg) stack_start,
options(noreturn),
),
}
}