feat(sched): implement preemptive time-slicing multitasking via PIT 8254 timer ISR (Vector 32)
This commit is contained in:
@@ -0,0 +1,49 @@
|
|||||||
|
/* opencoreC - Timer Preemptive Interrupt Trampoline (Vector 32 / 0x20) */
|
||||||
|
.global timer_isr_entry
|
||||||
|
.extern timer_interrupt_handler
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
timer_isr_entry:
|
||||||
|
/* 1. Save all general-purpose registers to form a complete interrupt context frame */
|
||||||
|
push rax
|
||||||
|
push rbx
|
||||||
|
push rcx
|
||||||
|
push rdx
|
||||||
|
push rsi
|
||||||
|
push rdi
|
||||||
|
push rbp
|
||||||
|
push r8
|
||||||
|
push r9
|
||||||
|
push r10
|
||||||
|
push r11
|
||||||
|
push r12
|
||||||
|
push r13
|
||||||
|
push r14
|
||||||
|
push r15
|
||||||
|
|
||||||
|
/* 2. Pass current saved stack pointer in RDI */
|
||||||
|
mov rdi, rsp
|
||||||
|
call timer_interrupt_handler
|
||||||
|
|
||||||
|
/* 3. Switch stack pointer to returned value (RAX contains next thread's RSP) */
|
||||||
|
mov rsp, rax
|
||||||
|
|
||||||
|
/* 4. Restore all general-purpose registers */
|
||||||
|
pop r15
|
||||||
|
pop r14
|
||||||
|
pop r13
|
||||||
|
pop r12
|
||||||
|
pop r11
|
||||||
|
pop r10
|
||||||
|
pop r9
|
||||||
|
pop r8
|
||||||
|
pop rbp
|
||||||
|
pop rdi
|
||||||
|
pop rsi
|
||||||
|
pop rdx
|
||||||
|
pop rcx
|
||||||
|
pop rbx
|
||||||
|
pop rax
|
||||||
|
|
||||||
|
/* 5. Return from interrupt (IRETQ restores RIP, CS, RFLAGS, RSP, SS) */
|
||||||
|
iretq
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
//! Interrupt Descriptor Table (IDT) and Exception Handling
|
//! Interrupt Descriptor Table (IDT) and Exception Handling
|
||||||
|
|
||||||
use crate::kprintln;
|
use crate::kprintln;
|
||||||
|
use crate::sched::SCHEDULER;
|
||||||
|
use crate::drivers::timer::send_eoi;
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
@@ -49,6 +51,7 @@ static mut IDT: [IdtEntry; 256] = [IdtEntry::missing(); 256];
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn default_isr_stub();
|
fn default_isr_stub();
|
||||||
|
fn timer_isr_entry();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global assembly ISR stub for default exception handling
|
// Global assembly ISR stub for default exception handling
|
||||||
@@ -85,6 +88,10 @@ pub unsafe fn init() {
|
|||||||
(*idt_ptr.add(i)).set_handler(stub_addr, 0, 0);
|
(*idt_ptr.add(i)).set_handler(stub_addr, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set Timer Interrupt (Vector 32 / 0x20)
|
||||||
|
let timer_addr = timer_isr_entry as *const () as usize as u64;
|
||||||
|
(*idt_ptr.add(32)).set_handler(timer_addr, 0, 0);
|
||||||
|
|
||||||
let descriptor = IdtDescriptor {
|
let descriptor = IdtDescriptor {
|
||||||
limit: (size_of::<[IdtEntry; 256]>() - 1) as u16,
|
limit: (size_of::<[IdtEntry; 256]>() - 1) as u16,
|
||||||
base: idt_ptr as u64,
|
base: idt_ptr as u64,
|
||||||
@@ -97,3 +104,15 @@ pub unsafe fn init() {
|
|||||||
pub extern "C" fn raw_exception_handler(stack_ptr: *const u64) {
|
pub extern "C" fn raw_exception_handler(stack_ptr: *const u64) {
|
||||||
kprintln!("[CPU EXCEPTION] Trap triggered at stack frame: {:p}", stack_ptr);
|
kprintln!("[CPU EXCEPTION] Trap triggered at stack frame: {:p}", stack_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn timer_interrupt_handler(saved_rsp: u64) -> u64 {
|
||||||
|
unsafe {
|
||||||
|
// Send End of Interrupt to controller
|
||||||
|
send_eoi();
|
||||||
|
|
||||||
|
// Perform preemptive scheduling quantum check
|
||||||
|
let sched = &mut *core::ptr::addr_of_mut!(SCHEDULER);
|
||||||
|
sched.preempt(saved_rsp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
pub mod serial;
|
pub mod serial;
|
||||||
|
pub mod timer;
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
//! System Timer & PIC (Programmable Interval Timer 8254 on Vector 32)
|
||||||
|
|
||||||
|
use crate::kprintln;
|
||||||
|
|
||||||
|
const PIC1_COMMAND: u16 = 0x20;
|
||||||
|
const PIC1_DATA: u16 = 0x21;
|
||||||
|
const PIC2_COMMAND: u16 = 0xA0;
|
||||||
|
const PIC2_DATA: u16 = 0xA1;
|
||||||
|
|
||||||
|
const PIT_CHANNEL0_DATA: u16 = 0x40;
|
||||||
|
const PIT_COMMAND_MODE: u16 = 0x43;
|
||||||
|
|
||||||
|
const PIC_EOI: u8 = 0x20;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn outb(port: u16, val: u8) {
|
||||||
|
core::arch::asm!("out dx, al", in("dx") port, in("al") val, options(nomem, nostack, preserves_flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn io_wait() {
|
||||||
|
outb(0x80, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send End of Interrupt to PIC
|
||||||
|
pub unsafe fn send_eoi() {
|
||||||
|
outb(PIC1_COMMAND, PIC_EOI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remap PIC offsets to 32 (0x20) and 40 (0x28)
|
||||||
|
unsafe fn remap_pic() {
|
||||||
|
// ICW1: Start initialization in cascade mode
|
||||||
|
outb(PIC1_COMMAND, 0x11);
|
||||||
|
io_wait();
|
||||||
|
outb(PIC2_COMMAND, 0x11);
|
||||||
|
io_wait();
|
||||||
|
|
||||||
|
// ICW2: Vector offsets (Master = 32, Slave = 40)
|
||||||
|
outb(PIC1_DATA, 0x20);
|
||||||
|
io_wait();
|
||||||
|
outb(PIC2_DATA, 0x28);
|
||||||
|
io_wait();
|
||||||
|
|
||||||
|
// ICW3: Cascade wiring
|
||||||
|
outb(PIC1_DATA, 0x04);
|
||||||
|
io_wait();
|
||||||
|
outb(PIC2_DATA, 0x02);
|
||||||
|
io_wait();
|
||||||
|
|
||||||
|
// ICW4: 8086 mode
|
||||||
|
outb(PIC1_DATA, 0x01);
|
||||||
|
io_wait();
|
||||||
|
outb(PIC2_DATA, 0x01);
|
||||||
|
io_wait();
|
||||||
|
|
||||||
|
// Mask all IRQs except IRQ 0 (Timer)
|
||||||
|
outb(PIC1_DATA, 0xFE); // Enable only IRQ0 (bit 0 = 0)
|
||||||
|
outb(PIC2_DATA, 0xFF); // Disable all on Slave
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize PIT to tick at target Hz (e.g. 100 Hz = 10 ms quantum)
|
||||||
|
pub unsafe fn init(target_hz: u32) {
|
||||||
|
remap_pic();
|
||||||
|
|
||||||
|
let divisor = (1193182 / target_hz) as u16;
|
||||||
|
|
||||||
|
// Channel 0, lobyte/hibyte, Rate Generator (Mode 2)
|
||||||
|
outb(PIT_COMMAND_MODE, 0x36);
|
||||||
|
outb(PIT_CHANNEL0_DATA, (divisor & 0xFF) as u8);
|
||||||
|
outb(PIT_CHANNEL0_DATA, ((divisor >> 8) & 0xFF) as u8);
|
||||||
|
|
||||||
|
kprintln!("[TIMER] PIT 8254 initialized at {} Hz ({} ms time slice quantum).",
|
||||||
|
target_hz, 1000 / target_hz);
|
||||||
|
}
|
||||||
+14
-14
@@ -17,6 +17,7 @@ use sched::SCHEDULER;
|
|||||||
core::arch::global_asm!(include_str!("../asm/context.S"));
|
core::arch::global_asm!(include_str!("../asm/context.S"));
|
||||||
core::arch::global_asm!(include_str!("../asm/syscall_entry.S"));
|
core::arch::global_asm!(include_str!("../asm/syscall_entry.S"));
|
||||||
core::arch::global_asm!(include_str!("../asm/ring3_enter.S"));
|
core::arch::global_asm!(include_str!("../asm/ring3_enter.S"));
|
||||||
|
core::arch::global_asm!(include_str!("../asm/timer_isr.S"));
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn _start() -> ! {
|
pub extern "C" fn _start() -> ! {
|
||||||
@@ -60,21 +61,18 @@ pub extern "C" fn _start() -> ! {
|
|||||||
mm::init(memmap_resp);
|
mm::init(memmap_resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Initialize IPC & Capability System
|
// 6. Initialize Preemptive Hardware Timer (PIT 8254 @ 100 Hz)
|
||||||
|
kprintln!("[BOOT] Configuring PIT 8254 timer for Preemptive Multi-Tasking...");
|
||||||
|
unsafe {
|
||||||
|
drivers::timer::init(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Initialize IPC & Capability System
|
||||||
ipc::init();
|
ipc::init();
|
||||||
|
|
||||||
// 7. Initialize Scheduler
|
// 8. Initialize Scheduler
|
||||||
sched::init();
|
sched::init();
|
||||||
|
|
||||||
// 8. Self-Test Fast-Path IPC Ping
|
|
||||||
kprintln!("[TEST] Executing Kernel Fast-Path IPC Self-Test...");
|
|
||||||
let (status, resp_op, val) = ipc::fastpath::handle_fastpath_call(
|
|
||||||
ipc::fastpath::CAP_KERNEL_CONTROL,
|
|
||||||
ipc::fastpath::IPC_OP_PING,
|
|
||||||
42, 0, 0, 0
|
|
||||||
);
|
|
||||||
kprintln!("[TEST] IPC Fast-Path Ping Result: status={}, opcode={:#x}, val={}", status, resp_op, val);
|
|
||||||
|
|
||||||
// 9. Inspect and Load Initial Userspace Processes
|
// 9. Inspect and Load Initial Userspace Processes
|
||||||
unsafe {
|
unsafe {
|
||||||
let mod_resp = MODULE_REQUEST.response;
|
let mod_resp = MODULE_REQUEST.response;
|
||||||
@@ -102,7 +100,7 @@ pub extern "C" fn _start() -> ! {
|
|||||||
proc.pml4_paddr,
|
proc.pml4_paddr,
|
||||||
proc.kernel_stack_top,
|
proc.kernel_stack_top,
|
||||||
);
|
);
|
||||||
kprintln!("[BOOT] Registered Thread '{}' with TID {:?}", name, tid);
|
kprintln!("[BOOT] Registered Preemptible Thread '{}' with TID {:?}", name, tid);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
kprintln!("[ERROR] Failed to load module [{}]: {}", i, err);
|
kprintln!("[ERROR] Failed to load module [{}]: {}", i, err);
|
||||||
@@ -110,8 +108,10 @@ pub extern "C" fn _start() -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintln!("[BOOT] Starting Multi-Tasking & IPC Rendezvous...");
|
kprintln!("[BOOT] Enabling Interrupts & Starting Preemptive Scheduler...");
|
||||||
kprintln!("-------------------------------------------------------");
|
kprintln!("-------------------------------------------------------");
|
||||||
|
|
||||||
|
// Pick first ready thread and switch to it with interrupts enabled
|
||||||
(*sched_ptr).schedule();
|
(*sched_ptr).schedule();
|
||||||
} else {
|
} else {
|
||||||
kprintln!("[BOOT] No userspace modules detected. Staying in Ring 0 idle loop.");
|
kprintln!("[BOOT] No userspace modules detected. Staying in Ring 0 idle loop.");
|
||||||
@@ -122,7 +122,7 @@ pub extern "C" fn _start() -> ! {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
unsafe {
|
unsafe {
|
||||||
core::arch::asm!("hlt");
|
core::arch::asm!("sti; hlt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+91
-60
@@ -11,27 +11,34 @@ extern "C" {
|
|||||||
fn switch_to(prev_rsp: *mut u64, next_rsp: u64);
|
fn switch_to(prev_rsp: *mut u64, next_rsp: u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_QUANTUM_TICKS: u32 = 5; // 5 ticks @ 100Hz = 50ms time slice
|
||||||
|
|
||||||
pub struct Scheduler {
|
pub struct Scheduler {
|
||||||
pub threads: [Thread; MAX_THREADS],
|
pub threads: [Thread; MAX_THREADS],
|
||||||
pub current_tid: usize,
|
pub current_tid: usize,
|
||||||
pub next_tid: u64,
|
pub next_tid: u64,
|
||||||
|
pub quantum_remaining: u32,
|
||||||
|
pub ticks: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static mut SCHEDULER: Scheduler = Scheduler {
|
pub static mut SCHEDULER: Scheduler = Scheduler {
|
||||||
threads: [const { Thread::empty() }; MAX_THREADS],
|
threads: [const { Thread::empty() }; MAX_THREADS],
|
||||||
current_tid: 0,
|
current_tid: 0,
|
||||||
next_tid: 1,
|
next_tid: 1,
|
||||||
|
quantum_remaining: DEFAULT_QUANTUM_TICKS,
|
||||||
|
ticks: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Scheduler {
|
impl Scheduler {
|
||||||
pub fn init(&mut self) {
|
pub fn init(&mut self) {
|
||||||
// Slot 0 is reserved for Kernel Idle/Bootstrap thread
|
|
||||||
self.threads[0].id = 0;
|
self.threads[0].id = 0;
|
||||||
self.threads[0].name = "kernel_idle";
|
self.threads[0].name = "kernel_idle";
|
||||||
self.threads[0].state = ThreadState::Running;
|
self.threads[0].state = ThreadState::Running;
|
||||||
self.current_tid = 0;
|
self.current_tid = 0;
|
||||||
self.next_tid = 1;
|
self.next_tid = 1;
|
||||||
kprintln!("[SCHED] Scheduler initialized (Multi-Thread TCB table ready).");
|
self.quantum_remaining = DEFAULT_QUANTUM_TICKS;
|
||||||
|
self.ticks = 0;
|
||||||
|
kprintln!("[SCHED] Preemptive Multi-Tasking Scheduler initialized (Quantum: {} ticks).", DEFAULT_QUANTUM_TICKS);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_user_thread(
|
pub fn create_user_thread(
|
||||||
@@ -55,23 +62,33 @@ impl Scheduler {
|
|||||||
self.threads[i].user_rsp = user_rsp;
|
self.threads[i].user_rsp = user_rsp;
|
||||||
self.threads[i].user_rip = entry_rip;
|
self.threads[i].user_rip = entry_rip;
|
||||||
|
|
||||||
// Setup initial kernel stack for IRETQ return
|
// Build initial interrupt frame for timer_isr_entry / iretq return:
|
||||||
|
// [kstack - 5]: SS (0x1B)
|
||||||
|
// [kstack - 4]: RSP (user_rsp)
|
||||||
|
// [kstack - 3]: RFLAGS (0x202)
|
||||||
|
// [kstack - 2]: CS (0x23)
|
||||||
|
// [kstack - 1]: RIP (entry_rip)
|
||||||
|
// [kstack - 20..-6]: 15 GPRs (rax, rbx, rcx, rdx, rsi, rdi, rbp, r8..r15)
|
||||||
unsafe {
|
unsafe {
|
||||||
let kstack = kernel_stack_top as *mut u64;
|
let kstack = kernel_stack_top as *mut u64;
|
||||||
let stack_ptr = kstack.sub(16);
|
let frame_ptr = kstack.sub(20);
|
||||||
|
|
||||||
*stack_ptr.add(0) = 0; // r15
|
// GPRs (all 0)
|
||||||
*stack_ptr.add(1) = 0; // r14
|
for j in 0..15 {
|
||||||
*stack_ptr.add(2) = 0; // r13
|
*frame_ptr.add(j) = 0;
|
||||||
*stack_ptr.add(3) = 0; // r12
|
|
||||||
*stack_ptr.add(4) = 0; // rbx
|
|
||||||
*stack_ptr.add(5) = 0; // rbp
|
|
||||||
*stack_ptr.add(6) = initial_user_trampoline as *const () as usize as u64; // RIP for switch_to
|
|
||||||
|
|
||||||
self.threads[i].context.rsp = stack_ptr as u64;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintln!("[SCHED] Created User Thread [TID {}] '{}' (RIP: {:#x}, RSP: {:#x})",
|
// IRETQ Frame
|
||||||
|
*frame_ptr.add(15) = entry_rip; // RIP
|
||||||
|
*frame_ptr.add(16) = 0x23; // CS (User Code)
|
||||||
|
*frame_ptr.add(17) = 0x0202; // RFLAGS (IF enabled)
|
||||||
|
*frame_ptr.add(18) = user_rsp; // RSP (User Stack)
|
||||||
|
*frame_ptr.add(19) = 0x1B; // SS (User Data)
|
||||||
|
|
||||||
|
self.threads[i].context.rsp = frame_ptr as u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
kprintln!("[SCHED] Created Preemptible Thread [TID {}] '{}' (RIP: {:#x}, RSP: {:#x})",
|
||||||
tid, name, entry_rip, user_rsp);
|
tid, name, entry_rip, user_rsp);
|
||||||
return Some(tid);
|
return Some(tid);
|
||||||
}
|
}
|
||||||
@@ -109,14 +126,72 @@ impl Scheduler {
|
|||||||
if self.threads[self.current_tid].state == ThreadState::Running {
|
if self.threads[self.current_tid].state == ThreadState::Running {
|
||||||
self.threads[self.current_tid].state = ThreadState::Ready;
|
self.threads[self.current_tid].state = ThreadState::Ready;
|
||||||
}
|
}
|
||||||
|
self.quantum_remaining = DEFAULT_QUANTUM_TICKS;
|
||||||
self.schedule();
|
self.schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Preemptive tick called directly from timer ISR handler
|
||||||
|
pub fn preempt(&mut self, saved_rsp: u64) -> u64 {
|
||||||
|
self.ticks += 1;
|
||||||
|
|
||||||
|
if self.quantum_remaining > 0 {
|
||||||
|
self.quantum_remaining -= 1;
|
||||||
|
if self.quantum_remaining > 0 {
|
||||||
|
return saved_rsp; // Keep running current thread
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time slice quantum expired -> Preempt current thread!
|
||||||
|
self.quantum_remaining = DEFAULT_QUANTUM_TICKS;
|
||||||
|
|
||||||
|
let prev_idx = self.current_tid;
|
||||||
|
self.threads[prev_idx].context.rsp = saved_rsp;
|
||||||
|
if self.threads[prev_idx].state == ThreadState::Running {
|
||||||
|
self.threads[prev_idx].state = ThreadState::Ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find next Ready thread (Round-Robin)
|
||||||
|
let mut next_idx = (prev_idx + 1) % MAX_THREADS;
|
||||||
|
let mut found = false;
|
||||||
|
for _ in 0..MAX_THREADS {
|
||||||
|
if self.threads[next_idx].state == ThreadState::Ready {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next_idx = (next_idx + 1) % MAX_THREADS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
// Restore previous thread if it's still runnable
|
||||||
|
if self.threads[prev_idx].state == ThreadState::Ready {
|
||||||
|
self.threads[prev_idx].state = ThreadState::Running;
|
||||||
|
}
|
||||||
|
return saved_rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current_tid = next_idx;
|
||||||
|
self.threads[next_idx].state = ThreadState::Running;
|
||||||
|
|
||||||
|
let next_pml4 = self.threads[next_idx].pml4_paddr;
|
||||||
|
let next_kstack = self.threads[next_idx].kernel_stack_top;
|
||||||
|
let next_rsp = self.threads[next_idx].context.rsp;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if next_pml4 != 0 {
|
||||||
|
(*core::ptr::addr_of_mut!(VMM)).load_cr3(next_pml4);
|
||||||
|
}
|
||||||
|
if next_kstack != 0 {
|
||||||
|
set_kernel_stack(next_kstack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next_rsp
|
||||||
|
}
|
||||||
|
|
||||||
pub fn schedule(&mut self) {
|
pub fn schedule(&mut self) {
|
||||||
let prev_idx = self.current_tid;
|
let prev_idx = self.current_tid;
|
||||||
let mut next_idx = (prev_idx + 1) % MAX_THREADS;
|
let mut next_idx = (prev_idx + 1) % MAX_THREADS;
|
||||||
|
|
||||||
// Find next Ready thread (Round-Robin)
|
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
for _ in 0..MAX_THREADS {
|
for _ in 0..MAX_THREADS {
|
||||||
if self.threads[next_idx].state == ThreadState::Ready {
|
if self.threads[next_idx].state == ThreadState::Ready {
|
||||||
@@ -130,7 +205,7 @@ impl Scheduler {
|
|||||||
if self.threads[prev_idx].state == ThreadState::Running {
|
if self.threads[prev_idx].state == ThreadState::Running {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
next_idx = 0; // idle thread
|
next_idx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if prev_idx == next_idx && self.threads[prev_idx].state == ThreadState::Running {
|
if prev_idx == next_idx && self.threads[prev_idx].state == ThreadState::Running {
|
||||||
@@ -166,47 +241,3 @@ pub fn init() {
|
|||||||
(*core::ptr::addr_of_mut!(SCHEDULER)).init();
|
(*core::ptr::addr_of_mut!(SCHEDULER)).init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn initial_user_trampoline() {
|
|
||||||
let (entry_rip, user_rsp) = unsafe {
|
|
||||||
let sched = &mut *core::ptr::addr_of_mut!(SCHEDULER);
|
|
||||||
let curr = sched.get_current_mut();
|
|
||||||
(curr.user_rip, curr.user_rsp)
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// IRETQ to Ring 3
|
|
||||||
core::arch::asm!(
|
|
||||||
"mov ax, 0x1B",
|
|
||||||
"mov ds, ax",
|
|
||||||
"mov es, ax",
|
|
||||||
"mov fs, ax",
|
|
||||||
"mov gs, ax",
|
|
||||||
"push 0x1B", // User SS
|
|
||||||
"push {user_rsp}", // User RSP
|
|
||||||
"push 0x0202", // RFLAGS (IF enabled)
|
|
||||||
"push 0x23", // User CS
|
|
||||||
"push {entry_rip}", // User RIP
|
|
||||||
"xor rax, rax",
|
|
||||||
"xor rbx, rbx",
|
|
||||||
"xor rcx, rcx",
|
|
||||||
"xor rdx, rdx",
|
|
||||||
"xor rsi, rsi",
|
|
||||||
"xor rdi, rdi",
|
|
||||||
"xor rbp, rbp",
|
|
||||||
"xor r8, r8",
|
|
||||||
"xor r9, r9",
|
|
||||||
"xor r10, r10",
|
|
||||||
"xor r11, r11",
|
|
||||||
"xor r12, r12",
|
|
||||||
"xor r13, r13",
|
|
||||||
"xor r14, r14",
|
|
||||||
"xor r15, r15",
|
|
||||||
"iretq",
|
|
||||||
user_rsp = in(reg) user_rsp,
|
|
||||||
entry_rip = in(reg) entry_rip,
|
|
||||||
options(noreturn)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user