Work on switching more
This commit is contained in:
parent
62ab97f354
commit
5b218a5298
4 changed files with 149 additions and 40 deletions
30
src/arch/amd64/interrupts/asm/trap.asm
Normal file
30
src/arch/amd64/interrupts/asm/trap.asm
Normal 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
|
|
@ -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 {
|
||||
|
|
|
@ -1,2 +1,7 @@
|
|||
use core::arch::global_asm;
|
||||
|
||||
pub mod gdt;
|
||||
pub mod idt;
|
||||
pub mod idt;
|
||||
//
|
||||
// global_asm!("asm/trap.asm");
|
||||
//
|
||||
|
|
|
@ -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(¤t_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();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue