refactor: rename syscall to libsys
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
pub const SYS_EX_DEBUG_TRACE: usize = 128;
|
||||
pub const SYS_EX_NANOSLEEP: usize = 129;
|
||||
|
||||
pub const SYS_EXIT: usize = 1;
|
||||
pub const SYS_READ: usize = 2;
|
||||
pub const SYS_WRITE: usize = 3;
|
||||
pub const SYS_OPENAT: usize = 4;
|
||||
pub const SYS_FSTATAT: usize = 5;
|
||||
pub const SYS_CLOSE: usize = 6;
|
||||
pub const SYS_FORK: usize = 7;
|
||||
pub const SYS_EXECVE: usize = 8;
|
||||
pub const SYS_WAITPID: usize = 9;
|
||||
pub const SYS_IOCTL: usize = 10;
|
||||
@@ -0,0 +1,200 @@
|
||||
use crate::abi;
|
||||
use crate::{
|
||||
ioctl::IoctlCmd,
|
||||
stat::{FileMode, OpenFlags, Stat},
|
||||
};
|
||||
use core::mem::size_of;
|
||||
|
||||
// TODO document the syscall ABI
|
||||
|
||||
macro_rules! syscall {
|
||||
($num:expr) => {{
|
||||
let mut res: usize;
|
||||
asm!("svc #0", out("x0") res, in("x8") $num, options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res,
|
||||
in("x8") $num, options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1,
|
||||
in("x8") $num, options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr, $a2:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
in("x8") $num, options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
in("x3") $a3, in("x8") $num, options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
in("x3") $a3, in("x4") $a4, in("x8") $num, options(nostack));
|
||||
res
|
||||
}};
|
||||
}
|
||||
|
||||
/// Integer/size argument
|
||||
macro_rules! argn {
|
||||
($a:expr) => {
|
||||
$a as usize
|
||||
};
|
||||
}
|
||||
/// Pointer/base argument
|
||||
macro_rules! argp {
|
||||
($a:expr) => {
|
||||
$a as usize
|
||||
};
|
||||
}
|
||||
// /// Immutable pointer/base argument
|
||||
// macro_rules! argpi {
|
||||
// ($a:expr) => ($a as *const core::ffi::c_void as usize)
|
||||
// }
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// System call
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_exit(status: i32) -> ! {
|
||||
syscall!(abi::SYS_EXIT, argn!(status));
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// System call
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_close(fd: i32) -> i32 {
|
||||
syscall!(abi::SYS_CLOSE, argn!(fd)) as i32
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// System call
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_ex_nanosleep(ns: u64, rem: &mut [u64; 2]) -> i32 {
|
||||
syscall!(abi::SYS_EX_NANOSLEEP, argn!(ns), argp!(rem.as_mut_ptr())) as i32
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// System call
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_ex_debug_trace(msg: &[u8]) -> usize {
|
||||
syscall!(
|
||||
abi::SYS_EX_DEBUG_TRACE,
|
||||
argp!(msg.as_ptr()),
|
||||
argn!(msg.len())
|
||||
)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// System call
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_openat(at: i32, pathname: &str, mode: FileMode, flags: OpenFlags) -> i32 {
|
||||
syscall!(
|
||||
abi::SYS_OPENAT,
|
||||
argn!(at),
|
||||
argp!(pathname.as_ptr()),
|
||||
argn!(pathname.len()),
|
||||
argn!(mode.bits()),
|
||||
argn!(flags.bits())
|
||||
) as i32
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// System call
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_read(fd: i32, data: &mut [u8]) -> isize {
|
||||
syscall!(
|
||||
abi::SYS_READ,
|
||||
argn!(fd),
|
||||
argp!(data.as_mut_ptr()),
|
||||
argn!(data.len())
|
||||
) as isize
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// System call
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_write(fd: i32, data: &[u8]) -> isize {
|
||||
syscall!(
|
||||
abi::SYS_WRITE,
|
||||
argn!(fd),
|
||||
argp!(data.as_ptr()),
|
||||
argn!(data.len())
|
||||
) as isize
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// System call
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_fstatat(at: i32, pathname: &str, statbuf: &mut Stat, flags: u32) -> i32 {
|
||||
syscall!(
|
||||
abi::SYS_FSTATAT,
|
||||
argn!(at),
|
||||
argp!(pathname.as_ptr()),
|
||||
argn!(pathname.len()),
|
||||
argp!(statbuf as *mut Stat),
|
||||
argn!(flags)
|
||||
) as i32
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// System call
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_fork() -> i32 {
|
||||
syscall!(abi::SYS_FORK) as i32
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// System call
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_execve(pathname: &str) -> i32 {
|
||||
syscall!(
|
||||
abi::SYS_EXECVE,
|
||||
argp!(pathname.as_ptr()),
|
||||
argn!(pathname.len())
|
||||
) as i32
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// System call
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_waitpid(pid: u32, status: &mut i32) -> i32 {
|
||||
syscall!(abi::SYS_WAITPID, argn!(pid), argp!(status as *mut i32)) as i32
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_ioctl(fd: u32, cmd: IoctlCmd, ptr: usize, len: usize) -> isize {
|
||||
syscall!(
|
||||
abi::SYS_IOCTL,
|
||||
argn!(fd),
|
||||
argn!(cmd),
|
||||
argn!(ptr),
|
||||
argn!(len)
|
||||
) as isize
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum Errno {
|
||||
AlreadyExists,
|
||||
BadExecutable,
|
||||
Busy,
|
||||
DeviceError,
|
||||
DoesNotExist,
|
||||
EndOfFile,
|
||||
Interrupt,
|
||||
InvalidArgument,
|
||||
InvalidFile,
|
||||
InvalidOperation,
|
||||
IsADirectory,
|
||||
NotADirectory,
|
||||
NotImplemented,
|
||||
OutOfMemory,
|
||||
ReadOnly,
|
||||
TimedOut,
|
||||
TooManyDescriptors,
|
||||
WouldBlock,
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
use core::convert::TryFrom;
|
||||
use crate::error::Errno;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(u32)]
|
||||
pub enum IoctlCmd {
|
||||
TtySetAttributes = 1,
|
||||
TtyGetAttributes = 2,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for IoctlCmd {
|
||||
type Error = Errno;
|
||||
|
||||
#[inline]
|
||||
fn try_from(u: u32) -> Result<IoctlCmd, Errno> {
|
||||
match u {
|
||||
1 => Ok(Self::TtySetAttributes),
|
||||
2 => Ok(Self::TtyGetAttributes),
|
||||
_ => Err(Errno::InvalidArgument)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#![feature(asm)]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
||||
pub mod abi;
|
||||
pub mod stat;
|
||||
pub mod ioctl;
|
||||
pub mod termios;
|
||||
pub mod error;
|
||||
pub mod path;
|
||||
pub mod mem;
|
||||
pub mod traits;
|
||||
|
||||
#[cfg(feature = "user")]
|
||||
pub mod calls;
|
||||
#[cfg(feature = "user")]
|
||||
pub use calls::*;
|
||||
@@ -0,0 +1,77 @@
|
||||
pub fn read_le32(src: &[u8]) -> u32 {
|
||||
(src[0] as u32) | ((src[1] as u32) << 8) | ((src[2] as u32) << 16) | ((src[3] as u32) << 24)
|
||||
}
|
||||
|
||||
pub fn read_le16(src: &[u8]) -> u16 {
|
||||
(src[0] as u16) | ((src[1] as u16) << 8)
|
||||
}
|
||||
|
||||
/// See memcpy(3p).
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: writes to arbitrary memory locations, performs no pointer
|
||||
/// validation.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn memcpy(dst: *mut u8, src: *mut u8, mut len: usize) -> *mut u8 {
|
||||
while len != 0 {
|
||||
len -= 1;
|
||||
*dst.add(len) = *src.add(len);
|
||||
}
|
||||
dst
|
||||
}
|
||||
|
||||
/// See memcmp(3p).
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: performs reads from arbitrary memory locations, performs no
|
||||
/// pointer validation.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn memcmp(a: *mut u8, b: *mut u8, mut len: usize) -> isize {
|
||||
while len != 0 {
|
||||
len -= 1;
|
||||
if *a.add(len) < *b.add(len) {
|
||||
return -1;
|
||||
}
|
||||
if *a.add(len) > *b.add(len) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// See memmove(3p)
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: writes to arbitrary memory locations, performs no pointer
|
||||
/// validation.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn memmove(dst: *mut u8, src: *mut u8, len: usize) -> *mut u8 {
|
||||
if dst < src {
|
||||
for i in 0..len {
|
||||
*dst.add(i) = *src.add(i);
|
||||
}
|
||||
} else {
|
||||
for i in 0..len {
|
||||
*dst.add(len - (i + 1)) = *src.add(len - (i + 1));
|
||||
}
|
||||
}
|
||||
dst
|
||||
}
|
||||
|
||||
/// See memset(3p)
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: writes to arbitrary memory locations, performs no pointer
|
||||
/// validation.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn memset(buf: *mut u8, val: u8, mut len: usize) -> *mut u8 {
|
||||
while len != 0 {
|
||||
len -= 1;
|
||||
*buf.add(len) = val;
|
||||
}
|
||||
buf
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
pub fn path_component_left(path: &str) -> (&str, &str) {
|
||||
if let Some((left, right)) = path.split_once('/') {
|
||||
(left, right.trim_start_matches('/'))
|
||||
} else {
|
||||
(path, "")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path_component_right(path: &str) -> (&str, &str) {
|
||||
if let Some((left, right)) = path.trim_end_matches('/').rsplit_once('/') {
|
||||
(left.trim_end_matches('/'), right)
|
||||
} else {
|
||||
("", path)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
pub const AT_FDCWD: i32 = -2;
|
||||
pub const AT_EMPTY_PATH: u32 = 1 << 16;
|
||||
|
||||
pub const STDIN_FILENO: i32 = 0;
|
||||
pub const STDOUT_FILENO: i32 = 1;
|
||||
pub const STDERR_FILENO: i32 = 2;
|
||||
|
||||
bitflags! {
|
||||
pub struct OpenFlags: u32 {
|
||||
const O_RDONLY = 1;
|
||||
const O_WRONLY = 2;
|
||||
const O_RDWR = 3;
|
||||
const O_ACCESS = 0x7;
|
||||
|
||||
const O_CREAT = 1 << 4;
|
||||
const O_EXEC = 1 << 5;
|
||||
const O_CLOEXEC = 1 << 6;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct FileMode: u32 {
|
||||
const USER_READ = 1 << 8;
|
||||
const USER_WRITE = 1 << 7;
|
||||
const USER_EXEC = 1 << 6;
|
||||
const GROUP_READ = 1 << 5;
|
||||
const GROUP_WRITE = 1 << 4;
|
||||
const GROUP_EXEC = 1 << 3;
|
||||
const OTHER_READ = 1 << 2;
|
||||
const OTHER_WRITE = 1 << 1;
|
||||
const OTHER_EXEC = 1 << 0;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct Stat {
|
||||
pub mode: u32,
|
||||
pub size: u64,
|
||||
pub blksize: u32,
|
||||
}
|
||||
|
||||
impl FileMode {
|
||||
/// Returns default permission set for directories
|
||||
pub const fn default_dir() -> Self {
|
||||
unsafe { Self::from_bits_unchecked(0o755) }
|
||||
}
|
||||
|
||||
/// Returns default permission set for regular files
|
||||
pub const fn default_reg() -> Self {
|
||||
unsafe { Self::from_bits_unchecked(0o644) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
bitflags! {
|
||||
pub struct TermiosIflag: u32 {
|
||||
/// Translate NL to CR on input
|
||||
const INLCR = 1 << 0;
|
||||
/// Translate CR to NL on input
|
||||
const ICRNL = 1 << 1;
|
||||
}
|
||||
|
||||
pub struct TermiosOflag: u32 {
|
||||
/// Translate NL to CR-NL on output
|
||||
const ONLCR = 1 << 0;
|
||||
}
|
||||
|
||||
pub struct TermiosLflag: u32 {
|
||||
/// Signal processing (INTR, QUIT, SUSP)
|
||||
const ISIG = 1 << 0;
|
||||
/// Canonical mode
|
||||
const ICANON = 1 << 1;
|
||||
/// Echo input characters
|
||||
const ECHO = 1 << 2;
|
||||
/// If ICANON also set, ERASE erases chars, WERASE erases words
|
||||
const ECHOE = 1 << 3;
|
||||
/// If ICANON also set, KILL erases line
|
||||
const ECHOK = 1 << 4;
|
||||
/// If ICANON also set, echo NL even if ECHO is not set
|
||||
const ECHONL = 1 << 5;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TermiosChars {
|
||||
pub eof: u8,
|
||||
pub erase: u8,
|
||||
pub intr: u8,
|
||||
pub kill: u8,
|
||||
pub vlnext: u8,
|
||||
pub werase: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct Termios {
|
||||
pub iflag: TermiosIflag,
|
||||
pub oflag: TermiosOflag,
|
||||
pub lflag: TermiosLflag,
|
||||
pub chars: TermiosChars
|
||||
}
|
||||
|
||||
impl TermiosChars {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
eof: 0x04,
|
||||
erase: 0x7F,
|
||||
intr: 0x03,
|
||||
kill: 0x15,
|
||||
vlnext: 0x16,
|
||||
werase: 0x17,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Termios {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
iflag: TermiosIflag::ICRNL,
|
||||
oflag: TermiosOflag::ONLCR,
|
||||
// TODO prettify this
|
||||
lflag: unsafe {
|
||||
TermiosLflag::from_bits_unchecked(
|
||||
(1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5),
|
||||
)
|
||||
},
|
||||
chars: TermiosChars::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn is_canon(&self) -> bool {
|
||||
self.lflag.contains(TermiosLflag::ICANON)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
use crate::error::Errno;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum SeekDir {
|
||||
Set,
|
||||
End,
|
||||
Current,
|
||||
}
|
||||
|
||||
pub trait Read {
|
||||
fn read(&mut self, data: &mut [u8]) -> Result<usize, Errno>;
|
||||
}
|
||||
|
||||
pub trait Seek {
|
||||
fn seek(&mut self, off: isize, whence: SeekDir) -> Result<usize, Errno>;
|
||||
}
|
||||
|
||||
pub trait Write {
|
||||
fn write(&mut self, data: &[u8]) -> Result<usize, Errno>;
|
||||
}
|
||||
|
||||
pub trait RandomRead {
|
||||
fn pread(&mut self, pos: usize, data: &mut [u8]) -> Result<usize, Errno>;
|
||||
}
|
||||
|
||||
pub trait RandomWrite {
|
||||
fn pwrite(&mut self, pos: usize, data: &[u8]) -> Result<usize, Errno>;
|
||||
}
|
||||
Reference in New Issue
Block a user