Initial commit
This commit is contained in:
commit
8ec1d7fdc2
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
/Cargo.lock
|
22
Cargo.toml
Normal file
22
Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "yggdrasil-rt"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
|
||||
|
||||
core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" }
|
||||
alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" }
|
||||
compiler_builtins = { version = "0.1", optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
rustc-dep-of-std = [
|
||||
"core",
|
||||
"alloc",
|
||||
"compiler_builtins/rustc-dep-of-std",
|
||||
"yggdrasil-abi/rustc-dep-of-std"
|
||||
]
|
59
src/alloc.rs
Normal file
59
src/alloc.rs
Normal file
@ -0,0 +1,59 @@
|
||||
//! Application heap management functions
|
||||
use core::alloc::Layout;
|
||||
|
||||
use crate::sys;
|
||||
|
||||
/// Allocates memory for `layout`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe.
|
||||
pub unsafe fn malloc(layout: Layout) -> *mut u8 {
|
||||
if layout.size() > 0x1000 || layout.align() > 0x1000 {
|
||||
sys::debug_trace("rt::malloc() invalid align/size");
|
||||
loop {}
|
||||
}
|
||||
let page = sys::map_memory(None, 0x1000).unwrap();
|
||||
|
||||
page as *mut u8
|
||||
}
|
||||
|
||||
/// Allocates memory for `layout` and fills it with zeroes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe.
|
||||
pub unsafe fn malloc_zeroed(_layout: Layout) -> *mut u8 {
|
||||
sys::debug_trace("rt::malloc_zeroed()");
|
||||
loop {}
|
||||
}
|
||||
|
||||
/// Frees the memory pointed to by `ptr`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe.
|
||||
pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
|
||||
if layout.size() > 0x1000 || layout.align() > 0x1000 {
|
||||
sys::debug_trace("rt::dealloc() invalid align/size");
|
||||
loop {}
|
||||
}
|
||||
sys::debug_trace("rt::dealloc()");
|
||||
|
||||
sys::unmap_memory(ptr as usize, (layout.size() + 0xFFF) & !0xFFF).ok();
|
||||
}
|
||||
|
||||
/// Allocates a new storage for `new_size` from a previously allocated `ptr`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe.
|
||||
pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
sys::debug_trace("rt::realloc()");
|
||||
if layout.align() > 0x1000 || new_size > 0x1000 || layout.size() > 0x1000 {
|
||||
sys::debug_trace("rt::realloc() invalid align/size/new_size");
|
||||
loop {}
|
||||
}
|
||||
|
||||
ptr
|
||||
}
|
53
src/lib.rs
Normal file
53
src/lib.rs
Normal file
@ -0,0 +1,53 @@
|
||||
//! Yggdrasil OS application runtime
|
||||
#![no_std]
|
||||
#![deny(missing_docs)]
|
||||
#![allow(nonstandard_style)]
|
||||
|
||||
use core::ffi::{c_char, c_void};
|
||||
|
||||
pub use abi::error::Error;
|
||||
pub use abi::io::{OpenFlags, RawFd};
|
||||
pub use abi::path;
|
||||
pub mod alloc;
|
||||
pub mod netc;
|
||||
pub mod sys;
|
||||
pub mod time;
|
||||
|
||||
/// Type alias for a raw file descriptor
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn memcmp(_p0: *const c_void, _p1: *const c_void, _len: usize) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn memcpy(p0: *mut c_void, p1: *const c_void, len: usize) -> *mut c_void {
|
||||
let mut offset = 0;
|
||||
while offset < len {
|
||||
(p0 as *mut u8)
|
||||
.add(offset)
|
||||
.write((p1 as *mut u8).add(offset).read());
|
||||
offset += 1;
|
||||
}
|
||||
p0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn memmove(_dst: *mut c_void, _src: *const c_void, _len: usize) -> *mut c_void {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn memset(dst: *mut c_void, val: i32, len: usize) -> *mut c_void {
|
||||
let mut offset = 0;
|
||||
while offset < len {
|
||||
(dst as *mut u8).add(offset).write(val as u8);
|
||||
offset += 1;
|
||||
}
|
||||
dst
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn strlen(_s: *mut c_char) -> usize {
|
||||
todo!()
|
||||
}
|
177
src/netc.rs
Normal file
177
src/netc.rs
Normal file
@ -0,0 +1,177 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use core::ffi::{c_char, c_void};
|
||||
|
||||
use abi::io::RawFd;
|
||||
|
||||
pub type socklen_t = u32;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct in_addr {
|
||||
pub s_addr: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct in6_addr {
|
||||
pub s6_addr: [u8; 16],
|
||||
}
|
||||
|
||||
pub type sa_family_t = u16;
|
||||
pub type in_port_t = u16;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct sockaddr {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct sockaddr_in {
|
||||
pub sin_family: sa_family_t,
|
||||
pub sin_port: in_port_t,
|
||||
pub sin_addr: in_addr,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct sockaddr_in6 {
|
||||
pub sin6_family: sa_family_t,
|
||||
pub sin6_port: in_port_t,
|
||||
pub sin6_flowinfo: u32,
|
||||
pub sin6_addr: in6_addr,
|
||||
pub sin6_scope_id: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ip_mreq {
|
||||
pub imr_multiaddr: in_addr,
|
||||
pub imr_interface: in_addr,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ipv6_mreq {
|
||||
pub ipv6mr_multiaddr: in6_addr,
|
||||
pub ipv6mr_interface: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct addrinfo {
|
||||
pub ai_flags: i32,
|
||||
pub ai_family: i32,
|
||||
pub ai_socktype: i32,
|
||||
pub ai_protocol: i32,
|
||||
pub ai_addrlen: socklen_t,
|
||||
pub ai_addr: *mut sockaddr,
|
||||
pub ai_canonname: *mut c_char,
|
||||
pub ai_next: *mut addrinfo,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct sockaddr_storage {
|
||||
pub ss_family: sa_family_t,
|
||||
}
|
||||
|
||||
pub const IP_ADD_MEMBERSHIP: i32 = 1;
|
||||
pub const IP_DROP_MEMBERSHIP: i32 = 2;
|
||||
pub const IP_MULTICAST_LOOP: i32 = 3;
|
||||
pub const IP_MULTICAST_TTL: i32 = 4;
|
||||
|
||||
pub const IPV6_MULTICAST_LOOP: i32 = 101;
|
||||
pub const IPV6_V6ONLY: i32 = 102;
|
||||
pub const IPV6_DROP_MEMBERSHIP: i32 = 103;
|
||||
pub const IPV6_ADD_MEMBERSHIP: i32 = 104;
|
||||
|
||||
pub const SO_BROADCAST: i32 = 201;
|
||||
pub const SO_SNDTIMEO: i32 = 202;
|
||||
pub const SO_RCVTIMEO: i32 = 203;
|
||||
pub const SO_REUSEADDR: i32 = 204;
|
||||
|
||||
pub const SOL_SOCKET: i32 = 205;
|
||||
|
||||
pub const SOCK_DGRAM: i32 = 301;
|
||||
pub const SOCK_STREAM: i32 = 302;
|
||||
|
||||
pub const IPPROTO_IP: i32 = 401;
|
||||
pub const IPPROTO_IPV6: i32 = 402;
|
||||
|
||||
pub const AF_INET: i32 = 501;
|
||||
pub const AF_INET6: i32 = 502;
|
||||
|
||||
pub const IP_TTL: i32 = 601;
|
||||
|
||||
pub unsafe fn send(_fd: RawFd, _buf: *const c_void, _len: usize, _opt: i32) -> isize {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub unsafe fn sendto(
|
||||
_fd: RawFd,
|
||||
_buf: *const c_void,
|
||||
_len: usize,
|
||||
_opt: i32,
|
||||
_addr: *const sockaddr,
|
||||
_dst_len: socklen_t,
|
||||
) -> isize {
|
||||
todo!();
|
||||
}
|
||||
|
||||
pub unsafe fn getsockname(
|
||||
_fd: RawFd,
|
||||
_address: *mut sockaddr,
|
||||
_address_len: *mut socklen_t,
|
||||
) -> i32 {
|
||||
todo!();
|
||||
}
|
||||
|
||||
pub unsafe fn getpeername(
|
||||
_fd: RawFd,
|
||||
_address: *mut sockaddr,
|
||||
_address_len: *mut socklen_t,
|
||||
) -> i32 {
|
||||
todo!();
|
||||
}
|
||||
|
||||
pub unsafe fn connect(_fd: RawFd, _name: *const sockaddr, _namelen: socklen_t) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub unsafe fn bind(_fd: RawFd, _name: *const sockaddr, _namelen: socklen_t) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub unsafe fn listen(_fd: RawFd, _backlog: i32) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub unsafe fn getsockopt(
|
||||
_fd: RawFd,
|
||||
_level: i32,
|
||||
_opt: i32,
|
||||
_opt_val: *mut c_void,
|
||||
_opt_len: *mut socklen_t,
|
||||
) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub unsafe fn setsockopt(
|
||||
_fd: RawFd,
|
||||
_level: i32,
|
||||
_opt: i32,
|
||||
_opt_val: *const c_void,
|
||||
_opt_len: socklen_t,
|
||||
) -> i32 {
|
||||
todo!();
|
||||
}
|
||||
|
||||
pub unsafe fn getaddrinfo(
|
||||
_node: *const c_char,
|
||||
_service: *const c_char,
|
||||
_hints: *const addrinfo,
|
||||
_res: *mut *mut addrinfo,
|
||||
) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub unsafe fn freeaddrinfo(_node: *mut addrinfo) {
|
||||
todo!()
|
||||
}
|
201
src/sys.rs
Normal file
201
src/sys.rs
Normal file
@ -0,0 +1,201 @@
|
||||
//! System call implementations
|
||||
use core::time::Duration;
|
||||
|
||||
use abi::{
|
||||
error::{Error, FromSyscallResult},
|
||||
io::{OpenFlags, RawFd},
|
||||
SyscallFunction,
|
||||
};
|
||||
|
||||
macro_rules! syscall {
|
||||
($num:expr) => {{
|
||||
let mut res: usize;
|
||||
core::arch::asm!("svc #0", out("x0") res, in("x8") $num.repr(), options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
core::arch::asm!("svc #0",
|
||||
inout("x0") res,
|
||||
in("x8") usize::from($num), options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
core::arch::asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1,
|
||||
in("x8") usize::from($num), options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr, $a2:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
core::arch::asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
in("x8") usize::from($num), options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
core::arch::asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
in("x3") $a3, in("x8") usize::from($num), options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
core::arch::asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
in("x3") $a3, in("x4") $a4, in("x8") usize::from($num), options(nostack));
|
||||
res
|
||||
}};
|
||||
}
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! argn {
|
||||
($a:expr) => {
|
||||
$a as usize
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! argp {
|
||||
($a:expr) => {
|
||||
$a as usize
|
||||
};
|
||||
}
|
||||
|
||||
/// [SyscallFunction::DebugTrace] call.
|
||||
///
|
||||
/// * msg: message to print to the debug trace log.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: direct system call.
|
||||
pub unsafe fn debug_trace(msg: &str) {
|
||||
syscall!(
|
||||
SyscallFunction::DebugTrace,
|
||||
argp!(msg.as_ptr()),
|
||||
argn!(msg.len())
|
||||
);
|
||||
}
|
||||
|
||||
/// [SyscallFunction::MapMemory] call.
|
||||
///
|
||||
/// * virt: hint to the memory manager. Mapping is not guaranteed to be placed at the specific
|
||||
/// address, but the kernel will at least try.
|
||||
/// * len: size of the region to map in bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: direct system call.
|
||||
pub unsafe fn map_memory(virt: Option<usize>, len: usize) -> Result<usize, Error> {
|
||||
let virt = virt.unwrap_or(0);
|
||||
usize::from_syscall_result(syscall!(
|
||||
SyscallFunction::MapMemory,
|
||||
argn!(virt),
|
||||
argn!(len)
|
||||
))
|
||||
}
|
||||
|
||||
/// [SyscallFunction::UnmapMemory] call.
|
||||
///
|
||||
/// * virt: address of the region to unmap.
|
||||
/// * len: length of the region to unmap.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: direct system call.
|
||||
pub unsafe fn unmap_memory(virt: usize, len: usize) -> Result<(), Error> {
|
||||
<()>::from_syscall_result(syscall!(
|
||||
SyscallFunction::UnmapMemory,
|
||||
argn!(virt),
|
||||
argn!(len)
|
||||
))
|
||||
}
|
||||
|
||||
/// [SyscallFunction::Nanosleep] call.
|
||||
///
|
||||
/// * duration: amount of time to sleep.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: direct system call.
|
||||
pub unsafe fn nanosleep(duration: Duration) {
|
||||
let seconds = duration.as_secs();
|
||||
let nanos = duration.subsec_nanos();
|
||||
syscall!(SyscallFunction::Nanosleep, argn!(seconds), argn!(nanos));
|
||||
}
|
||||
|
||||
/// [SyscallFunction::Exit] call.
|
||||
///
|
||||
/// * code: process termination status code.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: direct system call.
|
||||
pub unsafe fn exit(code: i32) -> ! {
|
||||
syscall!(SyscallFunction::Exit, argn!(code));
|
||||
panic!();
|
||||
}
|
||||
|
||||
/// [SyscallFunction::Write] call.
|
||||
///
|
||||
/// * fd: file descriptor to write to.
|
||||
/// * data: data to write to the file.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: direct system call.
|
||||
pub unsafe fn write(fd: RawFd, data: &[u8]) -> Result<usize, Error> {
|
||||
usize::from_syscall_result(syscall!(
|
||||
SyscallFunction::Write,
|
||||
argn!(fd.0),
|
||||
argp!(data.as_ptr()),
|
||||
argn!(data.len())
|
||||
))
|
||||
}
|
||||
|
||||
/// [SyscallFunction::Read] call.
|
||||
///
|
||||
/// * fd: file descriptor to read from.
|
||||
/// * data: buffer to store the read data.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: direct system call.
|
||||
pub unsafe fn read(fd: RawFd, data: &mut [u8]) -> Result<usize, Error> {
|
||||
usize::from_syscall_result(syscall!(
|
||||
SyscallFunction::Read,
|
||||
argn!(fd.0),
|
||||
argp!(data.as_ptr()),
|
||||
argn!(data.len())
|
||||
))
|
||||
}
|
||||
|
||||
/// [SyscallFunction::Open] call.
|
||||
///
|
||||
/// * path: path of the file to open.
|
||||
/// * opts: flags and mode to open the file with.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: direct system call.
|
||||
pub unsafe fn open(path: &str, opts: OpenFlags) -> Result<RawFd, Error> {
|
||||
RawFd::from_syscall_result(syscall!(
|
||||
SyscallFunction::Open,
|
||||
argp!(path.as_ptr()),
|
||||
argn!(path.len()),
|
||||
argn!(opts.0)
|
||||
))
|
||||
}
|
||||
|
||||
/// [SyscallFunction::Close] call.
|
||||
///
|
||||
/// * fd: file descriptor to close.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: direct system call.
|
||||
pub unsafe fn close(fd: RawFd) -> Result<(), Error> {
|
||||
<()>::from_syscall_result(syscall!(SyscallFunction::Close, argn!(fd.0)))
|
||||
}
|
21
src/time.rs
Normal file
21
src/time.rs
Normal file
@ -0,0 +1,21 @@
|
||||
//! System time management
|
||||
|
||||
/// System time representation
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct Timespec {
|
||||
/// Seconds component
|
||||
pub seconds: u64,
|
||||
/// Nanoseconds component
|
||||
pub nanoseconds: u64,
|
||||
}
|
||||
|
||||
impl Timespec {
|
||||
/// Constructs a [Timespec] with all components set to zero
|
||||
pub const fn zero() -> Self {
|
||||
Self {
|
||||
seconds: 0,
|
||||
nanoseconds: 0,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user