use alloc::vec::Vec;
use core::hint::spin_loop;
use crate::sys::{
Errno, SYS_WAIT_PID,
calls::{syscall0, syscall1, syscall2, syscall3, syscall5},
constants::{
SYS_DUP2, SYS_EXIT, SYS_GETPID, SYS_MONOTONIC_TIME, SYS_PIPE, SYS_SLEEP_MS, SYS_SPAWN,
},
errno,
};
pub fn sys_getpid() -> u64 {
unsafe { syscall0(SYS_GETPID) }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WaitPidStatus {
StillRunning,
Exited(i32),
}
pub fn sys_waitpid(pid: u64, block: bool) -> Result<WaitPidStatus, Errno> {
let mut status = 0i32;
let result = unsafe {
syscall3(
SYS_WAIT_PID,
pid,
block as u64,
(&mut status as *mut i32) as u64,
)
};
if result == u64::MAX {
return Err(errno());
}
if result == 0 {
Ok(WaitPidStatus::StillRunning)
} else {
Ok(WaitPidStatus::Exited(status))
}
}
pub fn sys_exit(code: i32) -> ! {
unsafe { syscall1(SYS_EXIT, code as u64) };
loop {
spin_loop();
}
}
pub fn sleep_ms(ms: u64) -> Result<(), Errno> {
let result = unsafe { syscall1(SYS_SLEEP_MS, ms) };
if result == u64::MAX {
Err(errno())
} else {
Ok(())
}
}
pub fn monotonic_time_ns() -> Result<u64, Errno> {
let result = unsafe { syscall0(SYS_MONOTONIC_TIME) };
if result == u64::MAX {
Err(errno())
} else {
Ok(result)
}
}
pub fn pipe() -> Option<(u64, u64)> {
let mut pipefd = [0u64; 2];
let result = unsafe { syscall1(SYS_PIPE, pipefd.as_mut_ptr() as u64) };
if result == 0 {
Some((pipefd[0], pipefd[1]))
} else {
None
}
}
pub fn dup2(oldfd: u64, newfd: u64) -> u64 {
unsafe { syscall2(SYS_DUP2, oldfd, newfd) }
}
pub fn spawn(path: &str, args: &[&str], stdin_fd: u64, stdout_fd: u64, stderr_fd: u64) -> u64 {
let mut path_buf = Vec::with_capacity(path.len() + 1);
path_buf.extend_from_slice(path.as_bytes());
path_buf.push(0);
let mut argv_storage: Vec<Vec<u8>> = Vec::with_capacity(args.len());
let mut argv_ptrs: Vec<*const u8> = Vec::with_capacity(args.len() + 1);
for &arg in args {
let mut buf = Vec::with_capacity(arg.len() + 1);
buf.extend_from_slice(arg.as_bytes());
buf.push(0);
argv_ptrs.push(buf.as_ptr());
argv_storage.push(buf);
}
argv_ptrs.push(core::ptr::null());
let argv_ptr = if argv_ptrs.is_empty() {
core::ptr::null()
} else {
argv_ptrs.as_ptr()
};
unsafe {
syscall5(
SYS_SPAWN,
path_buf.as_ptr() as u64,
argv_ptr as u64,
stdin_fd,
stdout_fd,
stderr_fd,
)
}
}
unsafe extern "C" {
fn main(argc: isize, argv: *const *const u8) -> i32;
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn _start(argc: isize, argv: *const *const u8) -> ! {
crate::allocator::ALLOCATOR.lock();
let code = unsafe { main(argc, argv) };
sys_exit(code);
}
#[panic_handler]
pub fn rust_panic(info: &core::panic::PanicInfo) -> ! {
crate::println!("{info}");
sys_exit(-1);
}