os/src/proc.rs

164 lines
5.3 KiB
Rust

use core::{fmt::Debug, mem, hint::black_box};
use alloc::boxed::Box;
use spin::Mutex;
use x86_64::{VirtAddr, structures::{paging::{Page, PageTableFlags}, idt::InterruptStackFrameValue}};
use crate::{sync::SyncLazy, mem::map_next, lazy_static, assert_canonical, println};
#[derive(Clone, Copy, Debug)]
pub struct ProcessControlBlock {
pub stack_frame: InterruptStackFrameValue,
pub registers: Registers
}
#[derive(Clone, Copy, Default)]
#[non_exhaustive]
#[repr(C)]
pub struct Registers {
pub rax: usize,
pub rbx: usize,
pub rcx: usize,
pub rdx: usize,
pub rsi: usize,
pub rdi: usize,
pub rbp: usize,
pub r8: usize,
pub r9: usize,
pub r10: usize,
pub r11: usize,
pub r12: usize,
pub r13: usize,
pub r14: usize,
pub r15: usize,
}
impl Debug for Registers {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Registers")
.field("rax", &format_args!("{:#018x}", self.rax))
.field("rbx", &format_args!("{:#018x}", self.rbx))
.field("rcx", &format_args!("{:#018x}", self.rcx))
.field("rdx", &format_args!("{:#018x}", self.rdx))
.field("rsi", &format_args!("{:#018x}", self.rsi))
.field("rdi", &format_args!("{:#018x}", self.rdi))
.field("rbp", &format_args!("{:#018x}", self.rbp))
.field("r8", &format_args!("{:#018x}", self.r8))
.field("r9", &format_args!("{:#018x}", self.r9))
.field("r10", &format_args!("{:#018x}", self.r10))
.field("r11", &format_args!("{:#018x}", self.r11))
.field("r12", &format_args!("{:#018x}", self.r12))
.field("r13", &format_args!("{:#018x}", self.r13))
.field("r14", &format_args!("{:#018x}", self.r14))
.field("r15", &format_args!("{:#018x}", self.r15))
.finish()
}
}
const MAX_PROCESSES: usize = 0x7fff;
const PROCESS_LIST_ADDR: usize = 0x7fff_0000_0000;
pub struct ProcListElement {
pub pcb: Option<&'static mut ProcessControlBlock>, // npo for the win!
pub prev: u16, // only needed to patch an element out of the list
pub next: u16,
}
impl ProcListElement {
pub fn write(&mut self, pcb: ProcessControlBlock) {
println!("write");
match self.pcb.as_deref_mut() {
None => {
let addr = Box::leak(Box::new(pcb));
// with this println, it tries to execute 0x0. without it, it (sometimes) tries to execute PROCESS_LIST_ADDR.
// whatever the case, it happens after 1 println in `fn timer`, before this code is even hit.
// if the line up above ^^^ is inlined, it faults after 2 printlns instead. what in the actual fuck
// println!("addr: {:x}", addr as *mut _ as usize);
self.pcb.replace(addr);
}
Some(v) => { *v = pcb; }
}
// println!("end write");
}
}
lazy_static! {
pub static ref PROCESSES: Mutex<&'static mut [ProcListElement; MAX_PROCESSES]> = {
let ptr = PROCESS_LIST_ADDR as *mut [_; MAX_PROCESSES];
// const gaming
const DEFAULT: ProcListElement = ProcListElement { pcb: None, next: 0, prev: 0 };
unsafe { ptr.write([DEFAULT; MAX_PROCESSES]) }
Mutex::new(unsafe { &mut *ptr })
};
}
static CURRENT_PROCESS: Mutex<u64> = Mutex::new(0);
// here i make the assumption that the privilege level is *somewhere* in `InterruptStackFrame`
pub fn timer(stack_frame: &mut InterruptStackFrameValue, registers: &mut Registers) {
println!("Hello there from timer interrupt");
let mut curr_pid = CURRENT_PROCESS.lock();
let mut procs = PROCESSES.lock();
println!("Hello there from timer interrupt 2");
// first, save the stack and registers values in the pcb for this pid
procs[*curr_pid as usize].write(ProcessControlBlock {
stack_frame: *stack_frame,
registers: *registers,
});
println!("Hello there from timer interrupt 3");
// then, choose the next pid
let next_pid = procs[*curr_pid as usize].next as u64;
*curr_pid = next_pid;
let next = procs[next_pid as usize].pcb.as_deref().unwrap();
println!("Hello there from timer interrupt 4");
// last, load the stack and registers values from the new pid
*stack_frame = next.stack_frame;
*registers = next.registers;
// println!("Next pid: {}", *curr_pid);
// println!("Next stack_frame: {:?}", stack_frame);
// println!("Next registers: {:?}", registers);
for i in 0..5000000 { black_box(i); }
}
pub fn init() {
assert_canonical(PROCESS_LIST_ADDR as u64);
let page_start = Page::containing_address(VirtAddr::new(PROCESS_LIST_ADDR as u64));
let page_end = Page::containing_address(VirtAddr::new((PROCESS_LIST_ADDR + MAX_PROCESSES * mem::size_of::<ProcListElement>()) as u64 - 1));
let page_range = Page::range_inclusive(page_start, page_end);
for page in page_range {
map_next(page, PageTableFlags::PRESENT | PageTableFlags::WRITABLE)
.unwrap()
.flush();
}
let _ = SyncLazy::get(&PROCESSES);
}
// macro_rules! new_stack_frame {
// () => {unsafe {
// let ip: usize;
// let cs: usize;
// let flags: usize;
// let sp: usize;
// let ss: usize;
// ::core::arch::asm! {
// "mov rax, rip",
// out("rax") ip
// }
// }};
// }
// fn foo() {
// new_stack_frame!()
// }