feat: userspace round-trip — syscall stubs, ecall dispatch, U-mode entry and exit on QEMU
This commit is contained in:
@@ -17,8 +17,6 @@ impl TrapFrame {
|
||||
}
|
||||
}
|
||||
|
||||
// sscratch = 0 when in S-mode, = kernel_stack_top when in U-mode.
|
||||
// On trap: swap sp/sscratch. If sp==0 after swap, we came from S-mode (undo swap).
|
||||
global_asm!(r#"
|
||||
.align 4
|
||||
.globl trap_vector
|
||||
@@ -149,6 +147,68 @@ pub fn set_kernel_stack(kernel_sp: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_syscall(frame: &TrapFrame) -> Option<domain::syscall::Syscall> {
|
||||
use domain::message::Message;
|
||||
use domain::syscall::Syscall;
|
||||
use types::syscall_abi::*;
|
||||
|
||||
let nr = frame.regs[17]; // a7
|
||||
let a0 = frame.regs[10]; // a0
|
||||
let a1 = frame.regs[11]; // a1
|
||||
let a2 = frame.regs[12]; // a2
|
||||
let a3 = frame.regs[13]; // a3
|
||||
let a4 = frame.regs[14]; // a4
|
||||
|
||||
match nr {
|
||||
SYS_EXIT => Some(Syscall::Exit),
|
||||
SYS_EXIT_THREAD => Some(Syscall::ExitThread),
|
||||
SYS_YIELD => Some(Syscall::Yield),
|
||||
SYS_GET_TIME => Some(Syscall::GetTime),
|
||||
SYS_GET_PROCESS_ID => Some(Syscall::GetProcessId),
|
||||
SYS_SEND => {
|
||||
let slot = types::bounded::CapSlot::new(a0 as u8)?;
|
||||
let msg = Message::from_words([a1, a2, a3, a4]);
|
||||
Some(Syscall::Send { endpoint: slot, message: msg })
|
||||
}
|
||||
SYS_RECEIVE => {
|
||||
let slot = types::bounded::CapSlot::new(a0 as u8)?;
|
||||
Some(Syscall::Receive { endpoint: slot })
|
||||
}
|
||||
SYS_SPAWN_THREAD => Some(Syscall::SpawnThread {
|
||||
entry: types::address::EntryPoint::from_raw(a0),
|
||||
stack: types::address::StackPointer::from_raw(a1),
|
||||
}),
|
||||
SYS_REQUEST_PAGES => {
|
||||
let count = types::bounded::PageCount::new(a0 as u16)?;
|
||||
Some(Syscall::RequestPages { count })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn write_result(frame: &mut TrapFrame, outcome: &kernel::SyscallOutcome) {
|
||||
use kernel::{SyscallOutcome, SyscallResult};
|
||||
|
||||
match outcome {
|
||||
SyscallOutcome::Complete(result) => match result {
|
||||
SyscallResult::Ok => frame.regs[10] = 0,
|
||||
SyscallResult::Value(v) => frame.regs[10] = *v,
|
||||
SyscallResult::Slot(s) => frame.regs[10] = s.value() as usize,
|
||||
SyscallResult::Message(m) => {
|
||||
frame.regs[10] = m.word(0);
|
||||
frame.regs[11] = m.word(1);
|
||||
frame.regs[12] = m.word(2);
|
||||
frame.regs[13] = m.word(3);
|
||||
}
|
||||
SyscallResult::Error(_) => frame.regs[10] = usize::MAX,
|
||||
SyscallResult::WakeReason(_) => frame.regs[10] = 0,
|
||||
},
|
||||
SyscallOutcome::BlockCaller(_) => {}
|
||||
SyscallOutcome::SwitchTo(_) => frame.regs[10] = 0,
|
||||
SyscallOutcome::TerminateCaller => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "C" fn trap_handler_rust(frame: &mut TrapFrame) {
|
||||
let scause: usize;
|
||||
@@ -171,7 +231,19 @@ extern "C" fn trap_handler_rust(frame: &mut TrapFrame) {
|
||||
match scause {
|
||||
CAUSE_ECALL_U => {
|
||||
frame.sepc += 4;
|
||||
uart.write_str("[ecall]\n");
|
||||
|
||||
if let Some(syscall) = decode_syscall(frame) {
|
||||
let kern = crate::kernel_mut();
|
||||
let outcome = kern.handle_syscall(syscall);
|
||||
write_result(frame, &outcome);
|
||||
|
||||
match &outcome {
|
||||
kernel::SyscallOutcome::TerminateCaller => {
|
||||
uart.write_str("k-os: process exited\n");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
uart.write_str("FAULT: scause=");
|
||||
|
||||
Reference in New Issue
Block a user