refactor(kernel): extract MockPlatform and test helpers into separate modules
This commit is contained in:
100
crates/kernel/src/tests/helpers.rs
Normal file
100
crates/kernel/src/tests/helpers.rs
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
use domain::memory::page_pool::PagePool;
|
||||||
|
use domain::resource::Resource;
|
||||||
|
use domain::scheduler::Scheduler;
|
||||||
|
use domain::thread::ThreadState;
|
||||||
|
use platform::Platform;
|
||||||
|
use types::{
|
||||||
|
address::PhysicalAddress,
|
||||||
|
bounded::{CapSlot, Priority},
|
||||||
|
id::{EndpointId, IrqId, ProcessId, ThreadId},
|
||||||
|
permission::PermissionSet,
|
||||||
|
time::TimeSlice,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::Kernel;
|
||||||
|
use super::mock_platform::MockPlatform;
|
||||||
|
|
||||||
|
pub fn test_kernel() -> Kernel<MockPlatform> {
|
||||||
|
let mock = MockPlatform::new(1);
|
||||||
|
let pool = PagePool::new(PhysicalAddress::from_raw(0x8000_0000), 1024);
|
||||||
|
Kernel::new(mock, pool)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kernel_with_process() -> (Kernel<MockPlatform>, ProcessId) {
|
||||||
|
let mut kernel = test_kernel();
|
||||||
|
let (pid, _tid) = kernel
|
||||||
|
.boot(Priority::new(16).unwrap(), TimeSlice::new(100))
|
||||||
|
.unwrap();
|
||||||
|
(kernel, pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Kernel<MockPlatform> {
|
||||||
|
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 register_irq_for_test(&mut self, irq: IrqId, thread: ThreadId) {
|
||||||
|
let _ = self.irqs.register(irq, thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
if 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) {
|
||||||
|
if matches!(t.state(), ThreadState::Ready) {
|
||||||
|
self.scheduler.next(core);
|
||||||
|
let _ = self.threads.get_mut(tid).map(|t| t.set_running(core));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_endpoint_for_test(&mut self) -> EndpointId {
|
||||||
|
self.endpoints.create().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")
|
||||||
|
}
|
||||||
|
}
|
||||||
49
crates/kernel/src/tests/mock_platform.rs
Normal file
49
crates/kernel/src/tests/mock_platform.rs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
use domain::memory::MemoryRegion;
|
||||||
|
use domain::thread::SavedContext;
|
||||||
|
use platform::Platform;
|
||||||
|
use types::{
|
||||||
|
address::{EntryPoint, StackPointer},
|
||||||
|
id::{CoreId, IrqId, ProcessId},
|
||||||
|
time::{Ticks, TimerDuration},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct MockPlatform {
|
||||||
|
ticks: Ticks,
|
||||||
|
core: CoreId,
|
||||||
|
cores: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MockPlatform {
|
||||||
|
pub fn new(num_cores: u8) -> Self {
|
||||||
|
Self {
|
||||||
|
ticks: Ticks::from_raw(0),
|
||||||
|
core: CoreId::from_raw(0),
|
||||||
|
cores: num_cores,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_ticks(&mut self, ticks: Ticks) {
|
||||||
|
self.ticks = ticks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Platform for MockPlatform {
|
||||||
|
fn configure_protection(&mut self, _process: ProcessId, _regions: &[MemoryRegion]) {}
|
||||||
|
fn context_switch(&mut self, _from: &mut SavedContext, _to: &SavedContext) {}
|
||||||
|
fn enable_user_mode(&mut self, _entry: EntryPoint, _stack: StackPointer) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
fn set_timer(&mut self, _duration: TimerDuration) {}
|
||||||
|
fn current_ticks(&self) -> Ticks {
|
||||||
|
self.ticks
|
||||||
|
}
|
||||||
|
fn mask_irq(&mut self, _irq: IrqId) {}
|
||||||
|
fn unmask_irq(&mut self, _irq: IrqId) {}
|
||||||
|
fn send_ipi(&mut self, _target: CoreId) {}
|
||||||
|
fn core_id(&self) -> CoreId {
|
||||||
|
self.core
|
||||||
|
}
|
||||||
|
fn num_cores(&self) -> u8 {
|
||||||
|
self.cores
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
mod mock_platform;
|
||||||
|
mod helpers;
|
||||||
|
|
||||||
mod capability;
|
mod capability;
|
||||||
mod exit;
|
mod exit;
|
||||||
mod ipc;
|
mod ipc;
|
||||||
@@ -6,144 +9,12 @@ mod memory;
|
|||||||
mod simple;
|
mod simple;
|
||||||
mod tick;
|
mod tick;
|
||||||
|
|
||||||
use domain::memory::page_pool::PagePool;
|
pub use mock_platform::MockPlatform;
|
||||||
use domain::memory::MemoryRegion;
|
pub use helpers::{test_kernel, kernel_with_process};
|
||||||
use domain::resource::Resource;
|
|
||||||
use domain::scheduler::Scheduler;
|
|
||||||
use domain::thread::{SavedContext, ThreadState};
|
|
||||||
use platform::Platform;
|
|
||||||
use types::{
|
|
||||||
address::{EntryPoint, PhysicalAddress, StackPointer},
|
|
||||||
bounded::{CapSlot, Priority},
|
|
||||||
id::{CoreId, EndpointId, IrqId, ProcessId, ThreadId},
|
|
||||||
permission::PermissionSet,
|
|
||||||
time::{Ticks, TimerDuration, TimeSlice},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{Kernel, SyscallResult};
|
pub use crate::Kernel;
|
||||||
|
pub use types::address::PhysicalAddress;
|
||||||
pub struct MockPlatform {
|
pub use types::bounded::Priority;
|
||||||
ticks: Ticks,
|
pub use types::id::ProcessId;
|
||||||
core: CoreId,
|
pub use types::time::TimeSlice;
|
||||||
cores: u8,
|
pub use domain::memory::page_pool::PagePool;
|
||||||
}
|
|
||||||
|
|
||||||
impl MockPlatform {
|
|
||||||
pub fn new(num_cores: u8) -> Self {
|
|
||||||
Self {
|
|
||||||
ticks: Ticks::from_raw(0),
|
|
||||||
core: CoreId::from_raw(0),
|
|
||||||
cores: num_cores,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_ticks(&mut self, ticks: Ticks) {
|
|
||||||
self.ticks = ticks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Platform for MockPlatform {
|
|
||||||
fn configure_protection(&mut self, _process: ProcessId, _regions: &[MemoryRegion]) {}
|
|
||||||
fn context_switch(&mut self, _from: &mut SavedContext, _to: &SavedContext) {}
|
|
||||||
fn enable_user_mode(&mut self, _entry: EntryPoint, _stack: StackPointer) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
fn set_timer(&mut self, _duration: TimerDuration) {}
|
|
||||||
fn current_ticks(&self) -> Ticks {
|
|
||||||
self.ticks
|
|
||||||
}
|
|
||||||
fn mask_irq(&mut self, _irq: IrqId) {}
|
|
||||||
fn unmask_irq(&mut self, _irq: IrqId) {}
|
|
||||||
fn send_ipi(&mut self, _target: CoreId) {}
|
|
||||||
fn core_id(&self) -> CoreId {
|
|
||||||
self.core
|
|
||||||
}
|
|
||||||
fn num_cores(&self) -> u8 {
|
|
||||||
self.cores
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn test_kernel() -> Kernel<MockPlatform> {
|
|
||||||
let mock = MockPlatform::new(1);
|
|
||||||
let pool = PagePool::new(PhysicalAddress::from_raw(0x8000_0000), 1024);
|
|
||||||
Kernel::new(mock, pool)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kernel_with_process() -> (Kernel<MockPlatform>, ProcessId) {
|
|
||||||
let mut kernel = test_kernel();
|
|
||||||
let (pid, _tid) = kernel
|
|
||||||
.boot(Priority::new(16).unwrap(), TimeSlice::new(100))
|
|
||||||
.unwrap();
|
|
||||||
(kernel, pid)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Kernel<MockPlatform> {
|
|
||||||
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 register_irq_for_test(&mut self, irq: IrqId, thread: ThreadId) {
|
|
||||||
let _ = self.irqs.register(irq, thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
if 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) {
|
|
||||||
if matches!(t.state(), ThreadState::Ready) {
|
|
||||||
self.scheduler.next(core);
|
|
||||||
let _ = self.threads.get_mut(tid).map(|t| t.set_running(core));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_endpoint_for_test(&mut self) -> EndpointId {
|
|
||||||
self.endpoints.create().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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user