Files
k-os/crates/kernel/src/syscall/mod.rs

192 lines
7.4 KiB
Rust

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<SyscallResult, KernelError>) -> SyscallOutcome {
SyscallOutcome::Complete(result.unwrap_or_else(SyscallResult::Error))
}
impl<P: Platform> Kernel<P> {
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),
}
}
}