feat(adapter-riscv): IPC demo — two processes exchange a message on QEMU virt
This commit is contained in:
@@ -76,11 +76,119 @@ extern "C" fn kmain() -> ! {
|
|||||||
uart.write_dec(tid.raw() as usize);
|
uart.write_dec(tid.raw() as usize);
|
||||||
uart.write_str(")\n");
|
uart.write_str(")\n");
|
||||||
|
|
||||||
|
ipc_demo(&mut kern, &uart, pid);
|
||||||
|
|
||||||
|
uart.write_str("k-os: demo complete\n");
|
||||||
loop {
|
loop {
|
||||||
unsafe { core::arch::asm!("wfi") };
|
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]
|
#[panic_handler]
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
let uart = Uart::new();
|
let uart = Uart::new();
|
||||||
|
|||||||
@@ -113,6 +113,44 @@ impl<P: Platform> Kernel<P> {
|
|||||||
self.processes.get(pid).is_ok()
|
self.processes.get(pid).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_endpoint(&mut self) -> Result<types::id::EndpointId, KernelError> {
|
||||||
|
self.endpoints.create().ok_or(KernelError::NoFreeSlot)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn grant_capability(
|
||||||
|
&mut self,
|
||||||
|
to: ProcessId,
|
||||||
|
resource: Resource,
|
||||||
|
permissions: PermissionSet,
|
||||||
|
) -> Result<CapSlot, KernelError> {
|
||||||
|
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> {
|
fn caller(&self) -> Result<(ThreadId, ProcessId), KernelError> {
|
||||||
let core = self.platform.core_id();
|
let core = self.platform.core_id();
|
||||||
let tid = self.scheduler.current(core)
|
let tid = self.scheduler.current(core)
|
||||||
|
|||||||
Reference in New Issue
Block a user