You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

239 lines
6.4 KiB

use crate::ALLOCATOR;
use alloc::string::String;
#[inline(always)]
fn sys_call(syscall_id: SyscallId, arg0: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> i32 {
let id = syscall_id as usize;
let ret: i32;
unsafe {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
asm!("ecall"
: "={x10}" (ret)
: "{x17}" (id), "{x10}" (arg0), "{x11}" (arg1), "{x12}" (arg2), "{x13}" (arg3), "{x14}" (arg4), "{x15}" (arg5)
: "memory"
: "volatile");
#[cfg(target_arch = "x86")]
asm!("int 0x80"
: "={eax}" (ret)
: "{eax}" (id), "{edx}" (arg0), "{ecx}" (arg1), "{ebx}" (arg2), "{edi}" (arg3), "{esi}" (arg4)
: "memory"
: "intel" "volatile");
#[cfg(target_arch = "x86_64")]
asm!("syscall"
: "={rax}" (ret)
: "{rax}" (id), "{rdi}" (arg0), "{rsi}" (arg1), "{rdx}" (arg2), "{r10}" (arg3), "{r8}" (arg4), "{r9}" (arg5)
: "rcx" "r11" "memory"
: "intel" "volatile");
#[cfg(target_arch = "aarch64")]
asm!("svc 0"
: "={x0}" (ret)
: "{x8}" (id), "{x0}" (arg0), "{x1}" (arg1), "{x2}" (arg2), "{x3}" (arg3), "{x4}" (arg4), "{x5}" (arg5)
: "memory"
: "volatile");
}
ret
}
pub fn enlarge_heap() {
const HEAP_SIZE: usize = 16 * 1024 * 1024;
let addr = sys_mmap(0, HEAP_SIZE, 0x3, 0x22, 0, 0) as usize;
unsafe { ALLOCATOR.lock().init(addr, HEAP_SIZE); }
}
pub fn sys_exit(code: usize) -> ! {
sys_call(SyscallId::Exit, code, 0, 0, 0, 0, 0);
unreachable!()
}
pub fn sys_exec(name: *const u8, argv: *const *const u8, envp: *const *const u8) -> i32 {
sys_call(SyscallId::Exec, name as usize, argv as usize, envp as usize, 0, 0, 0)
}
pub fn sys_write(fd: usize, base: *const u8, len: usize) -> i32 {
sys_call(SyscallId::Write, fd, base as usize, len, 0, 0, 0)
}
pub fn sys_read(fd: usize, base: *mut u8, len: usize) -> i32 {
sys_call(SyscallId::Read, fd, base as usize, len, 0, 0, 0)
}
pub fn sys_open(path: &str, flags: usize) -> i32 {
// UNSAFE: append '\0' to the string
use core::mem::replace;
let end = unsafe { &mut *(path.as_ptr().offset(path.len() as isize) as *mut u8) };
let backup = replace(end, 0);
const AT_FDCWD: isize = -100;
let ret = sys_call(SyscallId::Openat, AT_FDCWD as usize, path.as_ptr() as usize, flags, 0, 0, 0);
*end = backup;
ret
}
pub fn sys_close(fd: usize) -> i32 {
sys_call(SyscallId::Close, fd, 0, 0, 0, 0, 0)
}
pub fn sys_dup2(fd1: usize, fd2: usize) -> i32 {
sys_call(SyscallId::Dup3, fd1, fd2, 0, 0, 0, 0)
}
/// Fork the current process. Return the child's PID.
pub fn sys_vfork() -> i32 {
let mut sp: usize = 0;
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
unsafe {
asm!("mv $0, sp" : "=r" (sp) :: );
}
// TODO: more arch
const CLONE_VFORK: usize = 0x00004000;
const CLONE_VM: usize = 0x00000100;
const SIGCHILD: usize = 17;
sys_call(SyscallId::Clone, CLONE_VFORK | CLONE_VM | SIGCHILD, sp, 0, 0, 0, 0)
}
/// Wait the process exit.
/// Return the PID. Store exit code to `code` if it's not null.
pub fn sys_wait(pid: usize, code: *mut i32) -> i32 {
sys_call(SyscallId::Wait, pid, code as usize, 0, 0, 0, 0)
}
pub fn sys_yield() -> i32 {
sys_call(SyscallId::Yield, 0, 0, 0, 0, 0, 0)
}
/// Kill the process
pub fn sys_kill(pid: usize) -> i32 {
sys_call(SyscallId::Kill, pid, 0, 0, 0, 0, 0)
}
/// Get the current process id
pub fn sys_getpid() -> i32 {
sys_call(SyscallId::GetPid, 0, 0, 0, 0, 0, 0)
}
/// Get the current working directory
pub fn sys_getcwd() -> String {
let buffer = [0u8; 256];
sys_call(SyscallId::GetCwd, buffer.as_ptr() as usize, 256, 0, 0, 0, 0);
String::from_utf8(buffer.to_vec()).unwrap()
}
/// Change the current working directory
pub fn sys_chdir(path: &str) {
let path = String::from(path) + "\0";
sys_call(SyscallId::Chdir, path.as_bytes().as_ptr() as usize, 0, 0, 0, 0, 0);
}
/// Check file accessibility
pub fn sys_access(path: &str) -> i32 {
let path = String::from(path) + "\0";
sys_call(SyscallId::FAccessAt, -100isize as usize, path.as_bytes().as_ptr() as usize, 0, 0, 0, 0)
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct TimeSpec {
sec: u64,
nsec: u64,
}
pub fn sys_sleep(time: usize) -> i32 {
let ts = TimeSpec {
sec: time as u64,
nsec: 0
};
sys_call(SyscallId::Sleep, &ts as *const TimeSpec as usize, 0, 0, 0, 0, 0)
}
pub fn sys_get_time() -> i32 {
sys_call(SyscallId::GetTime, 0, 0, 0, 0, 0, 0)
}
pub fn sys_set_priority(priority: usize) -> i32 {
sys_call(SyscallId::SetPriority, priority, 0, 0, 0, 0, 0)
}
pub fn sys_arch_prctl(code: i32, addr: usize) -> i32 {
sys_call(SyscallId::ArchPrctl, code as usize, addr, 0, 0, 0, 0)
}
pub fn sys_map_pci_device(vendor: usize, product: usize) -> i32 {
sys_call(SyscallId::MapPciDevice, vendor, product, 0, 0, 0, 0)
}
pub fn sys_get_paddr(vaddr: &[u64], paddr: &mut [u64]) -> i32 {
assert_eq!(vaddr.len(), paddr.len());
sys_call(SyscallId::GetPaddr, vaddr.as_ptr() as usize, paddr.as_ptr() as usize, vaddr.len(), 0, 0, 0)
}
pub fn sys_mmap(addr: usize, len: usize, prot: usize, flags: usize, fd: usize, offset: usize) -> i32 {
sys_call(SyscallId::Mmap, addr, len, prot, flags, fd, offset)
}
#[cfg(target_arch = "x86_64")]
#[allow(dead_code)]
enum SyscallId {
Read = 0,
Write = 1,
Close = 3,
Fstat = 4,
Seek = 8,
Mmap = 9,
Munmap = 11,
Yield = 24,
Sleep = 35,
GetPid = 39,
Clone = 56,
Exec = 59,
Exit = 60,
Wait = 61,
Kill = 62,
Fsync = 74,
GetCwd = 79,
Chdir = 80,
GetTime = 96,
SetPriority = 141,
ArchPrctl = 158,
GetDirEntry64 = 217,
Openat = 257,
FAccessAt = 269,
Dup3 = 292,
// custom
MapPciDevice = 999,
GetPaddr = 998,
}
#[cfg(not(target_arch = "x86_64"))]
#[allow(dead_code)]
enum SyscallId {
Read = 63,
Write = 64,
Close = 57,
Fstat = 80,
Seek = 62,
Mmap = 222,
Munmap = 215,
Yield = 124,
Sleep = 101,
GetPid = 172,
Clone = 220,
Exec = 221,
Exit = 93,
Wait = 260,
Kill = 129,
Fsync = 82,
GetCwd = 17,
Chdir = 49,
GetTime = 169,
SetPriority = 140,
ArchPrctl = -4,
GetDirEntry64 = 61,
Openat = 56,
Dup3 = 24,
FAccessAt = 48,
// custom
MapPciDevice = 999,
GetPaddr = 998,
}