asterinas/src/kxos-std/src/syscall/mod.rs

96 lines
2.8 KiB
Rust

use alloc::ffi::CString;
use alloc::vec;
use alloc::{sync::Arc, vec::Vec};
use kxos_frame::cpu::CpuContext;
use kxos_frame::Error;
use kxos_frame::{task::Task, user::UserSpace, vm::VmIo};
use kxos_frame::info;
use crate::process::task::HandlerResult;
const SYS_WRITE: u64 = 1;
const SYS_EXIT: u64 = 60;
pub struct SyscallFrame {
syscall_number: u64,
args: [u64; 6],
}
pub enum SyscallResult {
Exit(i32),
Return(i32),
}
impl SyscallFrame {
fn new_from_context(context: &CpuContext) -> Self {
let syscall_number = context.gp_regs.rax;
let mut args = [0u64; 6];
args[0] = context.gp_regs.rdi;
args[1] = context.gp_regs.rsi;
args[2] = context.gp_regs.rdx;
args[3] = context.gp_regs.r10;
args[4] = context.gp_regs.r8;
args[5] = context.gp_regs.r9;
Self {
syscall_number,
args,
}
}
}
pub fn syscall_handler(context: &mut CpuContext) -> HandlerResult {
let syscall_frame = SyscallFrame::new_from_context(context);
let syscall_return = syscall_dispatch(syscall_frame.syscall_number, syscall_frame.args);
match syscall_return {
SyscallResult::Return(return_value) => {
// FIXME: set return value?
context.gp_regs.rax = return_value as u64;
HandlerResult::Continue
}
SyscallResult::Exit(exit_code) => HandlerResult::Exit,
}
}
pub fn syscall_dispatch(syscall_number: u64, args: [u64; 6]) -> SyscallResult {
match syscall_number {
SYS_WRITE => sys_write(args[0], args[1], args[2]),
SYS_EXIT => sys_exit(args[0] as _),
_ => panic!("Unsupported syscall number: {}", syscall_number),
}
}
pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> SyscallResult {
// only suppprt STDOUT now.
const STDOUT: u64 = 1;
if fd == STDOUT {
let task = Task::current();
let user_space = task.user_space().expect("No user space attached");
let user_buffer =
copy_bytes_from_user(user_space, user_buf_ptr as usize, user_buf_len as usize)
.expect("read user buffer failed");
let content = CString::from_vec_with_nul(user_buffer).expect("read string failed");
// TODO: print content
info!("Message from user mode: {:?}", content);
SyscallResult::Return(0)
} else {
panic!("Unsupported fd number {}", fd);
}
}
pub fn sys_exit(exit_code: i32) -> SyscallResult {
SyscallResult::Exit(exit_code)
}
fn copy_bytes_from_user(
user_space: &Arc<UserSpace>,
user_buf_ptr: usize,
user_buf_len: usize,
) -> Result<Vec<u8>, Error> {
let vm_space = user_space.vm_space();
let mut buffer = vec![0u8; user_buf_len];
vm_space.read_bytes(user_buf_ptr, &mut buffer)?;
Ok(buffer)
}