Initial commit

This commit is contained in:
Mark Poliakov 2023-07-18 18:05:50 +03:00
commit 8ec1d7fdc2
7 changed files with 535 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
/Cargo.lock

22
Cargo.toml Normal file
View 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
View 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
View 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
View 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
View 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
View 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,
}
}
}