diff --git a/hermit-builtins/Cargo.lock b/hermit-builtins/Cargo.lock index 9f9920ab10..035d8323fd 100644 --- a/hermit-builtins/Cargo.lock +++ b/hermit-builtins/Cargo.lock @@ -2,11 +2,26 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "allocator-api2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c880a97d28a3681c0267bd29cff89621202715b065127cd445fa0f0fe0aa2880" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + [[package]] name = "hermit-builtins" version = "0.0.0" dependencies = [ + "hermit-abi", "libm", + "spinning_top", + "talc", ] [[package]] @@ -14,3 +29,37 @@ name = "libm" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "spinning_top" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +dependencies = [ + "lock_api", +] + +[[package]] +name = "talc" +version = "5.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3081e3f3ad542dc4cd0ae720f752598f8880fd364dc2d031132e3509f673aa23" +dependencies = [ + "allocator-api2", + "lock_api", +] diff --git a/hermit-builtins/Cargo.toml b/hermit-builtins/Cargo.toml index 20ca9e6d56..dc0c07ac40 100644 --- a/hermit-builtins/Cargo.toml +++ b/hermit-builtins/Cargo.toml @@ -5,10 +5,23 @@ edition = "2024" [dependencies] libm = "0.2" +#! ## MASOS dependencies +hermit-abi = { version = "0.5", optional = true } +spinning_top = { version = "0.3", optional = true } +talc = { version = "5", default-features = false, optional = true } + [lib] crate-type = ["staticlib"] harness = false +[features] +default = [] +masos = [ + "dep:hermit-abi", + "dep:spinning_top", + "dep:talc", +] + [profile.dist] inherits = "release" lto = "thin" diff --git a/hermit-builtins/src/lib.rs b/hermit-builtins/src/lib.rs index 3d9a02571a..49506fcb09 100644 --- a/hermit-builtins/src/lib.rs +++ b/hermit-builtins/src/lib.rs @@ -1,7 +1,14 @@ #![no_std] #![no_main] #![feature(linkage)] +#![cfg_attr(feature = "masos", feature(macro_metavar_expr_concat))] +#![cfg_attr(feature = "masos", feature(thread_local))] +#[cfg(feature = "masos")] +extern crate alloc; + +#[cfg(feature = "masos")] +mod masos; pub mod math; #[panic_handler] diff --git a/hermit-builtins/src/masos/alloc.rs b/hermit-builtins/src/masos/alloc.rs new file mode 100644 index 0000000000..eb1077c9a0 --- /dev/null +++ b/hermit-builtins/src/masos/alloc.rs @@ -0,0 +1,65 @@ +use alloc::alloc::{alloc, alloc_zeroed, dealloc, realloc}; +use core::alloc::Layout; +use core::mem::MaybeUninit; + +use spinning_top::RawSpinlock; +use talc::TalcLock; +use talc::source::Claim; + +#[global_allocator] +static TALC: TalcLock = TalcLock::new(unsafe { + /// 16 MiB of statically allocated Heap memory. + #[repr(C, align(0x1000))] + struct Heap([MaybeUninit; 0x100_0000]); + + static mut HEAP: Heap = Heap([MaybeUninit::uninit(); _]); + + let base = (&raw mut HEAP).cast::(); + let size = size_of::(); + Claim::new(base, size) +}); + +#[unsafe(no_mangle)] +unsafe extern "C" fn sys_alloc(size: usize, align: usize) -> *mut u8 { + unsafe { alloc(layout_from_size_align(size, align)) } +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn sys_dealloc(ptr: *mut u8, size: usize, align: usize) { + unsafe { dealloc(ptr, layout_from_size_align(size, align)) } +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn sys_alloc_zeroed(size: usize, align: usize) -> *mut u8 { + unsafe { alloc_zeroed(layout_from_size_align(size, align)) } +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn sys_realloc( + ptr: *mut u8, + size: usize, + align: usize, + new_size: usize, +) -> *mut u8 { + unsafe { realloc(ptr, layout_from_size_align(size, align), new_size) } +} + +/// Deprecated +#[unsafe(no_mangle)] +unsafe extern "C" fn sys_malloc(size: usize, align: usize) -> *mut u8 { + unsafe { sys_alloc(size, align) } +} + +/// Deprecated +#[unsafe(no_mangle)] +unsafe extern "C" fn sys_free(ptr: *mut u8, size: usize, align: usize) { + unsafe { sys_dealloc(ptr, size, align) } +} + +unsafe fn layout_from_size_align(size: usize, align: usize) -> Layout { + if cfg!(debug_assertions) { + Layout::from_size_align(size, align).unwrap() + } else { + unsafe { Layout::from_size_align_unchecked(size, align) } + } +} diff --git a/hermit-builtins/src/masos/arch/aarch64.rs b/hermit-builtins/src/masos/arch/aarch64.rs new file mode 100644 index 0000000000..50b2c7c925 --- /dev/null +++ b/hermit-builtins/src/masos/arch/aarch64.rs @@ -0,0 +1,122 @@ +use core::arch::asm; + +#[inline] +pub(crate) unsafe fn syscall0(nr: usize) -> usize { + let r0; + unsafe { + asm!( + "svc 0", + in("x8") nr, + lateout("x0") r0, + options(preserves_flags), + ); + } + r0 +} + +#[inline] +pub(crate) unsafe fn syscall1(nr: usize, a0: usize) -> usize { + let r0; + unsafe { + asm!( + "svc 0", + in("x8") nr, + inlateout("x0") a0 => r0, + options(preserves_flags), + ); + } + r0 +} + +#[inline] +pub(crate) unsafe fn syscall2(nr: usize, a0: usize, a1: usize) -> usize { + let r0; + unsafe { + asm!( + "svc 0", + in("x8") nr, + inlateout("x0") a0 => r0, + in("x1") a1, + options(preserves_flags), + ); + } + r0 +} + +#[inline] +pub(crate) unsafe fn syscall3(nr: usize, a0: usize, a1: usize, a2: usize) -> usize { + let r0; + unsafe { + asm!( + "svc 0", + in("x8") nr, + inlateout("x0") a0 => r0, + in("x1") a1, + in("x2") a2, + options(preserves_flags), + ); + } + r0 +} + +#[inline] +pub(crate) unsafe fn syscall4(nr: usize, a0: usize, a1: usize, a2: usize, a3: usize) -> usize { + let r0; + unsafe { + asm!( + "svc 0", + in("x8") nr, + inlateout("x0") a0 => r0, + in("x1") a1, + in("x2") a2, + in("x3") a3, + options(preserves_flags), + ); + } + r0 +} + +#[inline] +pub(crate) unsafe fn syscall5(nr: usize, a0: usize, a1: usize, a2: usize, a3: usize, a4: usize) -> usize { + let r0; + unsafe { + asm!( + "svc 0", + in("x8") nr, + inlateout("x0") a0 => r0, + in("x1") a1, + in("x2") a2, + in("x3") a3, + in("x4") a4, + options(preserves_flags), + ); + } + r0 +} + +#[inline] +pub(crate) unsafe fn syscall6( + nr: usize, + a0: usize, + a1: usize, + a2: usize, + a3: usize, + a4: usize, + a5: usize, +) -> usize { + let r0; + unsafe { + asm!( + "svc 0", + in("x8") nr, + inlateout("x0") a0 => r0, + in("x1") a1, + in("x2") a2, + in("x3") a3, + in("x4") a4, + in("x5") a5, + options(preserves_flags), + ); + } + r0 +} diff --git a/hermit-builtins/src/masos/arch/mod.rs b/hermit-builtins/src/masos/arch/mod.rs new file mode 100644 index 0000000000..48a7ea1e38 --- /dev/null +++ b/hermit-builtins/src/masos/arch/mod.rs @@ -0,0 +1,62 @@ +cfg_select! { + target_arch = "aarch64" => { + mod aarch64; + pub(crate) use aarch64::*; + } + target_arch = "x86_64" => { + mod x86_64; + pub(crate) use x86_64::*; + } + _ => {} +} + +macro_rules! syscall { + ($nr:expr $(,)?) => { + $crate::masos::arch::syscall0($nr as usize) + }; + + ($nr:expr, $a0:expr $(,)?) => { + $crate::masos::arch::syscall1($nr as usize, $a0 as usize) + }; + + ($nr:expr, $a0:expr, $a1:expr $(,)?) => { + $crate::masos::arch::syscall2($nr as usize, $a0 as usize, $a1 as usize) + }; + + ($nr:expr, $a0:expr, $a1:expr, $a2:expr $(,)?) => { + $crate::masos::arch::syscall3($nr as usize, $a0 as usize, $a1 as usize, $a2 as usize) + }; + + ($nr:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr $(,)?) => { + $crate::masos::arch::syscall4( + $nr as usize, + $a0 as usize, + $a1 as usize, + $a2 as usize, + $a3 as usize, + ) + }; + + ($nr:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr $(,)?) => { + $crate::masos::arch::syscall5( + $nr as usize, + $a0 as usize, + $a1 as usize, + $a2 as usize, + $a3 as usize, + $a4 as usize, + ) + }; + + ($nr:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr $(,)?) => { + $crate::masos::arch::syscall6( + $nr as usize, + $a0 as usize, + $a1 as usize, + $a2 as usize, + $a3 as usize, + $a4 as usize, + $a5 as usize, + ) + }; +} diff --git a/hermit-builtins/src/masos/arch/x86_64.rs b/hermit-builtins/src/masos/arch/x86_64.rs new file mode 100644 index 0000000000..ce2dc2678e --- /dev/null +++ b/hermit-builtins/src/masos/arch/x86_64.rs @@ -0,0 +1,135 @@ +use core::arch::asm; + +#[inline] +pub(crate) unsafe fn syscall0(nr: usize) -> usize { + let r0; + unsafe { + asm!( + "syscall", + inlateout("rax") nr => r0, + lateout("rcx") _, + lateout("r11") _, + options(preserves_flags), + ); + } + r0 +} + +#[inline] +pub(crate) unsafe fn syscall1(nr: usize, a0: usize) -> usize { + let r0; + unsafe { + asm!( + "syscall", + inlateout("rax") nr => r0, + in("rdi") a0, + lateout("rcx") _, + lateout("r11") _, + options(preserves_flags), + ); + } + r0 +} + +#[inline] +pub(crate) unsafe fn syscall2(nr: usize, a0: usize, a1: usize) -> usize { + let r0; + unsafe { + asm!( + "syscall", + inlateout("rax") nr => r0, + in("rdi") a0, + in("rsi") a1, + lateout("rcx") _, + lateout("r11") _, + options(preserves_flags), + ); + } + r0 +} + +#[inline] +pub(crate) unsafe fn syscall3(nr: usize, a0: usize, a1: usize, a2: usize) -> usize { + let r0; + unsafe { + asm!( + "syscall", + inlateout("rax") nr => r0, + in("rdi") a0, + in("rsi") a1, + in("rdx") a2, + lateout("rcx") _, + lateout("r11") _, + options(preserves_flags), + ); + } + r0 +} + +#[inline] +pub(crate) unsafe fn syscall4(nr: usize, a0: usize, a1: usize, a2: usize, a3: usize) -> usize { + let r0; + unsafe { + asm!( + "syscall", + inlateout("rax") nr => r0, + in("rdi") a0, + in("rsi") a1, + in("rdx") a2, + in("r10") a3, + lateout("rcx") _, + lateout("r11") _, + options(preserves_flags), + ); + } + r0 +} + +#[inline] +pub(crate) unsafe fn syscall5(nr: usize, a0: usize, a1: usize, a2: usize, a3: usize, a4: usize) -> usize { + let r0; + unsafe { + asm!( + "syscall", + inlateout("rax") nr =>r0, + in("rdi") a0, + in("rsi") a1, + in("rdx") a2, + in("r10") a3, + in("r8") a4, + lateout("rcx") _, + lateout("r11") _, + options(preserves_flags), + ); + } + r0 +} + +#[inline] +pub(crate) unsafe fn syscall6( + nr: usize, + a0: usize, + a1: usize, + a2: usize, + a3: usize, + a4: usize, + a5: usize, +) -> usize { + let r0; + unsafe { + asm!( + "syscall", + inlateout("rax") nr => r0, + in("rdi") a0, + in("rsi") a1, + in("rdx") a2, + in("r10") a3, + in("r8") a4, + in("r9") a5, + lateout("rcx") _, + lateout("r11") _, + options(preserves_flags), + ); + } + r0 +} diff --git a/hermit-builtins/src/masos/mod.rs b/hermit-builtins/src/masos/mod.rs new file mode 100644 index 0000000000..966b3b266f --- /dev/null +++ b/hermit-builtins/src/masos/mod.rs @@ -0,0 +1,229 @@ +#[macro_use] +mod arch; +mod alloc; + +use core::cell::UnsafeCell; +use core::ffi::{c_char, c_int, c_void}; +use core::ptr; + +use ::alloc::borrow::ToOwned; +use ::alloc::vec; +use hermit_abi as libc; + +#[unsafe(no_mangle)] +unsafe extern "C" fn _start(_argc: c_int, _argv: *mut *mut c_char) -> ! { + let (argv, argc, _args_cap) = vec![c"dummy".to_owned().into_raw()].into_raw_parts(); + let argc = i32::try_from(argc).unwrap(); + + let envp = ptr::null_mut(); + + unsafe extern "C" { + fn runtime_entry(argc: c_int, argv: *mut *mut c_char, envp: *mut *mut c_char) -> !; + } + + unsafe { runtime_entry(argc, argv, envp) } +} + +#[thread_local] +static ERRNO: UnsafeCell = UnsafeCell::new(0); + +macro_rules! update_errno { + ($ret:expr) => { + let errno = -$ret.max(0); + let errno = c_int::try_from(errno).unwrap(); + // SAFETY: ERRNO is thread-local + unsafe { + ERRNO.get().write(errno); + } + }; +} + +#[unsafe(no_mangle)] +extern "C" fn sys_get_errno() -> c_int { + // SAFETY: ERRNO is thread-local + unsafe { ERRNO.get().read() } +} + +macro_rules! export { + () => (); + + (fn $fn:ident($($arg:ident: $argty:ty),*); $($rest:tt)*) => { + #[unsafe(no_mangle)] + unsafe extern "C" fn ${concat(sys_, $fn)}($($arg: $argty),*) { + unsafe { + syscall!(SyscallNo::$fn, $($arg),*); + } + } + + export!($($rest)*); + }; + + (fn $fn:ident($($arg:ident: $argty:ty),*) -> !; $($rest:tt)*) => { + #[unsafe(no_mangle)] + unsafe extern "C" fn ${concat(sys_, $fn)}($($arg: $argty),*) -> ! { + unsafe { + syscall!(SyscallNo::$fn, $($arg),*); + } + + unreachable!() + } + + export!($($rest)*); + }; + + (fn $fn:ident($($arg:ident: $argty:ty),*) -> $retty:ty; $($rest:tt)*) => { + #[unsafe(no_mangle)] + unsafe extern "C" fn ${concat(sys_, $fn)}($($arg: $argty),*) -> $retty { + let r0 = unsafe { syscall!(SyscallNo::$fn, $($arg),*) }; + let r0 = <$retty>::try_from(r0).unwrap(); + update_errno!(r0); + r0 + } + + export!($($rest)*); + }; + + (#[no_errno] fn $fn:ident($($arg:ident: $argty:ty),*) -> $retty:ty; $($rest:tt)*) => { + #[unsafe(no_mangle)] + unsafe extern "C" fn ${concat(sys_, $fn)}($($arg: $argty),*) -> $retty { + let r0 = unsafe { syscall!(SyscallNo::$fn, $($arg),*) }; + r0.try_into().unwrap() + } + + export!($($rest)*); + }; +} + +export! { + fn exit(arg: i32) -> !; + fn read(fd: i32, buf: *mut u8, len: usize) -> isize; + fn write(fd: i32, buf: *const u8, len: usize) -> isize; + fn usleep(usecs: u64); + #[no_errno] fn getpid() -> u32; + // fn sys_yield(); + fn read_entropy(buf: *mut u8, len: usize, flags: u32) -> isize; + #[no_errno] fn get_processor_count() -> usize; + fn close(fd: i32) -> i32; + fn futex_wait(address: *mut u32, expected: u32, timeout: *const libc::timespec, flags: u32) -> i32; + fn futex_wake(address: *mut u32, count: i32) -> i32; + fn open(name: *const i8, flags: i32, mode: i32) -> i32; + fn writev(fd: i32, iov: *const u8, iovcnt: usize) -> isize; + fn readv(fd: i32, iov: *const u8, iovcnt: usize) -> isize; + fn fork() -> libc::pid_t; + fn waitpid(pid: libc::pid_t) -> i32; + fn spawn_process(path: *const c_char) -> libc::pid_t; + fn clock_gettime(clock_id: u64, tp: *mut libc::timespec) -> i32; + fn spawn(id: *mut libc::Tid, func: extern "C" fn(usize), arg: usize, prio: u8, core_id: isize) -> i32; + #[no_errno] fn spawn2(func: extern "C" fn(usize), arg: usize, prio: u8, stack_size: usize, core_id: isize) -> libc::Tid; + fn join(id: libc::Tid) -> i32; + fn unlink(name: *const i8) -> i32; + fn mkdir(name: *const i8, mode: u32) -> i32; + fn rmdir(name: *const i8) -> i32; + fn stat(name: *const i8, stat: *mut libc::stat) -> i32; + fn lstat(name: *const i8, stat: *mut libc::stat) -> i32; + fn fstat(fd: i32, stat: *mut libc::stat) -> i32; + fn dup(fd: i32) -> i32; + fn ioctl(s: i32, cmd: i32, argp: *mut c_void) -> i32; + fn poll(fds: *mut libc::pollfd, nfds: libc::nfds_t, timeout: i32) -> i32; + fn notify(id: usize, count: i32) -> i32; + fn add_queue(id: usize, timeout_ns: i64) -> i32; + fn wait(id: usize) -> i32; + fn init_queue(id: usize) -> i32; + fn destroy_queue(id: usize) -> i32; + fn block_current_task(); + fn block_current_task_with_timeout(timeout: u64); + fn wakeup_task(tid: libc::Tid); + fn socket(domain: i32, type_: i32, protocol: i32) -> i32; + fn bind(s: i32, name: *const libc::sockaddr, namelen: libc::socklen_t) -> i32; + fn listen(s: i32, backlog: i32) -> i32; + fn accept(s: i32, addr: *mut libc::sockaddr, addrlen: *mut libc::socklen_t) -> i32; + fn connect(s: i32, name: *const libc::sockaddr, namelen: libc::socklen_t) -> i32; + fn recv(socket: i32, buf: *mut u8, len: usize, flags: i32) -> isize; + fn recvfrom(socket: i32, buf: *mut u8, len: usize, flags: i32, addr: *mut libc::sockaddr, addrlen: *mut libc::socklen_t) -> isize; + fn send(s: i32, mem: *const c_void, len: usize, flags: i32) -> isize; + fn sendto(s: i32, mem: *const c_void, len: usize, flags: i32, addr: *const libc::sockaddr, addr_len: libc::socklen_t) -> isize; + fn shutdown(s: i32, how: i32) -> i32; + fn getpeername(s: i32, name: *mut libc::sockaddr, namelen: *mut libc::socklen_t) -> i32; + fn getsockname(s: i32, name: *mut libc::sockaddr, namelen: *mut libc::socklen_t) -> i32; + fn getsockopt(s: i32, level: i32, optname: i32, optval: *mut c_void, optlen: *mut libc::socklen_t) -> i32; + fn setsockopt(s: i32, level: i32, optname: i32, optval: *const c_void, optlen: libc::socklen_t) -> i32; + fn getaddrinfo(nodename: *const i8, servname: *const i8, hints: *const libc::addrinfo, res: *mut *mut libc::addrinfo) -> i32; + fn freeaddrinfo(ai: *mut libc::addrinfo); + #[no_errno] fn available_parallelism() -> usize; + fn getdents64(fd: i32, dirp: *mut libc::dirent64, count: usize) -> i64; + fn exec(path: *const c_char) -> i32; +} + +#[unsafe(no_mangle)] +extern "C" fn sys_yield() { + unsafe { + syscall!(SyscallNo::r#yield); + } +} + +#[unsafe(no_mangle)] +extern "C" fn sys_abort() -> ! { + unsafe { sys_exit(1) } +} + +#[allow(non_camel_case_types)] +#[repr(usize)] +enum SyscallNo { + exit = 0, + write = 1, + read = 2, + usleep = 3, + getpid = 4, + r#yield = 5, + read_entropy = 6, + get_processor_count = 7, + close = 8, + futex_wait = 9, + futex_wake = 10, + open = 11, + writev = 12, + readv = 13, + fork = 14, + waitpid = 15, + spawn_process = 16, + clock_gettime = 17, + spawn = 18, + spawn2 = 19, + join = 20, + unlink = 21, + mkdir = 22, + rmdir = 23, + stat = 24, + lstat = 25, + fstat = 26, + dup = 27, + ioctl = 28, + poll = 29, + notify = 30, + add_queue = 31, + wait = 32, + init_queue = 33, + destroy_queue = 34, + block_current_task = 35, + block_current_task_with_timeout = 36, + wakeup_task = 37, + socket = 38, + bind = 39, + listen = 40, + accept = 41, + connect = 42, + recv = 43, + recvfrom = 44, + send = 45, + sendto = 46, + shutdown = 47, + getpeername = 48, + getsockname = 49, + getsockopt = 50, + setsockopt = 51, + getaddrinfo = 52, + freeaddrinfo = 53, + available_parallelism = 54, + getdents64 = 55, + exec = 56, +} diff --git a/typos.toml b/typos.toml index c283906f15..54fa65bbc3 100644 --- a/typos.toml +++ b/typos.toml @@ -3,6 +3,8 @@ locale = "en-us" extend-ignore-identifiers-re = [ "IST", "ist", + "masos", + "MASOS", "parm", "sie", ] diff --git a/xtask/src/arch.rs b/xtask/src/arch.rs index b8e61fb0dc..b220d1f7a3 100644 --- a/xtask/src/arch.rs +++ b/xtask/src/arch.rs @@ -81,22 +81,22 @@ impl Arch { match self { Self::X86_64 => &[ "--target=x86_64-unknown-hermit", - "-Zbuild-std=core", + "-Zbuild-std=core,alloc", "-Zbuild-std-features=compiler-builtins-mem", ], Self::Aarch64 => &[ "--target=aarch64-unknown-hermit", - "-Zbuild-std=core", + "-Zbuild-std=core,alloc", "-Zbuild-std-features=compiler-builtins-mem", ], Self::Aarch64Be => &[ "--target=aarch64_be-unknown-hermit", - "-Zbuild-std=core", + "-Zbuild-std=core,alloc", "-Zbuild-std-features=compiler-builtins-mem", ], Arch::Riscv64 => &[ "--target=riscv64gc-unknown-hermit", - "-Zbuild-std=core", + "-Zbuild-std=core,alloc", "-Zbuild-std-features=compiler-builtins-mem", ], } diff --git a/xtask/src/archive.rs b/xtask/src/archive.rs index 30f82e93b0..0d079bd1c8 100644 --- a/xtask/src/archive.rs +++ b/xtask/src/archive.rs @@ -22,7 +22,56 @@ impl AsRef for Archive { } impl Archive { - pub fn syscall_symbols(&self) -> Result> { + pub fn retain_kernel_symbols(&self) -> Result<()> { + eprintln!("Retaining kernel symbols"); + + let explicit_symbols = self.explicit_symbols().iter().copied(); + let syscall_symbols = self.syscall_symbols()?; + let syscall_symbols = syscall_symbols.iter().map(String::as_str); + + let symbols = explicit_symbols.chain(syscall_symbols).collect(); + self.retain_symbols(symbols)?; + + Ok(()) + } + + pub fn retain_builtin_symbols(&self) -> Result<()> { + eprintln!("Retaining hermit-builtins symbols"); + let sh = crate::sh()?; + + let builtin_symbols = sh.read_file("hermit-builtins/exports")?; + let builtin_symbols = builtin_symbols.lines(); + + let symbols = builtin_symbols.collect(); + self.retain_symbols(symbols)?; + + Ok(()) + } + + pub fn retain_masos_symbols(&self) -> Result<()> { + eprintln!("Retaining MASOS symbols"); + let sh = crate::sh()?; + + let explicit_symbols = self.explicit_symbols().iter().copied(); + let syscall_symbols = self.syscall_symbols()?; + let syscall_symbols = syscall_symbols.iter().map(String::as_str); + let builtin_symbols = sh.read_file("hermit-builtins/exports")?; + let builtin_symbols = builtin_symbols.lines(); + + let symbols = explicit_symbols + .chain(syscall_symbols) + .chain(builtin_symbols) + .collect(); + self.retain_symbols(symbols)?; + + Ok(()) + } + + fn explicit_symbols(&self) -> &[&str] { + &["_start", "__bss_start", "mcount", "runtime_entry"] + } + + fn syscall_symbols(&self) -> Result> { let sh = crate::sh()?; let archive = self.as_ref(); @@ -31,7 +80,7 @@ impl Archive { let symbols = archive .summarize() .into_iter() - .filter(|(member_name, _, _)| member_name.starts_with("hermit-")) + .filter(|(member_name, _, _)| member_name.starts_with("hermit")) .flat_map(|(_, _, symbols)| symbols) .filter(|symbol| symbol.starts_with("sys_")) .map(String::from) @@ -40,7 +89,7 @@ impl Archive { Ok(symbols) } - pub fn retain_symbols(&self, mut exported_symbols: HashSet<&str>) -> Result<()> { + fn retain_symbols(&self, mut exported_symbols: HashSet<&str>) -> Result<()> { let sh = crate::sh()?; let archive = self.as_ref(); let prefix = { @@ -87,6 +136,16 @@ impl Archive { Ok(()) } + pub fn create(&self) -> Result<()> { + let sh = crate::sh()?; + let archive = self.as_ref(); + + let ar = crate::binutil("ar").unwrap(); + cmd!(sh, "{ar} qc {archive}").run()?; + + Ok(()) + } + pub fn append(&self, file: &Self) -> Result<()> { let sh = crate::sh()?; let archive = self.as_ref(); diff --git a/xtask/src/build.rs b/xtask/src/build.rs index 8259e3d152..22c63bd1d9 100644 --- a/xtask/src/build.rs +++ b/xtask/src/build.rs @@ -1,4 +1,3 @@ -use std::collections::HashSet; use std::env::{self, VarError}; use anyhow::Result; @@ -38,7 +37,31 @@ impl Build { } self.cargo_build.artifact.arch.install_for_build()?; + let dist_archive = self.cargo_build.artifact.dist_archive(); + sh.create_dir(dist_archive.as_ref().parent().unwrap())?; + sh.remove_path(&dist_archive)?; + dist_archive.create()?; + + if self + .cargo_build + .features() + .any(|feature| feature == "masos") + { + self.build_builtins(true)?; + } else { + self.build_kernel()?; + + self.build_builtins(false)?; + } + eprintln!("Setting OSABI"); + dist_archive.set_osabi()?; + + eprintln!("Kernel available at {}", dist_archive.as_ref().display()); + Ok(()) + } + + fn build_kernel(&self) -> Result<()> { let careful = match env::var_os("HERMIT_CAREFUL") { Some(val) if val == "1" => &["careful"][..], _ => &[], @@ -60,17 +83,14 @@ impl Build { let build_archive = self.cargo_build.artifact.build_archive(); let dist_archive = self.cargo_build.artifact.dist_archive(); - eprintln!( - "Copying {} to {}", - build_archive.as_ref().display(), - dist_archive.as_ref().display() - ); - sh.create_dir(dist_archive.as_ref().parent().unwrap())?; - sh.copy_file(&build_archive, &dist_archive)?; - eprintln!("Exporting symbols"); - self.export_syms()?; + build_archive.retain_kernel_symbols()?; + dist_archive.append(&build_archive)?; + Ok(()) + } + + fn build_builtins(&self, masos: bool) -> Result<()> { eprintln!("Building hermit-builtins"); let mut cargo = crate::cargo(); cargo @@ -80,22 +100,24 @@ impl Build { .arg(self.cargo_build.artifact.builtins_profile_path_component()) .args(self.cargo_build.artifact.arch.builtins_cargo_args()) .args(self.cargo_build.builtins_target_dir_arg()); + if masos { + cargo.arg("--features=masos"); + } eprintln!("$ {cargo:?}"); let status = cargo.status()?; assert!(status.success()); - eprintln!("Exporting hermit-builtins symbols"); - let builtins = self.cargo_build.artifact.builtins_archive(); - let builtin_symbols = sh.read_file("hermit-builtins/exports")?; - builtins.retain_symbols(builtin_symbols.lines().collect::>())?; - - dist_archive.append(&builtins)?; + let builtins_archive = self.cargo_build.artifact.builtins_archive(); + let dist_archive = self.cargo_build.artifact.dist_archive(); - eprintln!("Setting OSABI"); - dist_archive.set_osabi()?; + if masos { + builtins_archive.retain_masos_symbols()?; + } else { + builtins_archive.retain_builtin_symbols()?; + } + dist_archive.append(&builtins_archive)?; - eprintln!("Kernel available at {}", dist_archive.as_ref().display()); Ok(()) } @@ -131,17 +153,4 @@ impl Build { Ok(rustflags.join("\x1f")) } - - fn export_syms(&self) -> Result<()> { - let archive = self.cargo_build.artifact.dist_archive(); - - let syscall_symbols = archive.syscall_symbols()?; - let explicit_exports = ["_start", "__bss_start", "mcount", "runtime_entry"].into_iter(); - - let symbols = explicit_exports.chain(syscall_symbols.iter().map(String::as_str)); - - archive.retain_symbols(symbols.collect::>())?; - - Ok(()) - } }