feat(kernel): add Kernel struct, MockPlatform, and simple syscalls (GetTime, GetProcessId, Yield)
This commit is contained in:
@@ -1,14 +1,151 @@
|
||||
pub fn add(left: u64, right: u64) -> u64 {
|
||||
left + right
|
||||
}
|
||||
#![no_std]
|
||||
|
||||
pub mod interrupt;
|
||||
pub mod syscall;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[path = "tests/mod.rs"]
|
||||
mod tests;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
use domain::{
|
||||
capability::{Capability, CapabilityTable},
|
||||
endpoint::EndpointTable,
|
||||
error::KernelError,
|
||||
irq::IrqRoutingTable,
|
||||
memory::{
|
||||
page_pool::PagePool,
|
||||
process_memory::ProcessMemory,
|
||||
RegionTable,
|
||||
},
|
||||
message::Message,
|
||||
process::{ProcessTable, MAX_PROCESSES},
|
||||
resource::Resource,
|
||||
scheduler::{multi_core::MultiCoreScheduler, Scheduler},
|
||||
thread::{ThreadTable, ThreadState, MAX_THREADS},
|
||||
};
|
||||
use platform::Platform;
|
||||
use types::{
|
||||
bounded::{CapSlot, Priority},
|
||||
generation::Generation,
|
||||
id::{ProcessId, ThreadId},
|
||||
permission::{Permission, PermissionSet},
|
||||
time::TimeSlice,
|
||||
};
|
||||
|
||||
pub enum SyscallOutcome {
|
||||
Complete(SyscallResult),
|
||||
BlockCaller(domain::thread::BlockReason),
|
||||
SwitchTo(ThreadId),
|
||||
TerminateCaller,
|
||||
}
|
||||
|
||||
pub enum SyscallResult {
|
||||
Ok,
|
||||
Value(usize),
|
||||
Slot(CapSlot),
|
||||
Message(Message),
|
||||
WakeReason(domain::syscall::WakeReason),
|
||||
Error(KernelError),
|
||||
}
|
||||
|
||||
pub struct Kernel<P: Platform> {
|
||||
platform: P,
|
||||
processes: ProcessTable,
|
||||
threads: ThreadTable,
|
||||
endpoints: EndpointTable,
|
||||
scheduler: MultiCoreScheduler,
|
||||
page_pool: PagePool,
|
||||
process_memory: [Option<ProcessMemory>; MAX_PROCESSES],
|
||||
regions: RegionTable,
|
||||
irqs: IrqRoutingTable,
|
||||
pending_messages: [Option<Message>; MAX_THREADS],
|
||||
pending_results: [Option<SyscallResult>; MAX_THREADS],
|
||||
}
|
||||
|
||||
impl<P: Platform> Kernel<P> {
|
||||
pub fn new(platform: P, page_pool: PagePool) -> Self {
|
||||
let num_cores = platform.num_cores();
|
||||
Self {
|
||||
platform,
|
||||
processes: ProcessTable::new(),
|
||||
threads: ThreadTable::new(),
|
||||
endpoints: EndpointTable::new(),
|
||||
scheduler: MultiCoreScheduler::new(num_cores),
|
||||
page_pool,
|
||||
process_memory: [const { None }; MAX_PROCESSES],
|
||||
regions: RegionTable::new(),
|
||||
irqs: IrqRoutingTable::new(),
|
||||
pending_messages: [const { None }; MAX_THREADS],
|
||||
pending_results: [const { None }; MAX_THREADS],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn boot(
|
||||
&mut self,
|
||||
priority: Priority,
|
||||
time_slice: TimeSlice,
|
||||
) -> Result<(ProcessId, ThreadId), KernelError> {
|
||||
let pid = self.processes.create(CapabilityTable::new(), None)?;
|
||||
let tid = self.threads.spawn(pid, priority, time_slice, None)?;
|
||||
self.processes.get_mut(pid)?.add_thread(tid)?;
|
||||
|
||||
self.process_memory[pid.raw() as usize] =
|
||||
Some(ProcessMemory::new(pid, 1024));
|
||||
|
||||
let cap = Capability::new(
|
||||
Resource::ProcessCreate,
|
||||
PermissionSet::empty().with(Permission::Execute),
|
||||
Generation::initial(),
|
||||
);
|
||||
self.processes.get_mut(pid)?.capabilities_mut().insert(cap)?;
|
||||
|
||||
let core = self.platform.core_id();
|
||||
self.scheduler.add(tid, priority, core);
|
||||
self.scheduler.next(core);
|
||||
self.threads.get_mut(tid)?.set_running(core)?;
|
||||
Ok((pid, tid))
|
||||
}
|
||||
|
||||
pub fn platform_mut(&mut self) -> &mut P {
|
||||
&mut self.platform
|
||||
}
|
||||
|
||||
pub fn pending_result(&self, thread: ThreadId) -> Option<&SyscallResult> {
|
||||
self.pending_results[thread.raw() as usize].as_ref()
|
||||
}
|
||||
|
||||
fn caller(&self) -> Result<(ThreadId, ProcessId), KernelError> {
|
||||
let core = self.platform.core_id();
|
||||
let tid = self.scheduler.current(core)
|
||||
.ok_or(KernelError::WouldBlock)?;
|
||||
let thread = self.threads.get(tid)?;
|
||||
match thread.state() {
|
||||
ThreadState::Running(_) => Ok((tid, thread.process())),
|
||||
_ => Err(KernelError::WouldBlock),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_cap(
|
||||
&self,
|
||||
owner: ProcessId,
|
||||
slot: CapSlot,
|
||||
needed: Permission,
|
||||
) -> Result<&Capability, KernelError> {
|
||||
let process = self.processes.get(owner)?;
|
||||
let cap = process.capabilities().get(slot)?;
|
||||
if !cap.permissions().allows(needed) {
|
||||
return Err(KernelError::PermissionDenied { slot, needed });
|
||||
}
|
||||
Ok(cap)
|
||||
}
|
||||
|
||||
fn grant_cap(
|
||||
&mut self,
|
||||
to: ProcessId,
|
||||
resource: Resource,
|
||||
permissions: PermissionSet,
|
||||
) -> Result<CapSlot, KernelError> {
|
||||
let cap = Capability::new(resource, permissions, Generation::initial());
|
||||
self.processes.get_mut(to)?.capabilities_mut().insert(cap)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user