diff --git a/Cargo.lock b/Cargo.lock index 0a8571ae7..d44d82774 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2444,7 +2444,6 @@ version = "0.1.0" dependencies = [ "cc", "log", - "sel4-immediate-sync-once-cell", "sel4-panicking-env", ] diff --git a/crates/examples/microkit/http-server/pds/server/Cargo.nix b/crates/examples/microkit/http-server/pds/server/Cargo.nix index da5259bfd..4407ac841 100644 --- a/crates/examples/microkit/http-server/pds/server/Cargo.nix +++ b/crates/examples/microkit/http-server/pds/server/Cargo.nix @@ -51,7 +51,6 @@ mk { features = [ "nosys" "all-symbols" - "sel4-panicking-env" ]; }; diff --git a/crates/examples/microkit/http-server/pds/server/Cargo.toml b/crates/examples/microkit/http-server/pds/server/Cargo.toml index 133c0fb88..5f6b93224 100644 --- a/crates/examples/microkit/http-server/pds/server/Cargo.toml +++ b/crates/examples/microkit/http-server/pds/server/Cargo.toml @@ -31,6 +31,7 @@ sel4-externally-shared = { path = "../../../../../sel4-externally-shared", featu sel4-immediate-sync-once-cell = { path = "../../../../../sel4-immediate-sync-once-cell" } sel4-logging = { path = "../../../../../sel4-logging" } sel4-microkit-message = { path = "../../../../../sel4-microkit/message" } +sel4-newlib = { path = "../../../../../sel4-newlib", features = ["nosys", "all-symbols"] } sel4-shared-ring-buffer = { path = "../../../../../sel4-shared-ring-buffer" } sel4-shared-ring-buffer-block-io = { path = "../../../../../sel4-shared-ring-buffer/block-io" } sel4-shared-ring-buffer-smoltcp = { path = "../../../../../sel4-shared-ring-buffer/smoltcp" } @@ -53,10 +54,6 @@ path = "../../../../../sel4-microkit" default-features = false features = ["alloc"] -[dependencies.sel4-newlib] -path = "../../../../../sel4-newlib" -features = ["nosys", "all-symbols", "sel4-panicking-env"] - [dependencies.sel4-shared-ring-buffer-block-io-types] path = "../../../../../sel4-shared-ring-buffer/block-io/types" diff --git a/crates/examples/microkit/http-server/pds/server/src/main.rs b/crates/examples/microkit/http-server/pds/server/src/main.rs index da150df08..bb1b24ce5 100644 --- a/crates/examples/microkit/http-server/pds/server/src/main.rs +++ b/crates/examples/microkit/http-server/pds/server/src/main.rs @@ -74,8 +74,6 @@ static LOGGER: Logger = LoggerBuilder::const_default() fn init() -> impl Handler { LOGGER.set().unwrap(); - setup_newlib(); - let timer_client = TimerClient::new(channels::TIMER_DRIVER); let net_client = NetClient::new(channels::NET_DRIVER); let block_client = BlockClient::new(channels::BLOCK_DRIVER); @@ -184,17 +182,4 @@ fn init() -> impl Handler { ) } -fn setup_newlib() { - use sel4_newlib::*; - - set_static_heap_for_sbrk({ - static HEAP: StaticHeap<{ 1024 * 1024 }> = StaticHeap::new(); - &HEAP - }); - - set_implementations(Implementations { - _sbrk: Some(sbrk_with_static_heap), - _write: Some(write_with_debug_put_char), - ..Default::default() - }) -} +sel4_newlib::declare_sbrk_with_static_heap!(1024 * 1024); diff --git a/crates/private/tests/root-task/mbedtls/Cargo.nix b/crates/private/tests/root-task/mbedtls/Cargo.nix index 36778cafc..d1dcf2718 100644 --- a/crates/private/tests/root-task/mbedtls/Cargo.nix +++ b/crates/private/tests/root-task/mbedtls/Cargo.nix @@ -29,7 +29,6 @@ mk { features = [ "nosys" "all-symbols" - "sel4-panicking-env" ]; }; }; diff --git a/crates/private/tests/root-task/mbedtls/Cargo.toml b/crates/private/tests/root-task/mbedtls/Cargo.toml index 60d1bae47..142011996 100644 --- a/crates/private/tests/root-task/mbedtls/Cargo.toml +++ b/crates/private/tests/root-task/mbedtls/Cargo.toml @@ -20,6 +20,7 @@ license = "BSD-2-Clause" log = "0.4.17" sel4 = { path = "../../../../sel4" } sel4-logging = { path = "../../../../sel4-logging" } +sel4-newlib = { path = "../../../../sel4-newlib", features = ["nosys", "all-symbols"] } sel4-root-task = { path = "../../../../sel4-root-task" } [dependencies.mbedtls] @@ -37,7 +38,3 @@ default-features = false git = "https://github.com/coliasgroup/rust-mbedtls" tag = "keep/30d001b63baea36135b2590c4fd05e95" default-features = false - -[dependencies.sel4-newlib] -path = "../../../../sel4-newlib" -features = ["nosys", "all-symbols", "sel4-panicking-env"] diff --git a/crates/private/tests/root-task/mbedtls/src/main.rs b/crates/private/tests/root-task/mbedtls/src/main.rs index 9d344af7f..a70154007 100644 --- a/crates/private/tests/root-task/mbedtls/src/main.rs +++ b/crates/private/tests/root-task/mbedtls/src/main.rs @@ -10,7 +10,6 @@ use core::ffi::{c_char, c_int, CStr}; use sel4_logging::{LevelFilter, Logger, LoggerBuilder}; -use sel4_newlib as _; use sel4_root_task::{debug_print, debug_println, root_task}; const LOG_LEVEL: LevelFilter = LevelFilter::Debug; @@ -31,21 +30,9 @@ fn main(_: &sel4::BootInfo) -> ! { unreachable!() } -fn run_tests() { - { - use sel4_newlib::*; - - set_static_heap_for_sbrk({ - static HEAP: StaticHeap<{ HEAP_SIZE }> = StaticHeap::new(); - &HEAP - }); - - let mut impls = Implementations::default(); - impls._sbrk = Some(sbrk_with_static_heap); - impls._write = Some(write_with_debug_put_char); - set_implementations(impls) - } +sel4_newlib::declare_sbrk_with_static_heap!(HEAP_SIZE); +fn run_tests() { unsafe { mbedtls::self_test::enable(rand, Some(log)); } @@ -112,3 +99,15 @@ const TESTS: &[(&str, Test)] = tests! { ecp, ecjpake, }; + +#[allow(non_snake_case)] +mod hack { + #[repr(C, align(16))] + #[derive(Debug)] + pub struct LongDoublePlaceholder(pub [u8; 16]); + + #[no_mangle] + extern "C" fn __trunctfdf2(a: LongDoublePlaceholder) -> f64 { + sel4_root_task::abort!("__trunctfdf2({:?})", a) + } +} diff --git a/crates/private/tests/root-task/ring-test-harness/Cargo.nix b/crates/private/tests/root-task/ring-test-harness/Cargo.nix index 67ce7ccfd..d0197ac0b 100644 --- a/crates/private/tests/root-task/ring-test-harness/Cargo.nix +++ b/crates/private/tests/root-task/ring-test-harness/Cargo.nix @@ -18,7 +18,6 @@ mk rec { features = [ "nosys" "all-symbols" - "sel4-panicking-env" ]; }; getrandom = { diff --git a/crates/private/tests/root-task/ring-test-harness/Cargo.toml b/crates/private/tests/root-task/ring-test-harness/Cargo.toml index 7f812db44..fad2d4614 100644 --- a/crates/private/tests/root-task/ring-test-harness/Cargo.toml +++ b/crates/private/tests/root-task/ring-test-harness/Cargo.toml @@ -20,9 +20,6 @@ license = "BSD-2-Clause" getrandom = { version = "0.2.10", features = ["custom"] } rand = { version = "0.8.5", default-features = false, features = ["small_rng"] } sel4 = { path = "../../../../sel4" } +sel4-newlib = { path = "../../../../sel4-newlib", features = ["nosys", "all-symbols"] } sel4-root-task = { path = "../../../../sel4-root-task" } sel4-test-harness = { path = "../../../../sel4-test-harness" } - -[dependencies.sel4-newlib] -path = "../../../../sel4-newlib" -features = ["nosys", "all-symbols", "sel4-panicking-env"] diff --git a/crates/sel4-newlib/Cargo.nix b/crates/sel4-newlib/Cargo.nix index 2963d22e5..03bf93e88 100644 --- a/crates/sel4-newlib/Cargo.nix +++ b/crates/sel4-newlib/Cargo.nix @@ -10,27 +10,22 @@ mk { package.name = "sel4-newlib"; features = { default = [ "detect-libc" ]; - detect-libc = []; + detect-libc = [ "cc" ]; nosys = []; _exit = []; - __trunctfdf2 = []; - _sbrk = []; _write = []; + errno = []; all-symbols = [ "_exit" - "_sbrk" "_write" - "__trunctfdf2" + "errno" ]; }; dependencies = { - inherit (versions) log; - inherit (localCrates) - sel4-immediate-sync-once-cell - ; - sel4-panicking-env = localCrates.sel4-panicking-env // { optional = true; }; + inherit (localCrates) sel4-panicking-env; + log = { version = versions.log; optional = true; }; }; build-dependencies = { - cc = "1.0.82"; + cc = { version = "1.0.82"; optional = true; }; }; } diff --git a/crates/sel4-newlib/Cargo.toml b/crates/sel4-newlib/Cargo.toml index b6683b119..2157c2bf8 100644 --- a/crates/sel4-newlib/Cargo.toml +++ b/crates/sel4-newlib/Cargo.toml @@ -17,19 +17,17 @@ edition = "2021" license = "BSD-2-Clause" [features] -__trunctfdf2 = [] _exit = [] -_sbrk = [] _write = [] -all-symbols = ["_exit", "_sbrk", "_write", "__trunctfdf2"] +all-symbols = ["_exit", "_write", "errno"] default = ["detect-libc"] -detect-libc = [] +detect-libc = ["cc"] +errno = [] nosys = [] [dependencies] -log = "0.4.17" -sel4-immediate-sync-once-cell = { path = "../sel4-immediate-sync-once-cell" } -sel4-panicking-env = { path = "../sel4-panicking/env", optional = true } +log = { version = "0.4.17", optional = true } +sel4-panicking-env = { path = "../sel4-panicking/env" } [build-dependencies] -cc = "1.0.82" +cc = { version = "1.0.82", optional = true } diff --git a/crates/sel4-newlib/build.rs b/crates/sel4-newlib/build.rs index 0fa2fe1f7..b7ad7c52e 100644 --- a/crates/sel4-newlib/build.rs +++ b/crates/sel4-newlib/build.rs @@ -14,11 +14,13 @@ fn main() { if cfg!(feature = "nosys") { println!("cargo:rustc-link-lib=static=nosys"); } - if cfg!(feature = "detect-libc") { + #[cfg(feature = "detect-libc")] + { detect_libc(); } } +#[cfg(feature = "detect-libc")] fn detect_libc() { let tool = cc::Build::new().get_compiler(); diff --git a/crates/sel4-newlib/src/errno.rs b/crates/sel4-newlib/src/errno.rs new file mode 100644 index 000000000..140645cc0 --- /dev/null +++ b/crates/sel4-newlib/src/errno.rs @@ -0,0 +1,29 @@ +// +// Copyright 2023, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + +use core::ffi::c_int; + +#[cfg(feature = "errno")] +#[no_mangle] +static mut errno: c_int = 0; + +#[cfg(not(feature = "errno"))] +extern "C" { + static mut errno: c_int; +} + +pub(crate) fn set_errno(err: c_int) { + unsafe { + errno = err; + } +} + +pub(crate) mod values { + use super::*; + + pub(crate) const ENOENT: c_int = 2; + pub(crate) const ENOMEM: c_int = 12; +} diff --git a/crates/sel4-newlib/src/heap.rs b/crates/sel4-newlib/src/heap.rs new file mode 100644 index 000000000..37427a71d --- /dev/null +++ b/crates/sel4-newlib/src/heap.rs @@ -0,0 +1,75 @@ +// +// Copyright 2023, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + +use super::*; + +use core::cell::SyncUnsafeCell; +use core::ffi::{c_int, c_void}; +use core::ptr; +use core::sync::atomic::{AtomicIsize, Ordering}; + +use sel4_panicking_env::abort; + +#[repr(align(4096))] // no real reason for this +struct BackingMemory(SyncUnsafeCell<[u8; N]>); + +impl BackingMemory { + const fn new() -> Self { + Self(SyncUnsafeCell::new([0; N])) + } + + const fn bounds(&self) -> *mut [u8] { + ptr::slice_from_raw_parts_mut(self.0.get().cast(), N) + } +} + +#[doc(hidden)] +pub struct StaticHeap { + memory: BackingMemory, + watermark: AtomicIsize, +} + +unsafe impl Sync for StaticHeap {} + +impl StaticHeap { + pub const fn new() -> Self { + Self { + memory: BackingMemory::new(), + watermark: AtomicIsize::new(0), + } + } + + // TODO handle overflowing atomic + pub fn sbrk(&self, incr: c_int) -> *mut c_void { + #[cfg(feature = "log")] + { + log::trace!("_sbrk({})", incr); + } + let incr = incr.try_into().unwrap_or_else(|_| abort!()); + let old = self.watermark.fetch_add(incr, Ordering::SeqCst); + let new = old + incr; + if new < 0 { + abort!("program break below data segment start") + } + if new > N.try_into().unwrap_or_else(|_| abort!()) { + self.watermark.fetch_sub(incr, Ordering::SeqCst); + errno::set_errno(errno::values::ENOMEM); + return usize::MAX as *mut c_void; + } + unsafe { self.memory.bounds().as_mut_ptr().offset(old).cast() } + } +} + +#[macro_export] +macro_rules! declare_sbrk_with_static_heap { + ($n:expr) => { + #[no_mangle] + extern "C" fn _sbrk(incr: core::ffi::c_int) -> *mut core::ffi::c_void { + static HEAP: $crate::StaticHeap<{ $n }> = $crate::StaticHeap::new(); + HEAP.sbrk(incr) + } + }; +} diff --git a/crates/sel4-newlib/src/lib.rs b/crates/sel4-newlib/src/lib.rs index 5bd60687d..34d0e96e3 100644 --- a/crates/sel4-newlib/src/lib.rs +++ b/crates/sel4-newlib/src/lib.rs @@ -4,6 +4,8 @@ // SPDX-License-Identifier: BSD-2-Clause // +// TODO address thread safety and reentrancy (init reentrancy structs and figure out what's up with errno) + #![no_std] #![feature(const_slice_from_raw_parts_mut)] #![feature(slice_ptr_get)] @@ -11,184 +13,63 @@ #![feature(sync_unsafe_cell)] #[allow(unused_imports)] -use core::ffi::{c_char, c_int, c_uint, c_void}; - -use sel4_immediate_sync_once_cell::ImmediateSyncOnceCell; +use core::ffi::{c_char, c_int, c_uint}; -#[derive(Default)] -pub struct Implementations { - #[cfg(feature = "_exit")] - pub _exit: Option, - #[cfg(feature = "_sbrk")] - pub _sbrk: Option *mut c_void>, - #[cfg(feature = "_write")] - pub _write: Option, - #[cfg(feature = "__trunctfdf2")] - pub __trunctfdf2: Option f64>, -} +mod errno; +mod heap; -static IMPLEMENTATIONS: ImmediateSyncOnceCell = ImmediateSyncOnceCell::new(); - -pub fn set_implementations(implementations: Implementations) { - IMPLEMENTATIONS.set(implementations).unwrap_or_else(|_| { - panic!("set_implementations() has already been called, or has not yet been completed") - }) -} +pub use heap::StaticHeap; -pub fn try_get_implementations() -> Option<&'static Implementations> { - IMPLEMENTATIONS.get() -} - -pub fn get_implementations() -> &'static Implementations { - try_get_implementations() - .unwrap_or_else(|| panic!("set_implementations() has not yet been called")) +extern "C" { + #[link_name = "srand"] + fn newlib_srand(seed: c_uint); } -#[allow(unused_macros)] -macro_rules! get_impl { - ($symbol:ident) => { - crate::get_implementations() - .$symbol - .unwrap_or_else(|| unimplemented!(stringify!($symbol))) - }; +pub fn srand(seed: c_uint) { + unsafe { + newlib_srand(seed); + } } #[cfg(feature = "_exit")] mod impl_exit { - #[no_mangle] - extern "C" fn _exit() { - get_impl!(_exit)() - } -} - -#[cfg(feature = "_sbrk")] -pub use impl_sbrk::*; - -#[cfg(feature = "_sbrk")] -mod impl_sbrk { use super::*; - use core::cell::SyncUnsafeCell; - use core::ptr; - use core::sync::atomic::{AtomicIsize, Ordering}; - - use sel4_immediate_sync_once_cell::ImmediateSyncOnceCell; - - pub struct StaticHeap(SyncUnsafeCell<[u8; N]>); - - impl StaticHeap { - pub const fn new() -> Self { - Self(SyncUnsafeCell::new([0; N])) - } - - const fn bounds(&self) -> *mut [u8] { - ptr::slice_from_raw_parts_mut(self.0.get().cast(), N) - } - } - - struct StaticHeapState { - watermark: AtomicIsize, - ptr: *mut [u8], - } - - unsafe impl Sync for StaticHeapState {} - - impl StaticHeapState { - const fn new(heap: &StaticHeap) -> Self { - Self { - watermark: AtomicIsize::new(0), - ptr: heap.bounds(), - } - } - - fn sbrk(&self, incr: isize) -> *mut u8 { - let old = self.watermark.fetch_add(incr, Ordering::SeqCst); - let new = old + incr; - assert!(new >= 0); - assert!(new <= self.ptr.len().try_into().unwrap()); - unsafe { self.ptr.as_mut_ptr().offset(old).cast() } - } - } - - static STATIC_HEAP_STATE: ImmediateSyncOnceCell = ImmediateSyncOnceCell::new(); - - pub fn sbrk_with_static_heap(incr: c_int) -> *mut c_void { - STATIC_HEAP_STATE - .get() - .expect( - "set_static_heap_for_sbrk() has not yet been called, or has not yet been completed", - ) - .sbrk(incr.try_into().unwrap()) - .cast() - } - - pub fn set_static_heap_for_sbrk(static_heap: &StaticHeap) { - STATIC_HEAP_STATE - .set(StaticHeapState::new(static_heap)) - .ok() - .expect("set_static_heap_for_sbrk() has already been called") - } + use sel4_panicking_env::abort; #[no_mangle] - extern "C" fn _sbrk(incr: c_int) -> *mut c_void { - get_impl!(_sbrk)(incr) + extern "C" fn _exit(rc: c_int) -> ! { + abort!("_exit({})", rc) } } -#[cfg(feature = "_write")] -pub use impl_write::*; - #[cfg(feature = "_write")] mod impl_write { use super::*; - #[no_mangle] - extern "C" fn _write(file: c_int, ptr: *const c_char, len: c_int) { - get_impl!(_write)(file, ptr, len) - } - - #[cfg(feature = "sel4-panicking-env")] - pub use with_sel4_panicking_env::*; - - #[cfg(feature = "sel4-panicking-env")] - mod with_sel4_panicking_env { - use super::*; + use core::slice; - use core::slice; + use sel4_panicking_env::debug_put_char; - use sel4_panicking_env::debug_put_char; - - pub fn write_with_debug_put_char(_file: c_int, ptr: *const c_char, len: c_int) { - let bytes = unsafe { slice::from_raw_parts(ptr.cast::(), len.try_into().unwrap()) }; - for b in bytes { - debug_put_char(*b); + #[no_mangle] + extern "C" fn _write(file: c_int, ptr: *const c_char, len: c_int) -> c_int { + match file { + 1 | 2 => { + let bytes = + unsafe { slice::from_raw_parts(ptr.cast::(), len.try_into().unwrap()) }; + for b in bytes { + debug_put_char(*b); + } + len + } + _ => { + #[cfg(feature = "log")] + { + log::warn!("_write({}, {:#x?}, {})", file, ptr, len); + } + errno::set_errno(errno::values::ENOENT); + -1 } } } } - -#[cfg(feature = "__trunctfdf2")] -pub use impl__trunctfdf2::*; - -#[cfg(feature = "__trunctfdf2")] -#[allow(non_snake_case)] -mod impl__trunctfdf2 { - #[repr(C, align(16))] - pub struct LongDoublePlaceholder(pub [u8; 16]); - - #[no_mangle] - extern "C" fn __trunctfdf2(a: LongDoublePlaceholder) -> f64 { - get_impl!(__trunctfdf2)(a) - } -} - -extern "C" { - #[link_name = "srand"] - fn newlib_srand(seed: c_uint); -} - -pub fn srand(seed: c_uint) { - unsafe { - newlib_srand(seed); - } -}