Files
riscv64-kernel/crates/shared/src/syscall.rs
2026-03-17 18:29:00 +01:00

202 lines
5.3 KiB
Rust

use core::{alloc::Layout, time::Duration};
use bffs::path::Path;
use io::SeekFrom;
use crate::fs::File;
#[repr(u64)]
pub enum SysCall {
Read = 0,
Write = 1,
Open = 2,
Close = 3,
Seek = 8,
Alloc = 40,
Dealloc = 41,
Spawn = 58,
ExecVE = 59,
Exit = 60,
NanoSleep = 101,
WriteIntTemp = 998,
WriteTemp = 999,
Unimplemented = 1 << 31,
}
impl From<u64> for SysCall {
fn from(value: u64) -> Self {
match value {
0 => SysCall::Read,
1 => SysCall::Write,
2 => SysCall::Open,
3 => SysCall::Close,
8 => SysCall::Seek,
40 => SysCall::Alloc,
41 => SysCall::Dealloc,
58 => SysCall::Spawn,
59 => SysCall::ExecVE,
60 => SysCall::Exit,
101 => SysCall::NanoSleep,
998 => SysCall::WriteIntTemp,
999 => SysCall::WriteTemp,
_ => SysCall::Unimplemented,
}
}
}
#[allow(clippy::too_many_arguments)]
unsafe fn _syscall(
syscall: SysCall,
mut a1: u64,
mut a2: u64,
mut a3: u64,
mut a4: u64,
mut a5: u64,
mut a6: u64,
mut a7: u64,
) -> (u64, u64, u64, u64, u64, u64, u64, u64) {
let mut a0 = syscall as u64;
unsafe {
core::arch::asm!(
"ecall",
inlateout("a0") a0,
inlateout("a1") a1,
inlateout("a2") a2,
inlateout("a3") a3,
inlateout("a4") a4,
inlateout("a5") a5,
inlateout("a6") a6,
inlateout("a7") a7,
clobber_abi("system")
);
}
(a0, a1, a2, a3, a4, a5, a6, a7)
}
macro_rules! syscall {
($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr, $a7:expr) => {
_syscall($syscall, $a1, $a2, $a3, $a4, $a5, $a6, $a7)
};
($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => {
syscall!($syscall, $a1, $a2, $a3, $a4, $a5, $a6, 0)
};
($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => {
syscall!($syscall, $a1, $a2, $a3, $a4, $a5, 0)
};
($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {
syscall!($syscall, $a1, $a2, $a3, $a4, 0)
};
($syscall:expr, $a1:expr, $a2:expr, $a3:expr) => {
syscall!($syscall, $a1, $a2, $a3, 0)
};
($syscall:expr, $a1:expr, $a2:expr) => {
syscall!($syscall, $a1, $a2, 0)
};
($syscall:expr, $a1:expr) => {
syscall!($syscall, $a1, 0)
};
($syscall:expr) => {
syscall!($syscall, 0)
};
}
pub fn exit() {
unsafe {
syscall!(SysCall::Exit);
}
}
pub fn sleep(duration: Duration) {
unsafe {
let (duration_secs, duration_nanos) = (duration.as_secs(), duration.subsec_nanos() as u64);
syscall!(SysCall::NanoSleep, duration_secs, duration_nanos);
}
}
pub fn write_string_temp(content: &str) {
unsafe {
syscall!(
SysCall::WriteTemp,
content.as_ptr() as u64,
content.len() as u64
);
}
}
pub fn write_int_temp(content: u64) {
unsafe {
syscall!(SysCall::WriteIntTemp, content);
}
}
pub fn alloc(layout: Layout) -> *mut u8 {
unsafe {
let size = layout.size();
let align = layout.align();
let (ptr, ..) = syscall!(SysCall::Alloc, size as u64, align as u64);
ptr as *mut u8
}
}
pub fn dealloc(ptr: *mut u8, layout: core::alloc::Layout) {
unsafe {
let size = layout.size();
let align = layout.align();
syscall!(SysCall::Dealloc, ptr as u64, size as u64, align as u64);
}
}
pub fn open<P: AsRef<Path>>(path: P) -> File {
unsafe {
let path_str = path.as_ref().as_str();
let ptr = path_str.as_ptr();
let size = path_str.len();
let (fd, ..) = syscall!(SysCall::Open, ptr as u64, size as u64);
File::from_raw_fd(fd)
}
}
pub fn close(file_descriptor: u64) {
unsafe {
syscall!(SysCall::Close, file_descriptor);
}
}
pub fn write(file_descriptor: u64, buf: &[u8]) -> u64 {
unsafe {
let ptr = buf.as_ptr();
let size = buf.len();
let (len, ..) = syscall!(SysCall::Write, file_descriptor, ptr as u64, size as u64);
len
}
}
pub fn read(file_descriptor: u64, buf: &mut [u8]) -> u64 {
unsafe {
let ptr = buf.as_ptr();
let size = buf.len();
let (len, ..) = syscall!(SysCall::Read, file_descriptor, ptr as u64, size as u64);
len
}
}
pub fn seek(file_descriptor: u64, seek: SeekFrom) {
unsafe {
let (discriminant, value) = match seek {
SeekFrom::Start(v) => (0, v),
SeekFrom::End(v) => (1, v as u64),
SeekFrom::Current(v) => (2, v as u64),
};
syscall!(SysCall::Seek, file_descriptor, discriminant, value);
}
}
pub fn spawn<P: AsRef<Path>>(path: P) {
unsafe {
let path_str = path.as_ref().as_str();
let ptr = path_str.as_ptr();
let size = path_str.len();
syscall!(SysCall::Spawn, ptr as u64, size as u64);
}
}
pub fn execve<P: AsRef<Path>>(path: P) {
unsafe {
let path_str = path.as_ref().as_str();
let ptr = path_str.as_ptr();
let size = path_str.len();
syscall!(SysCall::ExecVE, ptr as u64, size as u64);
}
}