mod capability; mod fault; mod ipc; mod lifecycle; mod memory; mod simple; use domain::{error::KernelError, syscall::Syscall}; use platform::Platform; use types::{bounded::CapSlot, id::ThreadId, syscall_abi::ErrorCode}; use crate::Kernel; pub use ipc::{IpcState, ThreadRef}; pub use types::syscall_abi::{Delivery, DeliveryKind}; pub enum SyscallOutcome { Complete(SyscallResult), BlockCaller(domain::thread::BlockReason), /// The caller blocked and `ThreadId` should run next. SwitchTo(ThreadId), TerminateCaller, } #[derive(Debug)] pub enum SyscallResult { Ok, Value(usize), Slot(CapSlot), Received(Delivery), Error(KernelError), } /// The status code userspace sees for a kernel error. pub fn error_code(error: &KernelError) -> ErrorCode { use KernelError::*; match error { InvalidSlot(_) | RevokedCapability(_) | NoSuchObject | InvalidEndpoint(_) => { ErrorCode::InvalidCap } PermissionDenied { .. } | ProcessCreateDenied | WritableAndExecutable => { ErrorCode::PermissionDenied } WrongObject => ErrorCode::WrongObject, NoFreeSlot => ErrorCode::NoFreeSlot, OutOfMemory => ErrorCode::OutOfMemory, InvalidAddress => ErrorCode::InvalidAddress, AddressInUse => ErrorCode::AddressInUse, NoReply => ErrorCode::NoReply, TooManyThreadsInProcess | TooManyProcesses | TooManyThreads | EndpointFull => { ErrorCode::LimitReached } InvalidProcess(_) | InvalidThread(_) | InvalidStateTransition(_) | InvalidIrq(_) | InvalidRegion | IrqAlreadyOwned(_) | WouldBlock | InvalidArgument => ErrorCode::InvalidArgument, } } fn complete(result: Result) -> SyscallOutcome { SyscallOutcome::Complete(result.unwrap_or_else(SyscallResult::Error)) } impl Kernel

{ pub fn handle_syscall(&mut self, syscall: Syscall) -> SyscallOutcome { let (tid, pid) = match self.caller() { Ok(caller) => caller, Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; match syscall { Syscall::GetTime => self.handle_get_time(), Syscall::GetProcessId => self.handle_get_process_id(pid), Syscall::Yield => self.handle_yield(tid), Syscall::Exit => self.handle_exit(tid, pid), Syscall::ExitThread => self.handle_exit_thread(tid, pid), Syscall::RequestPages { count } => self.handle_request_pages(pid, count), Syscall::ReleasePages { addr, count } => self.handle_release_pages(pid, addr, count), Syscall::SpawnThread { entry, stack, arg } => { self.handle_spawn_thread(pid, entry, stack, arg) } Syscall::CreateProcess { create_cap, image, limits, } => self.handle_create_process(pid, create_cap, image, limits), Syscall::Kill { process } => self.handle_kill(pid, process), Syscall::Revoke { slot } => self.handle_revoke(pid, slot), Syscall::DropCap { slot } => self.handle_drop_cap(pid, slot), Syscall::CreateRegion { pages } => { complete(self.create_region_cap(pid, pages).map(SyscallResult::Slot)) } Syscall::MapRegion { region, va, perms } => complete( self.map_region_cap(pid, region, va, perms) .map(|pages| SyscallResult::Value(pages.value() as usize)), ), Syscall::RegionAddress { region } => complete( self.region_address_cap(pid, region) .map(|pa| SyscallResult::Value(pa.raw())), ), Syscall::WatchDeath { process, notification, } => complete( self.watch_death(pid, process, notification) .map(|()| SyscallResult::Ok), ), Syscall::SetTimer { notification, deadline, } => complete( self.set_timer(pid, notification, deadline) .map(|()| SyscallResult::Ok), ), Syscall::Delegate { slot, to_endpoint, permissions, } => self.handle_delegate(pid, slot, to_endpoint, permissions), Syscall::Mint { slot, badge, permissions, } => complete( self.mint(pid, slot, badge, permissions) .map(SyscallResult::Slot), ), Syscall::Send { endpoint, message } => self.send(tid, pid, endpoint, message, false), Syscall::Call { endpoint, message } => self.send(tid, pid, endpoint, message, true), Syscall::Receive { endpoint } => self.receive(tid, pid, endpoint, true), Syscall::Reply { message } => { complete(self.reply(tid, pid, message).map(|()| SyscallResult::Ok)) } Syscall::ReplyRecv { endpoint, message } => { self.reply_recv(tid, pid, endpoint, message) } Syscall::SaveReply => complete( self.save_reply(tid) .map(|r| SyscallResult::Value(usize::from(r.value()))), ), Syscall::ReplySaved { reply, message } => complete( self.reply_saved(tid, pid, reply, message) .map(|()| SyscallResult::Ok), ), Syscall::CreateNotification => { complete(self.create_notification_cap(pid).map(SyscallResult::Slot)) } Syscall::Signal { notification } => { complete(self.signal(pid, notification).map(|()| SyscallResult::Ok)) } Syscall::Wait { notification } => self.wait(tid, pid, notification), Syscall::Poll { notification } => complete( self.poll(pid, notification) .map(|bits| SyscallResult::Received(Delivery::signal(bits))), ), Syscall::BindNotification { notification } => complete( self.bind_notification(tid, pid, notification) .map(|()| SyscallResult::Ok), ), Syscall::SetIrqNotification { irq, notification } => complete( self.set_irq_notification(pid, irq, notification) .map(|()| SyscallResult::Ok), ), Syscall::AcknowledgeInterrupt { irq } => { complete(self.ack_interrupt(pid, irq).map(|()| SyscallResult::Ok)) } Syscall::Halt { control } => self.handle_halt(pid, control), Syscall::CreateEndpoint => self.handle_create_endpoint(pid), Syscall::DebugPutchar { console, byte } => complete( self.debug_putchar(pid, console, byte) .map(|()| SyscallResult::Ok), ), Syscall::MapPage { process, src_va, dst_va, executable, } => self.handle_map_page(pid, process, src_va, dst_va, executable), Syscall::SpawnThreadIn { process, entry, stack, arg, } => self.handle_spawn_thread_in(pid, process, entry, stack, arg), } } }