feat(adapter-riscv): IPC demo — two processes exchange a message on QEMU virt

This commit is contained in:
2026-10-18 01:58:18 +02:00
parent 2436061215
commit 66a730b2fe
2 changed files with 146 additions and 0 deletions

View File

@@ -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<platform::RiscVPlatform>,
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();