144 lines
4.5 KiB
Rust
144 lines
4.5 KiB
Rust
use core::{fmt::Debug, mem};
|
|
|
|
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};
|
|
|
|
#[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) {
|
|
match self.pcb.as_deref_mut() {
|
|
None => {
|
|
let addr = Box::leak(Box::new(pcb));
|
|
self.pcb.replace(addr);
|
|
}
|
|
Some(v) => { *v = pcb; }
|
|
}
|
|
}
|
|
}
|
|
|
|
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) {
|
|
let mut curr_pid = CURRENT_PROCESS.lock();
|
|
let mut procs = PROCESSES.lock();
|
|
|
|
// 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,
|
|
});
|
|
|
|
// 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();
|
|
|
|
// last, load the stack and registers values from the new pid
|
|
*stack_frame = next.stack_frame;
|
|
*registers = next.registers;
|
|
}
|
|
|
|
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!()
|
|
// }
|