moros 0.12.0

MOROS: Obscure Rust Operating System
Documentation
pub mod number;
pub mod service;

use crate::api::process::ExitCode;
use crate::sys;
use crate::sys::fs::FileInfo;

use core::arch::asm;
use core::convert::TryInto;
use smoltcp::wire::IpAddress;
use smoltcp::wire::Ipv4Address;

fn utf8_from_raw_parts(ptr: *mut u8, len: usize) -> &'static str {
    unsafe {
        let slice = core::slice::from_raw_parts(ptr, len);
        core::str::from_utf8_unchecked(slice)
    }
}

pub fn dispatcher(
    n: usize,
    arg1: usize,
    arg2: usize,
    arg3: usize,
    arg4: usize
) -> usize {
    match n {
        number::EXIT => service::exit(ExitCode::from(arg1)) as usize,
        number::SLEEP => {
            service::sleep(f64::from_bits(arg1 as u64));
            0
        }
        number::DELETE => {
            let ptr = sys::process::ptr_from_addr(arg1 as u64);
            let len = arg2;
            let path = utf8_from_raw_parts(ptr, len);
            service::delete(path) as usize
        }
        number::INFO => {
            let ptr = sys::process::ptr_from_addr(arg1 as u64);
            let len = arg2;
            let path = utf8_from_raw_parts(ptr, len);
            let info = unsafe { &mut *(arg3 as *mut FileInfo) };
            service::info(path, info) as usize
        }
        number::KIND => {
            let handle = arg1;
            service::kind(handle) as usize
        }
        number::OPEN => {
            let ptr = sys::process::ptr_from_addr(arg1 as u64);
            let len = arg2;
            let path = utf8_from_raw_parts(ptr, len);
            let flags = arg3 as u8;
            service::open(path, flags) as usize
        }
        number::READ => {
            let handle = arg1;
            let ptr = sys::process::ptr_from_addr(arg2 as u64);
            let len = arg3;
            let buf = unsafe {
                core::slice::from_raw_parts_mut(ptr, len)
            };
            service::read(handle, buf) as usize
        }
        number::WRITE => {
            let handle = arg1;
            let ptr = sys::process::ptr_from_addr(arg2 as u64);
            let len = arg3;
            let buf = unsafe {
                core::slice::from_raw_parts_mut(ptr, len) // TODO: Remove mut
            };
            service::write(handle, buf) as usize
        }
        number::CLOSE => {
            let handle = arg1;
            service::close(handle);
            0
        }
        number::DUP => {
            let old_handle = arg1;
            let new_handle = arg2;
            service::dup(old_handle, new_handle) as usize
        }
        number::SPAWN => {
            let path_ptr = sys::process::ptr_from_addr(arg1 as u64);
            let path_len = arg2;
            let path = utf8_from_raw_parts(path_ptr, path_len);
            let args_ptr = arg3;
            let args_len = arg4;
            service::spawn(path, args_ptr, args_len) as usize
        }
        number::STOP => {
            let code = arg1;
            service::stop(code)
        }
        number::POLL => {
            let ptr = sys::process::ptr_from_addr(arg1 as u64) as *const _;
            let len = arg2;
            let list = unsafe { core::slice::from_raw_parts(ptr, len) };
            service::poll(list) as usize
        }
        number::CONNECT => {
            let handle = arg1;
            let ptr = sys::process::ptr_from_addr(arg2 as u64);
            let len = arg3;
            let buf = unsafe { core::slice::from_raw_parts(ptr, len) };
            if let Ok(buf) = buf.try_into() {
                let addr = IpAddress::from(Ipv4Address::from_octets(buf));
                let port = arg4 as u16;
                service::connect(handle, addr, port) as usize
            } else {
                -1 as isize as usize
            }
        }
        number::LISTEN => {
            let handle = arg1;
            let port = arg2 as u16;
            service::listen(handle, port) as usize
        }
        number::ACCEPT => {
            let handle = arg1;
            let ptr = sys::process::ptr_from_addr(arg2 as u64);
            let len = arg3;
            let buf = unsafe { core::slice::from_raw_parts_mut(ptr, len) };
            if let Ok(IpAddress::Ipv4(addr)) = service::accept(handle) {
                buf[0..len].clone_from_slice(&addr.octets());
                0
            } else {
                -1 as isize as usize
            }
        }
        number::ALLOC => {
            let size = arg1;
            let align = arg2;
            service::alloc(size, align) as usize
        }
        number::FREE => {
            let ptr = arg1 as *mut u8;
            let size = arg2;
            let align = arg3;
            unsafe {
                service::free(ptr, size, align);
            }
            0
        }
        _ => {
            unimplemented!();
        }
    }
}

#[doc(hidden)]
pub unsafe fn syscall0(n: usize) -> usize {
    let res: usize;
    asm!(
        "int 0x80", in("rax") n,
        lateout("rax") res
    );
    res
}

#[doc(hidden)]
pub unsafe fn syscall1(n: usize, arg1: usize) -> usize {
    let res: usize;
    asm!(
        "int 0x80", in("rax") n,
        in("rdi") arg1,
        lateout("rax") res
    );
    res
}

#[doc(hidden)]
pub unsafe fn syscall2(n: usize, arg1: usize, arg2: usize) -> usize {
    let res: usize;
    asm!(
        "int 0x80", in("rax") n,
        in("rdi") arg1, in("rsi") arg2,
        lateout("rax") res
    );
    res
}

#[doc(hidden)]
pub unsafe fn syscall3(
    n: usize,
    arg1: usize,
    arg2: usize,
    arg3: usize
) -> usize {
    let res: usize;
    asm!(
        "int 0x80", in("rax") n,
        in("rdi") arg1, in("rsi") arg2, in("rdx") arg3,
        lateout("rax") res
    );
    res
}

#[doc(hidden)]
pub unsafe fn syscall4(
    n: usize,
    arg1: usize,
    arg2: usize,
    arg3: usize,
    arg4: usize
) -> usize {
    let res: usize;
    asm!(
        "int 0x80", in("rax") n,
        in("rdi") arg1, in("rsi") arg2, in("rdx") arg3, in("r8") arg4,
        lateout("rax") res
    );
    res
}

#[macro_export]
macro_rules! syscall {
    ($n:expr) => {
        $crate::sys::syscall::syscall0($n as usize)
    };
    ($n:expr, $a1:expr) => {
        $crate::sys::syscall::syscall1($n as usize, $a1 as usize)
    };
    ($n:expr, $a1:expr, $a2:expr) => {
        $crate::sys::syscall::syscall2($n as usize, $a1 as usize, $a2 as usize)
    };
    ($n:expr, $a1:expr, $a2:expr, $a3:expr) => {
        $crate::sys::syscall::syscall3(
            $n as usize,
            $a1 as usize,
            $a2 as usize,
            $a3 as usize,
        )
    };
    ($n:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {
        $crate::sys::syscall::syscall4(
            $n as usize,
            $a1 as usize,
            $a2 as usize,
            $a3 as usize,
            $a4 as usize,
        )
    };
}