#![allow(dead_code)] use std::{cell::RefCell, rc::Rc}; use turkos_os_threads::threads::*; #[derive(Debug)] struct Stack { layout: StackLayout, bytes: Rc>>, guard: u64, prepare_fault: bool, release_fault: bool, } impl Stack { fn new(index: u64) -> Self { Self { layout: StackLayout { base: 0x8000_1000 + index * 0x20000, physical: 0x4100_0000 + index * 0x20000, bytes: 4 * PAGE, }, bytes: Rc::new(RefCell::new(vec![0xa5; 4 * PAGE as usize])), guard: 0, prepare_fault: false, release_fault: false, } } } #[derive(Default, Debug)] struct Hardware { sp: u64, unmasked: bool, in_irq: bool, cpu: u32, prepares: usize, releases: usize, released: Vec>, prepare_damage: u8, } #[derive(Debug)] struct Backend { hardware: Rc>, } unsafe impl turkos_os_threads::threads::Backend for Backend { type Stack = Stack; fn execution(&self) -> Execution { let h = self.hardware.borrow(); Execution { cpu: h.cpu, irq_masked: !h.unmasked, in_irq: h.in_irq, sp: h.sp, } } fn layout(&self, stack: &Stack) -> Result { Ok(stack.layout) } fn entry_executable(&self, entry: u64) -> bool { (0x40080000..0x40090000).contains(&entry) } fn prepare(&mut self, stack: &mut Stack) -> Result<(), Error> { self.hardware.borrow_mut().prepares += 1; let mut bytes = stack.bytes.borrow_mut(); bytes.fill(0); if stack.prepare_fault { return Err(Error::Backend); } bytes[..8].copy_from_slice(&LOW_CANARY.to_le_bytes()); let at = bytes.len() - 8; bytes[at..].copy_from_slice(&HIGH_CANARY.to_le_bytes()); match self.hardware.borrow().prepare_damage { 1 => bytes[0] ^= 1, 2 => bytes[at] ^= 1, 3 => bytes[8000] = 7, _ => {} } Ok(()) } fn observe(&self, stack: &Stack) -> Result { let bytes = stack.bytes.borrow(); Ok(StackObservation { layout: stack.layout, guard_descriptor: stack.guard, low_canary: u64::from_le_bytes(bytes[..8].try_into().unwrap()), high_canary: u64::from_le_bytes(bytes[bytes.len() - 8..].try_into().unwrap()), initially_zeroed: bytes[8..bytes.len() - 8].iter().all(|&v| v == 0), }) } fn release(&mut self, stack: Stack) -> Result<(), (Error, Stack)> { self.hardware.borrow_mut().releases += 1; stack.bytes.borrow_mut().fill(0); if stack.release_fault { return Err((Error::Backend, stack)); } self.hardware .borrow_mut() .released .push(stack.bytes.borrow().clone()); Ok(()) } } fn setup() -> (Table, Rc>) { let hardware = Rc::new(RefCell::new(Hardware::default())); let table = Table::new(Backend { hardware: hardware.clone(), }) .ok() .unwrap(); (table, hardware) } fn spawn(table: &mut Table, index: u64) -> ThreadId { table.create(Stack::new(index), 0x40080040, index).unwrap() } fn enter( table: &mut Table, hardware: &Rc>, id: ThreadId, ) { hardware.borrow_mut().sp = table.ready_context(id).unwrap().initial_sp; table.activate(id).unwrap(); } fn retire( table: &mut Table, hardware: &Rc>, id: ThreadId, ) { table.cancel(id).unwrap(); hardware.borrow_mut().sp = 0; table.reap(id).unwrap(); } pub(super) struct ThreadOwners { table: Table, hardware: Rc>, next: u64, } impl ThreadOwners { pub(super) fn new() -> Self { let (table, hardware) = setup(); Self { table, hardware, next: 0, } } pub(super) fn create(&mut self) -> ThreadId { let id = spawn(&mut self.table, self.next); self.next += 1; id } pub(super) fn record(&self, id: ThreadId) -> ThreadRecord { self.table.record(id).unwrap() } pub(super) fn activate(&mut self, id: ThreadId) { enter(&mut self.table, &self.hardware, id); } pub(super) fn yield_current(&mut self, id: ThreadId) { self.table.yield_current(id).unwrap(); self.hardware.borrow_mut().sp = 0; } pub(super) fn exit(&mut self, id: ThreadId) { if self.record(id).state == State::Running { self.table.exit_current(id).unwrap(); self.hardware.borrow_mut().sp = 0; } else { self.table.cancel(id).unwrap(); } } pub(super) fn reap(&mut self, id: ThreadId) { if self.record(id).state != State::Dead { self.exit(id); } self.table.reap(id).unwrap(); } pub(super) fn live(&self) -> usize { self.table.snapshot().live } }