From 66a730b2fea5bf77d4865905334c8fe59deb4f96 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Sun, 18 Oct 2026 01:58:18 +0200 Subject: [PATCH] =?UTF-8?q?feat(adapter-riscv):=20IPC=20demo=20=E2=80=94?= =?UTF-8?q?=20two=20processes=20exchange=20a=20message=20on=20QEMU=20virt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/adapter-riscv/src/main.rs | 108 +++++++++++++++++++++++++++++++ crates/kernel/src/lib.rs | 38 +++++++++++ 2 files changed, 146 insertions(+) diff --git a/crates/adapter-riscv/src/main.rs b/crates/adapter-riscv/src/main.rs index 7f07ae7..115dc4b 100644 --- a/crates/adapter-riscv/src/main.rs +++ b/crates/adapter-riscv/src/main.rs @@ -76,11 +76,119 @@ extern "C" fn kmain() -> ! { uart.write_dec(tid.raw() as usize); uart.write_str(")\n"); + ipc_demo(&mut kern, &uart, pid); + + uart.write_str("k-os: demo complete\n"); loop { unsafe { core::arch::asm!("wfi") }; } } +fn ipc_demo( + kern: &mut kernel::Kernel, + uart: &Uart, + init_pid: types::id::ProcessId, +) { + use domain::message::Message; + use domain::resource::Resource; + use domain::syscall::Syscall; + use kernel::{SyscallOutcome, SyscallResult}; + use types::address::DataRef; + use types::bounded::CapSlot; + use types::id::ThreadId; + use types::permission::{Permission, PermissionSet}; + + uart.write_str("k-os: --- IPC demo ---\n"); + + // Create process B using init's ProcessCreate cap (slot 0) + let proc_b_slot = match kern.handle_syscall(Syscall::CreateProcess { + create_cap: CapSlot::new(0).unwrap_or_else(|| unreachable!()), + image: DataRef::empty(), + }) { + SyscallOutcome::Complete(SyscallResult::Slot(s)) => s, + _ => { + uart.write_str("k-os: FAIL creating process B\n"); + return; + } + }; + let pid_b = types::id::ProcessId::from_raw(1); + let tid_b = ThreadId::from_raw(1); + uart.write_str("k-os: process B created\n"); + + // Create an endpoint + let ep_id = kern.create_endpoint().unwrap_or_else(|_| unreachable!()); + + // Grant endpoint caps to both processes + let ep_cap_a = kern.grant_capability( + init_pid, + Resource::Endpoint(ep_id), + PermissionSet::empty() + .with(Permission::Execute) + .with(Permission::Read), + ).unwrap_or_else(|_| unreachable!()); + + let ep_cap_b = kern.grant_capability( + pid_b, + Resource::Endpoint(ep_id), + PermissionSet::empty() + .with(Permission::Execute) + .with(Permission::Read), + ).unwrap_or_else(|_| unreachable!()); + + uart.write_str("k-os: endpoint created, caps granted\n"); + + // Process B calls Receive (blocks — no sender yet) + kern.switch_to_thread(tid_b); + let outcome = kern.handle_syscall(Syscall::Receive { endpoint: ep_cap_b }); + match &outcome { + SyscallOutcome::BlockCaller(_) => { + uart.write_str("k-os: process B blocked on Receive\n"); + } + _ => { + uart.write_str("k-os: UNEXPECTED outcome for Receive\n"); + return; + } + } + + // Process A calls Send (finds B waiting → delivers message) + let tid_a = ThreadId::from_raw(0); + kern.switch_to_thread(tid_a); + let msg = Message::from_words([42, 7, 0, 0]); + let outcome = kern.handle_syscall(Syscall::Send { + endpoint: ep_cap_a, + message: msg, + }); + match &outcome { + SyscallOutcome::SwitchTo(target) => { + uart.write_str("k-os: Send delivered, switching to thread "); + uart.write_dec(target.raw() as usize); + uart.put_char(b'\n'); + } + _ => { + uart.write_str("k-os: UNEXPECTED outcome for Send\n"); + return; + } + } + + // Check B's pending result + match kern.pending_result(tid_b) { + Some(SyscallResult::Message(m)) => { + uart.write_str("k-os: IPC complete — received: ["); + uart.write_dec(m.word(0)); + uart.write_str(", "); + uart.write_dec(m.word(1)); + uart.write_str(", "); + uart.write_dec(m.word(2)); + uart.write_str(", "); + uart.write_dec(m.word(3)); + uart.write_str("]\n"); + } + _ => { + uart.write_str("k-os: FAIL — no message in pending result\n"); + } + } +} + #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { let uart = Uart::new(); diff --git a/crates/kernel/src/lib.rs b/crates/kernel/src/lib.rs index 9c481d3..a578765 100644 --- a/crates/kernel/src/lib.rs +++ b/crates/kernel/src/lib.rs @@ -113,6 +113,44 @@ impl Kernel

{ self.processes.get(pid).is_ok() } + pub fn create_endpoint(&mut self) -> Result { + self.endpoints.create().ok_or(KernelError::NoFreeSlot) + } + + pub fn grant_capability( + &mut self, + to: ProcessId, + resource: Resource, + permissions: PermissionSet, + ) -> Result { + self.grant_cap(to, resource, permissions) + } + + pub fn switch_to_thread(&mut self, tid: ThreadId) { + use domain::scheduler::Scheduler; + 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)); + } + } + } + fn caller(&self) -> Result<(ThreadId, ProcessId), KernelError> { let core = self.platform.core_id(); let tid = self.scheduler.current(core)