use domain::resource::Resource; use domain::scheduler::Scheduler; use domain::thread::ThreadState; use platform::Platform; use types::{ address::PhysicalAddress, bounded::{CapSlot, Priority}, id::{EndpointId, ProcessId, ThreadId}, permission::PermissionSet, time::TimeSlice, }; use super::mock_platform::MockPlatform; use crate::Kernel; pub fn test_kernel() -> Kernel { let mock = MockPlatform::new(1); Kernel::new(mock, PhysicalAddress::from_raw(0x8400_0000), 1024) } pub fn kernel_with_process() -> (Kernel, ProcessId) { let mut kernel = test_kernel(); let (pid, _tid) = kernel.boot(Priority::DEFAULT, TimeSlice::DEFAULT).unwrap(); (kernel, pid) } impl Kernel { pub fn spawn_thread_for_test( &mut self, pid: ProcessId, priority: Priority, time_slice: TimeSlice, ) -> ThreadId { let tid = self .threads .spawn(pid, priority, time_slice, None) .expect("spawn"); let _ = self.processes.get_mut(pid).map(|p| p.add_thread(tid)); let core = self.platform.core_id(); self.scheduler.add(tid, priority, core); tid } pub fn block_thread_for_test(&mut self, tid: ThreadId, reason: domain::thread::BlockReason) { let core = self.platform.core_id(); if let Ok(t) = self.threads.get_mut(tid) { if matches!(t.state(), ThreadState::Ready) { let _ = t.set_running(core); } let _ = t.block(reason); } self.scheduler.remove(tid); } pub fn switch_to_thread_for_test(&mut self, tid: ThreadId) { let core = self.platform.core_id(); if let Some(current) = self.scheduler.current(core) { if current == tid { return; } if let Ok(t) = self.threads.get_mut(current) && matches!(t.state(), ThreadState::Running(_)) { let priority = t.priority(); let _ = t.preempt(); self.scheduler.add(current, priority, core); } } if let Ok(t) = self.threads.get(tid) && matches!(t.state(), ThreadState::Ready) && self.scheduler.run_now(core, tid) { let _ = self.threads.get_mut(tid).map(|t| t.set_running(core)); } } pub fn create_endpoint_for_test(&mut self) -> EndpointId { self.endpoints .create(ProcessId::from_raw(0)) .expect("create endpoint") } pub fn grant_cap_for_test( &mut self, pid: ProcessId, resource: Resource, permissions: PermissionSet, ) -> CapSlot { self.grant_cap(pid, resource, permissions) .expect("grant cap") } pub fn endpoint_of_cap_for_test(&self, pid: ProcessId, slot: CapSlot) -> EndpointId { match self .processes .get(pid) .unwrap() .capabilities() .get(slot) .unwrap() .resource() { Resource::Endpoint(id) => *id, _ => panic!("not an endpoint cap"), } } /// The process a Process cap in init's table points at. pub fn process_of_cap_for_test(&self, slot: CapSlot) -> ProcessId { let init = ProcessId::from_raw(0); match self .processes .get(init) .unwrap() .capabilities() .get(slot) .unwrap() .resource() { Resource::Process(pid) => *pid, _ => panic!("not a process cap"), } } pub fn destroy_process_notifications_for_test(&mut self, owner: ProcessId) { self.destroy_notifications_owned_by(owner); } /// The process a Process cap in `pid`'s table names, if it is one. pub fn process_cap_target_for_test(&self, pid: ProcessId, slot: CapSlot) -> Option { match self .processes .get(pid) .ok()? .capabilities() .get(slot) .ok()? .resource() { Resource::Process(target) if self.process_exists(*target) => Some(*target), _ => None, } } /// Which slots of `pid`'s capability table are occupied. pub fn cap_slots_for_test(&self, pid: ProcessId) -> [bool; 64] { let mut used = [false; 64]; if let Ok(p) = self.processes.get(pid) { for (slot, _) in p.capabilities().iter() { used[slot.value() as usize] = true; } } used } pub fn thread_state_for_test(&self, tid: ThreadId) -> Option { self.threads.get(tid).ok().map(|t| *t.state()) } }