use platform::Platform; use super::{SyscallOutcome, SyscallResult}; use crate::Kernel; impl Kernel

{ pub(crate) fn handle_create_endpoint( &mut self, caller_pid: types::id::ProcessId, ) -> SyscallOutcome { let ep_id = match self.create_endpoint() { Ok(id) => id, Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; let all_perms = types::permission::PermissionSet::empty() .with(types::permission::Permission::Read) .with(types::permission::Permission::Write) .with(types::permission::Permission::Execute) .with(types::permission::Permission::Delegate); match self.grant_cap( caller_pid, domain::resource::Resource::Endpoint(ep_id), all_perms, ) { Ok(slot) => SyscallOutcome::Complete(SyscallResult::Slot(slot)), Err(e) => SyscallOutcome::Complete(SyscallResult::Error(e)), } } pub(crate) fn handle_send( &mut self, caller_tid: types::id::ThreadId, caller_pid: types::id::ProcessId, endpoint_slot: types::bounded::CapSlot, message: domain::message::Message, ) -> SyscallOutcome { use domain::scheduler::Scheduler; let ep_id = match self.check_cap( caller_pid, endpoint_slot, types::permission::Permission::Execute, ) { Ok(cap) => match cap.resource() { domain::resource::Resource::Endpoint(id) => *id, _ => return SyscallOutcome::Complete(SyscallResult::Error( domain::error::KernelError::InvalidEndpoint(types::id::EndpointId::from_raw(0)), )), }, Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; let endpoint = match self.endpoints.get_mut(ep_id) { Some(ep) => ep, None => return SyscallOutcome::Complete(SyscallResult::Error( domain::error::KernelError::InvalidEndpoint(ep_id), )), }; if endpoint.has_waiting_receiver() { let receiver_tid = match endpoint.dequeue_receiver() { Some(t) => t, None => return SyscallOutcome::Complete(SyscallResult::Error( domain::error::KernelError::WouldBlock, )), }; self.pending_results[receiver_tid.raw() as usize] = Some(SyscallResult::Message(message)); let core = self.platform.core_id(); let receiver = match self.threads.get_mut(receiver_tid) { Ok(t) => t, Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; let _ = receiver.unblock(); let _ = receiver.set_running(core); let caller = match self.threads.get_mut(caller_tid) { Ok(t) => t, Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; let caller_priority = caller.priority(); let _ = caller.preempt(); self.scheduler.add(caller_tid, caller_priority, core); self.scheduler.set_current(core, receiver_tid); SyscallOutcome::SwitchTo(receiver_tid) } else { self.pending_messages[caller_tid.raw() as usize] = Some(message); let endpoint = match self.endpoints.get_mut(ep_id) { Some(ep) => ep, None => return SyscallOutcome::Complete(SyscallResult::Error( domain::error::KernelError::InvalidEndpoint(ep_id), )), }; let _ = endpoint.enqueue_sender(caller_tid); let caller = match self.threads.get_mut(caller_tid) { Ok(t) => t, Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; let _ = caller.block(domain::thread::BlockReason::Sending(endpoint_slot)); self.scheduler.remove(caller_tid); SyscallOutcome::BlockCaller(domain::thread::BlockReason::Sending(endpoint_slot)) } } pub(crate) fn handle_receive( &mut self, caller_tid: types::id::ThreadId, caller_pid: types::id::ProcessId, endpoint_slot: types::bounded::CapSlot, ) -> SyscallOutcome { use domain::scheduler::Scheduler; let ep_id = match self.check_cap( caller_pid, endpoint_slot, types::permission::Permission::Read, ) { Ok(cap) => match cap.resource() { domain::resource::Resource::Endpoint(id) => *id, _ => return SyscallOutcome::Complete(SyscallResult::Error( domain::error::KernelError::InvalidEndpoint(types::id::EndpointId::from_raw(0)), )), }, Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; let endpoint = match self.endpoints.get_mut(ep_id) { Some(ep) => ep, None => return SyscallOutcome::Complete(SyscallResult::Error( domain::error::KernelError::InvalidEndpoint(ep_id), )), }; if endpoint.has_waiting_sender() { let sender_tid = match endpoint.dequeue_sender() { Some(t) => t, None => return SyscallOutcome::Complete(SyscallResult::Error( domain::error::KernelError::WouldBlock, )), }; let message = self.pending_messages[sender_tid.raw() as usize] .take() .unwrap_or_else(|| domain::message::Message::empty()); self.pending_results[sender_tid.raw() as usize] = Some(SyscallResult::Ok); let sender = match self.threads.get_mut(sender_tid) { Ok(t) => t, Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; let priority = sender.priority(); let _ = sender.unblock(); let core = self.platform.core_id(); self.scheduler.add(sender_tid, priority, core); SyscallOutcome::Complete(SyscallResult::Message(message)) } else { let endpoint = match self.endpoints.get_mut(ep_id) { Some(ep) => ep, None => return SyscallOutcome::Complete(SyscallResult::Error( domain::error::KernelError::InvalidEndpoint(ep_id), )), }; let _ = endpoint.enqueue_receiver(caller_tid); let caller = match self.threads.get_mut(caller_tid) { Ok(t) => t, Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; let _ = caller.block(domain::thread::BlockReason::Receiving(endpoint_slot)); self.scheduler.remove(caller_tid); SyscallOutcome::BlockCaller(domain::thread::BlockReason::Receiving(endpoint_slot)) } } pub(crate) fn handle_wait_for_interrupt( &mut self, caller_tid: types::id::ThreadId, caller_pid: types::id::ProcessId, irq_slot: types::bounded::CapSlot, ) -> SyscallOutcome { use domain::scheduler::Scheduler; let irq_id = match self.check_cap( caller_pid, irq_slot, types::permission::Permission::Read, ) { Ok(cap) => match cap.resource() { domain::resource::Resource::Interrupt(id) => *id, _ => return SyscallOutcome::Complete(SyscallResult::Error( domain::error::KernelError::InvalidIrq(types::id::IrqId::from_raw(0)), )), }, Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; let _ = self.irqs.register(irq_id, caller_tid); let caller = match self.threads.get_mut(caller_tid) { Ok(t) => t, Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; let _ = caller.block(domain::thread::BlockReason::WaitingForInterrupt(irq_slot)); self.scheduler.remove(caller_tid); SyscallOutcome::BlockCaller(domain::thread::BlockReason::WaitingForInterrupt(irq_slot)) } pub(crate) fn handle_ack_interrupt( &mut self, caller_pid: types::id::ProcessId, irq_slot: types::bounded::CapSlot, ) -> SyscallOutcome { let irq_id = match self.check_cap( caller_pid, irq_slot, types::permission::Permission::Write, ) { Ok(cap) => match cap.resource() { domain::resource::Resource::Interrupt(id) => *id, _ => return SyscallOutcome::Complete(SyscallResult::Error( domain::error::KernelError::InvalidIrq(types::id::IrqId::from_raw(0)), )), }, Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; self.platform.unmask_irq(irq_id); SyscallOutcome::Complete(SyscallResult::Ok) } pub(crate) fn handle_wait_any( &mut self, caller_tid: types::id::ThreadId, caller_pid: types::id::ProcessId, sources: domain::syscall::WaitSet, ) -> SyscallOutcome { use domain::scheduler::Scheduler; if sources.is_empty() { return SyscallOutcome::Complete(SyscallResult::Error( domain::error::KernelError::WouldBlock, )); } for ep_slot in sources.endpoints() { if let Some(slot) = ep_slot { let ep_id = match self.check_cap( caller_pid, *slot, types::permission::Permission::Read, ) { Ok(cap) => match cap.resource() { domain::resource::Resource::Endpoint(id) => *id, _ => continue, }, Err(_) => continue, }; if let Some(ep) = self.endpoints.get_mut(ep_id) { if ep.has_waiting_sender() { return SyscallOutcome::Complete(SyscallResult::WakeReason( domain::syscall::WakeReason::MessageReady(*slot), )); } } } } for irq_slot in sources.interrupts() { if let Some(slot) = irq_slot { if let Ok(cap) = self.check_cap( caller_pid, *slot, types::permission::Permission::Read, ) { if let domain::resource::Resource::Interrupt(irq_id) = cap.resource() { if self.irqs.owner(*irq_id).is_some() { return SyscallOutcome::Complete(SyscallResult::WakeReason( domain::syscall::WakeReason::InterruptFired(*slot), )); } } } } } for ep_slot in sources.endpoints() { if let Some(slot) = ep_slot { if let Ok(cap) = self.check_cap(caller_pid, *slot, types::permission::Permission::Read) { if let domain::resource::Resource::Endpoint(id) = cap.resource() { if let Some(ep) = self.endpoints.get_mut(*id) { let _ = ep.enqueue_receiver(caller_tid); } } } } } self.wait_sets[caller_tid.raw() as usize] = Some(sources); let caller = match self.threads.get_mut(caller_tid) { Ok(t) => t, Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; let _ = caller.block(domain::thread::BlockReason::WaitingAny); self.scheduler.remove(caller_tid); SyscallOutcome::BlockCaller(domain::thread::BlockReason::WaitingAny) } }