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 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>(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>(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>(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); } }