#![allow(dead_code)] use std::{ cell::{Cell, RefCell}, collections::BTreeMap, }; use turkos_os_mapping::mapping::{ Backend, Change, Error as MappingError, Mapping, Owner, PAGE, Value, Window, }; use turkos_os_page_tables::descriptor::Permissions; use turkos_os_user_copy::user_copy::*; const USER: u64 = 0x8000_0000; const OWNER: Owner = Owner { id: 7, generation: 3, }; #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Ref { slot: usize, generation: u64, } struct Memory { root: BTreeMap>, data: Vec>>, generation: Cell, reads: RefCell>, writes: RefCell>, } impl Memory { fn new() -> Self { Self { root: BTreeMap::new(), data: (0..20) .map(|slot| { RefCell::new( (0..4096) .map(|offset| ((slot * 17 + offset) % 251 + 1) as u8) .collect(), ) }) .collect(), generation: Cell::new(1), reads: RefCell::new(vec![0; 20]), writes: RefCell::new(vec![0; 20]), } } } impl Backend for Memory { type FrameRef = Ref; type Prepared = BTreeMap>; fn owner(&self) -> Owner { OWNER } fn validate_frame(&self, owner: Owner, frame: Ref) -> Result<(), MappingError> { if owner == OWNER && frame.slot < self.data.len() && frame.generation == self.generation.get() { Ok(()) } else { Err(MappingError::Backing) } } fn current(&self, address: u64) -> Result>, MappingError> { Ok(self.root.get(&address).copied()) } fn prepare(&mut self, changes: &[Change]) -> Result { let mut draft = self.root.clone(); for change in changes { assert_eq!(draft.get(&change.virtual_address).copied(), change.before); if let Some(value) = change.after { draft.insert(change.virtual_address, value); } else { draft.remove(&change.virtual_address); } } Ok(draft) } fn commit(&mut self, draft: Self::Prepared) { self.root = draft; } } // SAFETY: actual owned host buffers are retained by Memory, bounded accesses // cannot fail, and no backend callback modifies frame identity or root state. unsafe impl PinnedMemory for Memory { unsafe fn read_ram(&self, frame: Ref, offset: usize, destination: &mut [u8]) { assert_eq!(frame.generation, self.generation.get()); destination .copy_from_slice(&self.data[frame.slot].borrow()[offset..offset + destination.len()]); self.reads.borrow_mut()[frame.slot] += destination.len(); } unsafe fn write_ram(&self, frame: Ref, offset: usize, source: &[u8]) { assert_eq!(frame.generation, self.generation.get()); self.data[frame.slot].borrow_mut()[offset..offset + source.len()].copy_from_slice(source); self.writes.borrow_mut()[frame.slot] += source.len(); } } fn rw() -> Permissions { Permissions { user: true, write: true, execute: false, } } fn rx() -> Permissions { Permissions { user: true, write: false, execute: true, } } fn window() -> UserWindow { UserWindow::new(USER, USER + 20 * PAGE, 39).unwrap() } fn mapper(pages: usize) -> Mapping { let mut mapping = Mapping::new( Memory::new(), 861, Window::new(USER, USER + 20 * PAGE, 39).unwrap(), ) .unwrap(); let frames: Vec<_> = (0..pages) .map(|slot| Ref { slot, generation: 1, }) .collect(); if pages != 0 { mapping.map(OWNER, USER, &frames, rw()).unwrap(); } mapping } fn buffers(mapping: &Mapping) -> Vec> { mapping.with_backend_observation(|memory| { memory .data .iter() .map(|data| data.borrow().clone()) .collect() }) } fn accesses(mapping: &Mapping) -> (usize, usize) { mapping.with_backend_observation(|memory| { ( memory.reads.borrow().iter().sum(), memory.writes.borrow().iter().sum(), ) }) } use std::rc::Rc; use turkos_os_exceptions::exceptions::{Error as ReturnError, Frame, ReturnAuthority, Stack, User}; use turkos_os_syscall_abi::syscall_abi::{ Backend as SyscallBackend, Errno, Execution, SVC_ESR, Write, }; pub const STACK_LOW: u64 = 0x4000_0000; pub const STACK_HIGH: u64 = STACK_LOW + 65536; pub const FRAME_ADDRESS: u64 = STACK_HIGH - 16 - 848; pub const DATA_ADDRESS: u64 = USER + PAGE; pub fn stack() -> Stack { Stack::new(STACK_LOW, STACK_HIGH).unwrap() } pub fn user() -> User { User { owner: OWNER.id, generation: OWNER.generation, root: 0x400b_0000, asid: 9, } } pub fn frame(number: u64, arguments: [u64; 6]) -> Frame { let mut f = Frame { vector_slot: 8, interrupted_sp: FRAME_ADDRESS + 848, sp_el0: USER + 3 * PAGE - 16, elr: USER + 64, spsr: 0x3c0, esr: SVC_ESR, ..Frame::EMPTY }; f.x[..6].copy_from_slice(&arguments); f.x[7] = 1; f.x[8] = number; for i in 9..31 { f.x[i] = 0x1122_0000 + i as u64; } for i in 0..32 { f.q[i] = [i as u64 + 0x7700, i as u64 + 0x9900]; } f.fpcr = 0x400000; f.fpsr = 0x08000000; f } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Mode { Normal, NoMem, CommitIo, ReleaseFail, PrepareCpuDrift, CommitCpuDrift, ReleaseCpuDrift, PrepareRootInvalid, CommitRootInvalid, WrongLength, } pub struct Prepared { pub bytes: Vec, owner: User, id: u64, fd: u32, references: Rc>, } pub struct SysBackend { mapping: Mapping, execution: Cell, live: RefCell>, valid_root: Cell, pub mode: Mode, pub prepares: usize, pub commits: usize, pub releases: usize, pub output: Vec, references: Rc>, issued: u64, pub observed_fd: Option, authority_accesses: Cell, } impl SysBackend { pub fn new() -> Self { let mut mapping = mapper(3); mapping.protect(OWNER, USER, 1, rx()).unwrap(); Self { mapping, execution: Cell::new(Execution { cpu: 0, current_el: 4, irq_masked: true, in_irq: false, kernel_stack: stack(), entry_sequence: 0, user: user(), }), live: RefCell::new(None), valid_root: Cell::new(true), mode: Mode::Normal, prepares: 0, commits: 0, releases: 0, output: Vec::new(), references: Rc::new(Cell::new(0)), issued: 0, observed_fd: None, authority_accesses: Cell::new(0), } } pub fn ingress(&mut self, frame: &Frame, address: u64) { let mut e = self.execution.get(); e.entry_sequence = e.entry_sequence.checked_add(1).unwrap(); self.execution.set(e); *self.live.borrow_mut() = Some((*frame, address)); } pub fn set_execution(&mut self, edit: impl FnOnce(&mut Execution)) { let mut e = self.execution.get(); edit(&mut e); self.execution.set(e); } pub fn set_root_valid(&mut self, valid: bool) { self.valid_root.set(valid); } pub fn references(&self) -> usize { self.references.get() } pub fn reference_counter(&self) -> Rc> { self.references.clone() } pub fn copy_accesses(&self) -> (usize, usize) { accesses(&self.mapping) } pub fn authority_accesses(&self) -> usize { self.authority_accesses.get() } pub fn pins(&self) -> usize { self.mapping.records().map(|r| r.3 as usize).sum() } pub fn source(&self, address: u64, len: usize) -> Vec { buffers(&self.mapping) .into_iter() .flatten() .skip((address - USER) as usize) .take(len) .collect() } pub fn remove_last_data_page(&mut self) { self.mapping.unmap(OWNER, USER + 2 * PAGE, 1).unwrap(); } } impl Default for SysBackend { fn default() -> Self { Self::new() } } impl ReturnAuthority for SysBackend { fn owner_root(&self, u: User) -> Result<(), ReturnError> { self.authority_accesses .set(self.authority_accesses.get() + 1); if self.valid_root.get() && u == self.execution.get().user && u == user() { Ok(()) } else { Err(ReturnError::Owner) } } fn executable(&self, u: User, entry: u64) -> Result<(), ReturnError> { self.owner_root(u)?; let value = self .mapping .lookup(OWNER, entry & !(PAGE - 1)) .map_err(|_| ReturnError::Entry)? .ok_or(ReturnError::Entry)?; if value.permissions.user && value.permissions.execute && !value.permissions.write { Ok(()) } else { Err(ReturnError::Entry) } } fn writable_stack(&self, u: User, sp: u64) -> Result<(), ReturnError> { self.owner_root(u)?; let value = self .mapping .lookup(OWNER, (sp - 1) & !(PAGE - 1)) .map_err(|_| ReturnError::Stack)? .ok_or(ReturnError::Stack)?; if value.permissions.user && value.permissions.write && !value.permissions.execute { Ok(()) } else { Err(ReturnError::Stack) } } } // SAFETY: CPU/frame/root/descriptor fields are explicit host model values. // Real frozen Mapping/PinnedRange copy operations use owned host RAM. Mode // drift cases intentionally violate callbacks to test the caller's quarantine. unsafe impl SyscallBackend for SysBackend { type Prepared = Prepared; fn execution(&self) -> Execution { self.execution.get() } fn live_frame(&self, f: &Frame, address: u64) -> bool { self.live .borrow() .as_ref() .is_some_and(|(actual, at)| actual == f && *at == address) } fn prepare_write(&mut self, u: User, r: Write) -> Result { self.prepares += 1; self.owner_root(u).map_err(|_| Errno::Access)?; self.observed_fd = Some(r.fd()); match r.fd() { 1 => (), 2 => return Err(Errno::Access), _ => return Err(Errno::BadFd), } if self.mode == Mode::NoMem { return Err(Errno::NoMem); } let mut bytes = vec![0xcc; r.bytes()]; copy_from_user(&mut self.mapping, OWNER, window(), r.address(), &mut bytes) .map_err(|_| Errno::Fault)?; assert_eq!(self.pins(), 0); self.issued = self.issued.checked_add(1).unwrap(); self.references.set(self.references.get() + 1); if self.mode == Mode::PrepareCpuDrift { self.set_execution(|e| e.cpu = 1) } if self.mode == Mode::PrepareRootInvalid { self.valid_root.set(false) } Ok(Prepared { bytes, owner: u, id: self.issued, fd: r.fd(), references: self.references.clone(), }) } fn commit_write(&mut self, p: &mut Prepared) -> Result { self.commits += 1; assert_eq!(p.id, self.issued); assert_eq!(p.fd, 1); assert_eq!(p.owner, user()); assert!(Rc::ptr_eq(&p.references, &self.references)); assert_eq!(self.references.get(), 1); if self.mode == Mode::CommitIo { return Err(Errno::Io); } self.output.extend_from_slice(&p.bytes); if self.mode == Mode::CommitCpuDrift { self.set_execution(|e| e.cpu = 1) } if self.mode == Mode::CommitRootInvalid { self.valid_root.set(false) } Ok(p.bytes.len() as u64 + u64::from(self.mode == Mode::WrongLength)) } fn release_write(&mut self, p: Prepared) -> Result<(), Prepared> { self.releases += 1; if self.mode == Mode::ReleaseFail { return Err(p); } assert_eq!(p.id, self.issued); assert!(Rc::ptr_eq(&p.references, &self.references)); assert_eq!(self.references.get(), 1); self.references.set(0); if self.mode == Mode::ReleaseCpuDrift { self.set_execution(|e| e.cpu = 1) } Ok(()) } }