Work on switching more

This commit is contained in:
Evie Viau-Chow-Stuart 2025-07-01 22:18:47 -07:00
parent 62ab97f354
commit 5b218a5298
Signed by: evie
GPG key ID: 928652CDFCEC8099
4 changed files with 149 additions and 40 deletions

View file

@ -0,0 +1,30 @@
.globl trap
trap:
push rbp
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push r8
push r9
push r10
push r11
push r12
push r13
push r15
push r14
mov rsi, rsp /* arg 2: registers */
mov rdi, rsp
add rdi, 15*8 /* arg1: interrupt frame */
call /* call the rust code here */
.globl return
return:
/* restore everything here */
iretq

View file

@ -2,11 +2,93 @@ use core::arch::asm;
use spin::lazy::Lazy;
use spin::mutex::Mutex;
use x86_64::registers::control::Cr2;
use x86_64::{set_general_handler, PrivilegeLevel};
use x86_64::{set_general_handler, PrivilegeLevel, VirtAddr};
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
use crate::arch::amd64::devices::i8259::PicPair;
use crate::arch::amd64::interrupts::gdt;
use crate::trafficcontrol::Process;
use core::arch::naked_asm;
use core::cell::UnsafeCell;
#[repr(align(8), C)]
#[derive(Debug, Clone, Default)]
pub struct Registers {
pub r15: usize,
pub r14: usize,
pub r13: usize,
pub r12: usize,
pub r11: usize,
pub r10: usize,
pub r9: usize,
pub r8: usize,
pub rdi: usize,
pub rsi: usize,
pub rdx: usize,
pub rcx: usize,
pub rbx: usize,
pub rax: usize,
pub rbp: usize,
}
impl Registers {
pub const fn zeroed() -> Self {
Registers {
r15: 0,
r14: 0,
r13: 0,
r12: 0,
r11: 0,
r10: 0,
r9: 0,
r8: 0,
rdi: 0,
rsi: 0,
rdx: 0,
rcx: 0,
rbx: 0,
rax: 0,
rbp: 0,
}
}
}
pub struct RegistersWrapper(pub UnsafeCell<Registers>);
unsafe impl Sync for RegistersWrapper {}
macro_rules! wrap {
($fn: ident => $w:ident) => {
#[unsafe(naked)]
pub unsafe extern "sysv64" fn $w() {
naked_asm!(
"
push rbp
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
mov rsi, rsp // arg2: register list
mov rdi, rsp
add rdi, 15*8 // arg1: interupt frame
call {}
",
sym $fn,
);
}
};
}
wrap!(timer_interrupt_handler => wrapped_timer_interrupt_handler);
pub const PIC_1_OFFSET: u8 = 32;
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
@ -36,7 +118,9 @@ static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
.set_stack_index(gdt::PAGE_FAULT_IST_INDEX);
}
idt[InterruptIndex::Timer as u8].set_handler_fn(timer_interrupt_handler);
unsafe {
idt[InterruptIndex::Timer as u8].set_handler_addr(VirtAddr::new(wrapped_timer_interrupt_handler as u64));
}
// syscall capture
idt[0x80].set_handler_fn(syscall_handler).set_privilege_level(PrivilegeLevel::Ring3);
@ -155,41 +239,19 @@ fn catch_all_handler(
}
#[unsafe(no_mangle)]
extern "x86-interrupt" fn timer_interrupt_handler(
extern "sysv64" fn timer_interrupt_handler(
interrupt_stack_frame: InterruptStackFrame,
regs: &mut Registers,
) {
// first thing: save all the gp registers
let mut saved_registers: [u64; 15] = [0; 15];
unsafe {
asm!(
"mov [{regs} + 0], rax",
"mov [{regs} + 8], rbx",
"mov [{regs} + 16], rcx",
"mov [{regs} + 24], rdx",
"mov [{regs} + 32], rsi",
"mov [{regs} + 40], rdi",
"mov [{regs} + 48], rbp",
"mov [{regs} + 56], r8",
"mov [{regs} + 64], r9",
"mov [{regs} + 72], r10",
"mov [{regs} + 80], r11",
"mov [{regs} + 88], r12",
"mov [{regs} + 96], r13",
"mov [{regs} + 104], r14",
"mov [{regs} + 112], r15",
regs = in(reg) saved_registers.as_mut_ptr(),
);
}
// TODO: debug code
println!(".");
print!(".");
// since we're gonna be jumping, we should notify early bc we wont have a chance to do this
unsafe {
PICS.lock().notify_end_interrupt(InterruptIndex::Timer as u8);
}
Process::execute_next_round_robin(interrupt_stack_frame, saved_registers);
Process::execute_next_round_robin(interrupt_stack_frame, regs);
}
extern "x86-interrupt" fn syscall_handler(
@ -205,9 +267,9 @@ extern "x86-interrupt" fn syscall_handler(
unsafe {
asm!(
// llvm will cry about it if we use rbx, move it somewhere else
"mov {rbx_out}, rbx",
"mov {ee}, rbx",
ee = out(reg) rbx,
out("rax") rax,
rbx_out = out(reg) rbx,
out("rcx") rcx,
out("rdx") rdx,
out("rsi") rsi,
@ -216,6 +278,8 @@ extern "x86-interrupt" fn syscall_handler(
);
}
print!(" syscall: {:#x} ", rax);
let result = crate::syscalls::route(rax, rbx, rcx, rdx, rsi, rdi);
unsafe {

View file

@ -1,2 +1,7 @@
use core::arch::global_asm;
pub mod gdt;
pub mod idt;
pub mod idt;
//
// global_asm!("asm/trap.asm");
//

View file

@ -3,6 +3,7 @@ use alloc::boxed::Box;
use alloc::collections::VecDeque;
use alloc::sync::Arc;
use core::arch::asm;
use core::cell::UnsafeCell;
use core::ptr;
use core::sync::atomic::{AtomicUsize, Ordering};
use elf::ElfBytes;
@ -19,6 +20,7 @@ use crate::arch::amd64::memory::{pmm, vmm};
use crate::println;
use elf::abi;
use hashbrown::HashMap;
use crate::arch::amd64::interrupts::idt::{Registers, RegistersWrapper};
static PID: AtomicUsize = AtomicUsize::new(0);
@ -32,6 +34,8 @@ static PROCESS_QUEUE: Lazy<RwLock<VecDeque<usize>>> = Lazy::new(|| {
RwLock::new(VecDeque::new())
});
static REGISTERS: RegistersWrapper = RegistersWrapper(UnsafeCell::new(Registers::zeroed()));
#[derive(Clone)]
pub struct Process {
pub id: usize,
@ -39,7 +43,7 @@ pub struct Process {
instruction_pointer: u64,
stack_pointer: u64,
pub page_table: PhysFrame,
saved_registers: [u64; 15]
saved_registers: Registers
}
impl Process {
@ -168,7 +172,7 @@ impl Process {
instruction_pointer: entry,
stack_pointer: initial_stack_pointer,
page_table: page_table_frame,
saved_registers: [0; 15],
saved_registers: Registers::default(),
};
let mut processes = PROCESSES.write();
@ -183,18 +187,25 @@ impl Process {
pub fn start(&self) {
println!("Running pid {}", self.id);
println!("saved rax: {:#x}", self.saved_registers.rax);
// lets not clobber the stack or anything with a timer intr
amd64::instructions::cli();
let saved_registers = REGISTERS.0.get() as *mut Registers;
unsafe {
saved_registers.write_volatile(self.saved_registers.clone());
}
// swap to the process's page table
unsafe {
Cr3::write(self.page_table, Cr3Flags::empty());
}
unsafe {
asm!(
// TODO: figure out why the gp registers cause issues
"mov rax, [{regs} + 0]",
"mov rbx, [{regs} + 8]",
"mov rcx, [{regs} + 16]",
@ -224,10 +235,9 @@ impl Process {
"push {code_seg:r}",
"push {instruction_pointer}",
// lets jump back
"iretq",
regs = in(reg) self.saved_registers.as_ptr(),
regs = in(reg) REGISTERS.0.get() as *mut u64,
data_seg = in(reg) GDT.1.user_data_selector.0,
code_seg = in(reg) GDT.1.user_code_selector.0,
@ -242,7 +252,7 @@ impl Process {
}
}
pub fn execute_next_round_robin(interrupt_stack_frame: InterruptStackFrame, saved_registers: [u64; 15]) {
pub fn execute_next_round_robin(interrupt_stack_frame: InterruptStackFrame, saved_registers: &mut Registers) {
let mut queue = PROCESS_QUEUE.write();
let mut processes = PROCESSES.write();
if queue.is_empty() || processes.is_empty() {
@ -252,7 +262,7 @@ impl Process {
let current_pid = CURRENT_PROCESS.load(Ordering::SeqCst);
if current_pid != usize::MAX {
if let Some(process) = processes.get_mut(&current_pid) {
process.saved_registers = saved_registers;
process.saved_registers = saved_registers.clone();
process.instruction_pointer = interrupt_stack_frame.instruction_pointer.as_u64();
process.stack_pointer = interrupt_stack_frame.stack_pointer.as_u64();
}