diff --git a/src/runtime/monitor/secapi/gates.rs b/src/runtime/monitor/secapi/gates.rs index 3b2f4798..db6d8cd8 100644 --- a/src/runtime/monitor/secapi/gates.rs +++ b/src/runtime/monitor/secapi/gates.rs @@ -14,11 +14,12 @@ pub fn monitor_rt_spawn_thread( thread_pointer: usize, stack_pointer: usize, ) -> Result { - crate::thread::__monitor_rt_spawn_thread( + let monitor = crate::mon::get_monitor(); + monitor.spawn_compartment_thread( info.source_context().unwrap_or(0.into()), args, - thread_pointer, stack_pointer, + thread_pointer, ) } @@ -28,7 +29,12 @@ pub fn monitor_rt_spawn_thread( secgate::secure_gate(options(info, api)) )] pub fn monitor_rt_get_comp_config(info: &secgate::GateCallInfo) -> usize { - crate::thread::__monitor_rt_get_comp_config(info.source_context().unwrap_or(0.into())) as usize + use crate::api::MONITOR_INSTANCE_ID; + let monitor = crate::mon::get_monitor(); + monitor + .get_comp_config(info.source_context().unwrap_or(MONITOR_INSTANCE_ID)) + .map(|ptr| ptr as usize) + .unwrap_or(0) } #[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))] @@ -66,8 +72,38 @@ pub fn monitor_rt_object_map( info: &secgate::GateCallInfo, id: ObjID, flags: twizzler_runtime_api::MapFlags, -) -> Result { - crate::object::map_object(info, id, flags) +) -> Result { + use twz_rt::{RuntimeState, OUR_RUNTIME}; + + use crate::{api::MONITOR_INSTANCE_ID, mon::space::MapInfo}; + if OUR_RUNTIME.state().contains(RuntimeState::READY) { + // Are we recursing from the monitor, with a lock held? In that case, use early_object_map + // to map the object. This will leak this mapping, but this is both rare, and then + // since the mapping is leaked, it can be used as an allocator object indefinitely + // (not currently implemented). Make sure the ThreadKey drops. + let is_monitor_recursed = + { happylock::ThreadKey::get().is_none() && info.source_context().is_none() }; + if is_monitor_recursed { + tracing::debug!( + "performing early object mapping (recursed), {} {:?}", + id, + flags + ); + return Ok(crate::mon::early_object_map(MapInfo { id, flags })); + } + let monitor = crate::mon::get_monitor(); + monitor + .map_object( + info.source_context().unwrap_or(MONITOR_INSTANCE_ID), + MapInfo { id, flags }, + ) + .map(|handle| handle.addrs()) + } else { + // We need to use early_object_map, since the monitor hasn't finished initializing, but + // still needs to allocate (which may involve mapping an object). + tracing::debug!("performing early object mapping, {} {:?}", id, flags); + Ok(crate::mon::early_object_map(MapInfo { id, flags })) + } } #[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))] @@ -75,6 +111,24 @@ pub fn monitor_rt_object_map( not(feature = "secgate-impl"), secgate::secure_gate(options(info, api)) )] -pub fn monitor_rt_object_unmap(info: &secgate::GateCallInfo, slot: usize) { - crate::object::unmap_object(info, slot) +pub fn monitor_rt_object_unmap( + info: &secgate::GateCallInfo, + _slot: usize, + id: ObjID, + flags: twizzler_runtime_api::MapFlags, +) { + use twz_rt::{RuntimeState, OUR_RUNTIME}; + if OUR_RUNTIME.state().contains(RuntimeState::READY) { + let monitor = crate::mon::get_monitor(); + let key = happylock::ThreadKey::get().unwrap(); + monitor + .comp_mgr + .write(key) + .get_mut( + info.source_context() + .unwrap_or(crate::api::MONITOR_INSTANCE_ID), + ) + .unwrap() + .unmap_object(crate::mon::space::MapInfo { id, flags }) + } } diff --git a/src/runtime/monitor/src/lib.rs b/src/runtime/monitor/src/lib.rs index 244e104b..ebec63f6 100644 --- a/src/runtime/monitor/src/lib.rs +++ b/src/runtime/monitor/src/lib.rs @@ -4,22 +4,15 @@ #![feature(new_uninit)] #![feature(hash_extract_if)] -use std::sync::{Arc, Mutex}; - -use dynlink::{engines::Backing, symbol::LookupFlags}; -use state::MonitorState; -use tracing::{debug, info, trace, warn, Level}; +use dynlink::engines::Backing; +use tracing::{debug, info, warn, Level}; use tracing_subscriber::{fmt::format::FmtSpan, FmtSubscriber}; use twizzler_abi::{ aux::KernelInitInfo, object::{MAX_SIZE, NULLPAGE_SIZE}, - syscall::{sys_object_create, ObjectCreate}, }; use twizzler_object::ObjID; -use twizzler_runtime_api::AuxEntry; -use twz_rt::{set_upcall_handler, CompartmentInitInfo}; - -use crate::{compartment::Comp, state::set_monitor_state}; +use twz_rt::{set_upcall_handler, OUR_RUNTIME}; mod compartment; mod init; @@ -33,6 +26,8 @@ mod upcall; mod api; mod mon; +pub use monitor_api::MappedObjectAddrs; + #[path = "../secapi/gates.rs"] mod gates; @@ -51,130 +46,32 @@ pub fn main() { })) .unwrap(); - trace!("monitor entered, discovering dynlink context"); + debug!("monitor entered, discovering dynlink context"); let init = init::bootstrap_dynlink_context().expect("failed to discover initial dynlink context"); - let mut state = state::MonitorState::new(init); - let monitor_comp_id = state.dynlink.lookup_compartment("monitor").unwrap(); - let monitor_comp = Comp::new( - 0.into(), - state.dynlink.get_compartment_mut(monitor_comp_id).unwrap(), - ) - .unwrap(); - state.add_comp(monitor_comp, twizzler_runtime_api::LibraryId(0)); + let mon = mon::Monitor::new(init); + mon::set_monitor(mon); - let state = Arc::new(Mutex::new(state)); - tracing::info!(".. state: {:p}", state); - debug!( - "found dynlink context, with root {}", - state.lock().unwrap().root - ); + // Safety: the monitor is ready, and so we can set our runtime as ready to use the monitor. + unsafe { OUR_RUNTIME.set_runtime_ready() }; + // Had to wait till now to be able to spawn threads. + mon::get_monitor().start_background_threads(); + debug!("Ok"); std::env::set_var("RUST_BACKTRACE", "1"); - set_upcall_handler(&crate::upcall::upcall_monitor_handler).unwrap(); - set_monitor_state(state.clone()); - let main_thread = std::thread::spawn(|| monitor_init(state)); + let main_thread = std::thread::spawn(|| monitor_init()); let _r = main_thread.join().unwrap().map_err(|e| { tracing::error!("{:?}", e); }); warn!("monitor main thread exited"); } -fn monitor_init(state: Arc>) -> miette::Result<()> { +fn monitor_init() -> miette::Result<()> { info!("monitor early init completed, starting init"); - { - let state = state.lock().unwrap(); - let comp = state.dynlink.lookup_compartment("monitor").unwrap(); - let mon = state.dynlink.lookup_library(comp, "libmonitor.so").unwrap(); - - let mon = state.dynlink.get_library(mon)?; - - for gate in mon.iter_secgates().unwrap() { - let name = gate.name().to_string_lossy(); - info!("secure gate in {} => {}: {:x}", mon.name, name, gate.imp); - } - } - - load_hello_world_test(&state).unwrap(); - - Ok(()) -} - -fn load_hello_world_test(state: &Arc>) -> miette::Result<()> { - let lib = dynlink::library::UnloadedLibrary::new("hello-world"); - let rt_lib = dynlink::library::UnloadedLibrary::new("libtwz_rt.so"); - - let mut state = state.lock().unwrap(); - let test_comp_id = state.dynlink.add_compartment("test")?; - - let libhw_id = state - .dynlink - .load_library_in_compartment(test_comp_id, lib)?; - - let rt_id = match state - .dynlink - .load_library_in_compartment(test_comp_id, rt_lib) - { - Ok(rt_id) => { - state.dynlink.add_manual_dependency(libhw_id, rt_id); - rt_id - } - Err(_) => state - .dynlink - .lookup_library(test_comp_id, "libtwz_rt.so") - .unwrap(), - }; - - println!("found rt_id: {}", rt_id); - let rt_lib = state.dynlink.get_library(rt_id).unwrap(); - - drop(rt_lib); - - state.dynlink.relocate_all(libhw_id)?; - - let test_comp = Comp::new( - 1.into(), - state.dynlink.get_compartment_mut(test_comp_id).unwrap(), - ) - .unwrap(); - - info!("!! root = {}", libhw_id); - let ctors = state.dynlink.build_ctors_list(libhw_id).unwrap(); - - let rtinfo = CompartmentInitInfo { - ctor_array_start: ctors.as_ptr() as usize, - ctor_array_len: ctors.len(), - comp_config_addr: test_comp.get_comp_config() as *const _ as usize, - }; - state.add_comp(test_comp, libhw_id.into()); - - info!("lookup entry"); - - let rt_lib = state.dynlink.get_library(rt_id).unwrap(); - let entry = rt_lib.get_entry_address().unwrap(); - - let aux = [ - AuxEntry::RuntimeInfo(&rtinfo as *const _ as usize, 1), - AuxEntry::Null, - ]; - println!("==> {:p}", entry); - drop(state); - entry(aux.as_ptr()); - /* - let sym = state - .dynlink - .lookup_symbol(libhw_id, "test_sec_call", LookupFlags::empty())?; - - let addr = sym.reloc_value(); - info!("addr = {:x}", addr); - let ptr: extern "C" fn() = unsafe { core::mem::transmute(addr as usize) }; - (ptr)(); - */ - Ok(()) } diff --git a/src/runtime/monitor/src/mon/compartment.rs b/src/runtime/monitor/src/mon/compartment.rs index 6094be23..a21d2c7f 100644 --- a/src/runtime/monitor/src/mon/compartment.rs +++ b/src/runtime/monitor/src/mon/compartment.rs @@ -2,14 +2,17 @@ use std::collections::HashMap; use twizzler_runtime_api::ObjID; -use self::runcomp::RunComp; use crate::api::MONITOR_INSTANCE_ID; mod compconfig; mod compthread; mod runcomp; +pub use compconfig::*; +pub use runcomp::*; + /// Manages compartments. +#[derive(Default)] pub struct CompartmentMgr { names: HashMap, instances: HashMap, diff --git a/src/runtime/monitor/src/mon/compartment/runcomp.rs b/src/runtime/monitor/src/mon/compartment/runcomp.rs index a89e281e..411996c2 100644 --- a/src/runtime/monitor/src/mon/compartment/runcomp.rs +++ b/src/runtime/monitor/src/mon/compartment/runcomp.rs @@ -43,9 +43,35 @@ pub struct RunComp { } impl RunComp { + pub fn new( + sctx: ObjID, + instance: ObjID, + name: String, + compartment_id: CompartmentId, + deps: Vec, + comp_config_object: CompConfigObject, + flags: u64, + ) -> Self { + let mut alloc = Talc::new(ErrOnOom); + unsafe { alloc.claim(comp_config_object.alloc_span()).unwrap() }; + Self { + sctx, + instance, + name, + compartment_id, + main: None, + deps, + comp_config_object, + alloc, + mapped_objects: HashMap::default(), + flags: Box::new(AtomicU64::new(flags)), + } + } + /// Map an object into this compartment. - pub fn map_object(&mut self, info: MapInfo) -> Result { - todo!() + pub fn map_object(&mut self, info: MapInfo, handle: MapHandle) -> Result { + self.mapped_objects.insert(info, handle.clone()); + Ok(handle) } /// Unmap and object from this compartment. @@ -59,6 +85,11 @@ impl RunComp { self.comp_config_object.read_comp_config() } + /// Get a pointer to the compartment config. + pub fn comp_config_ptr(&self) -> *const SharedCompConfig { + self.comp_config_object.get_comp_config() + } + /// Set the compartment config. pub fn set_comp_config(&mut self, scc: SharedCompConfig) { self.comp_config_object.write_config(scc) diff --git a/src/runtime/monitor/src/mon/mod.rs b/src/runtime/monitor/src/mon/mod.rs index 76d66146..2b4ffa20 100644 --- a/src/runtime/monitor/src/mon/mod.rs +++ b/src/runtime/monitor/src/mon/mod.rs @@ -1,8 +1,18 @@ -use std::sync::OnceLock; +use std::{ptr::NonNull, sync::OnceLock}; -use happylock::RwLock; +use dynlink::compartment::MONITOR_COMPARTMENT_ID; +use happylock::{LockCollection, RwLock, ThreadKey}; +use monitor_api::{SharedCompConfig, TlsTemplateInfo}; +use twizzler_abi::upcall::UpcallFrame; +use twizzler_runtime_api::{MapError, MapFlags, ObjID, SpawnError, ThreadSpawnArgs}; +use twz_rt::{RuntimeState, RuntimeThreadControl, OUR_RUNTIME}; -use self::space::Unmapper; +use self::{ + compartment::{CompConfigObject, RunComp}, + space::{MapHandle, MapInfo, Unmapper}, + thread::{ManagedThread, ThreadCleaner}, +}; +use crate::{api::MONITOR_INSTANCE_ID, init::InitDynlinkContext}; pub(crate) mod compartment; pub(crate) mod space; @@ -15,11 +25,139 @@ pub(crate) mod thread; /// 'dynlink', which contains the dynamic linker state. The unmapper allows for background unmapping /// and cleanup of objects and handles. pub struct Monitor { - space: RwLock, - thread_mgr: RwLock, - compartments: RwLock, - dynlink: RwLock, - unmapper: Unmapper, + locks: LockCollection>, + unmapper: OnceLock, + /// Management of address space. + pub space: &'static RwLock, + /// Management of all threads. + pub thread_mgr: &'static RwLock, + /// Management of compartments. + pub comp_mgr: &'static RwLock, + /// Dynamic linker state. + pub dynlink: &'static RwLock<&'static mut dynlink::context::Context>, +} + +// We allow locking individually, using eg mon.space.write(key), or locking the collection for more +// complex operations that touch multiple pieces of state. +type MonitorLocks<'a> = ( + &'a RwLock, + &'a RwLock, + &'a RwLock, + &'a RwLock<&'static mut dynlink::context::Context>, +); + +impl Monitor { + /// Start the background threads for the monitor instance. Must be done only once the monitor + /// has been initialized. + pub fn start_background_threads(&self) { + assert!(OUR_RUNTIME.state().contains(RuntimeState::READY)); + let cleaner = ThreadCleaner::new(); + self.unmapper.set(Unmapper::new()).ok().unwrap(); + self.thread_mgr + .write(ThreadKey::get().unwrap()) + .set_cleaner(cleaner); + } + + /// Build a new monitor state from the initial dynamic linker context. + pub fn new(init: InitDynlinkContext) -> Self { + let mut comp_mgr = compartment::CompartmentMgr::default(); + let mut space = space::Space::default(); + + // Build our TLS region, and create a template for the monitor compartment. + let super_tls = (unsafe { &mut *init.ctx }) + .get_compartment_mut(MONITOR_COMPARTMENT_ID) + .unwrap() + .build_tls_region(RuntimeThreadControl::default(), |layout| unsafe { + NonNull::new(std::alloc::alloc_zeroed(layout)) + }) + .unwrap(); + let template: &'static TlsTemplateInfo = Box::leak(Box::new(super_tls.into())); + + // Set up the monitor's compartment. + let monitor_scc = + SharedCompConfig::new(MONITOR_INSTANCE_ID, template as *const _ as *mut _); + let handle = space + .safe_create_and_map_runtime_object( + MONITOR_INSTANCE_ID, + MapFlags::READ | MapFlags::WRITE, + ) + .unwrap(); + comp_mgr.insert(RunComp::new( + MONITOR_INSTANCE_ID, + MONITOR_INSTANCE_ID, + "monitor".to_string(), + MONITOR_COMPARTMENT_ID, + vec![], + CompConfigObject::new(handle, monitor_scc), + 0, + )); + + // Allocate and leak all the locks (they are global and eternal, so we can do this to safely + // and correctly get &'static lifetime) + let space = Box::leak(Box::new(RwLock::new(space))); + let thread_mgr = Box::leak(Box::new(RwLock::new(thread::ThreadMgr::default()))); + let comp_mgr = Box::leak(Box::new(RwLock::new(comp_mgr))); + let dynlink = Box::leak(Box::new(RwLock::new(unsafe { init.ctx.as_mut().unwrap() }))); + + // Okay to call try_new here, since it's not many locks and only happens once. + Self { + locks: LockCollection::try_new((&*space, &*thread_mgr, &*comp_mgr, &*dynlink)).unwrap(), + unmapper: OnceLock::new(), + space, + thread_mgr, + comp_mgr, + dynlink, + } + } + + /// Start a managed monitor thread. + pub fn start_thread(&self, main: Box) -> Result { + let key = ThreadKey::get().unwrap(); + let locks = &mut *self.locks.lock(key); + + let monitor_dynlink_comp = locks.3.get_compartment_mut(MONITOR_COMPARTMENT_ID).unwrap(); + locks + .1 + .start_thread(&mut *locks.0, monitor_dynlink_comp, main) + } + + /// Spawn a thread into a given compartment, using initial thread arguments. + pub fn spawn_compartment_thread( + &self, + instance: ObjID, + args: ThreadSpawnArgs, + stack_ptr: usize, + thread_ptr: usize, + ) -> Result { + let thread = self.start_thread(Box::new(move || { + let frame = UpcallFrame::new_entry_frame( + stack_ptr, + args.stack_size, + thread_ptr, + instance, + args.start, + args.arg, + ); + unsafe { twizzler_abi::syscall::sys_thread_resume_from_upcall(&frame) }; + }))?; + Ok(thread.id) + } + + /// Get the compartment config for the given compartment. + pub fn get_comp_config(&self, sctx: ObjID) -> Option<*const SharedCompConfig> { + let comps = self.comp_mgr.read(ThreadKey::get().unwrap()); + Some(comps.get(sctx)?.comp_config_ptr()) + } + + /// Map an object into a given compartment. + pub fn map_object(&self, sctx: ObjID, info: MapInfo) -> Result { + let handle = self.space.write(ThreadKey::get().unwrap()).map(info)?; + + let mut comp_mgr = self.comp_mgr.write(ThreadKey::get().unwrap()); + let rc = comp_mgr.get_mut(sctx).ok_or(MapError::InvalidArgument)?; + let handle = rc.map_object(info, handle)?; + Ok(handle) + } } static MONITOR: OnceLock = OnceLock::new(); @@ -36,3 +174,5 @@ pub fn set_monitor(monitor: Monitor) { panic!("second call to set_monitor"); } } + +pub use space::early_object_map; diff --git a/src/runtime/monitor/src/mon/space.rs b/src/runtime/monitor/src/mon/space.rs index 8dec7a72..cccb9021 100644 --- a/src/runtime/monitor/src/mon/space.rs +++ b/src/runtime/monitor/src/mon/space.rs @@ -3,8 +3,9 @@ use std::{collections::HashMap, sync::Arc}; use miette::IntoDiagnostic; use monitor_api::MappedObjectAddrs; use twizzler_abi::syscall::{ - sys_object_create, sys_object_ctrl, sys_object_map, sys_object_unmap, CreateTieSpec, - DeleteFlags, ObjectControlCmd, ObjectCreate, ObjectSource, UnmapFlags, + sys_object_create, sys_object_ctrl, sys_object_map, sys_object_unmap, BackingType, + CreateTieSpec, DeleteFlags, LifetimeType, ObjectControlCmd, ObjectCreate, ObjectCreateFlags, + ObjectSource, UnmapFlags, }; use twizzler_object::Protections; use twizzler_runtime_api::{MapError, MapFlags, ObjID}; @@ -136,10 +137,28 @@ impl Space { } .into_diagnostic() } + + pub(crate) fn safe_create_and_map_runtime_object( + &mut self, + instance: ObjID, + map_flags: MapFlags, + ) -> miette::Result { + self.safe_create_and_map_object( + ObjectCreate::new( + BackingType::Normal, + LifetimeType::Volatile, + Some(instance), + ObjectCreateFlags::empty(), + ), + &[], + &[], + map_flags, + ) + } } -// Allows us to call handle_drop and do all the hard work in the caller, since -// the caller probably had to hold a lock to call these functions. +/// Allows us to call handle_drop and do all the hard work in the caller, since +/// the caller probably had to hold a lock to call these functions. pub(crate) struct UnmapOnDrop { slot: usize, } @@ -153,3 +172,20 @@ impl Drop for UnmapOnDrop { } } } + +/// Map an object into the address space, without tracking it. This leaks the mapping, but is useful +/// for bootstrapping. See the object mapping gate comments for more details. +pub fn early_object_map(info: MapInfo) -> MappedObjectAddrs { + let slot = twz_rt::OUR_RUNTIME.allocate_slot().unwrap(); + + sys_object_map( + None, + info.id, + slot, + mapflags_into_prot(info.flags), + twizzler_abi::syscall::MapFlags::empty(), + ) + .unwrap(); + + MappedObjectAddrs::new(slot) +} diff --git a/src/runtime/monitor/src/mon/space/handle.rs b/src/runtime/monitor/src/mon/space/handle.rs index 743aa7a1..c790ac4e 100644 --- a/src/runtime/monitor/src/mon/space/handle.rs +++ b/src/runtime/monitor/src/mon/space/handle.rs @@ -42,6 +42,8 @@ impl Drop for MapHandleInner { fn drop(&mut self) { // Toss this work onto a background thread. let monitor = get_monitor(); - monitor.unmapper.background_unmap_info(self.info); + if let Some(unmapper) = monitor.unmapper.get() { + unmapper.background_unmap_info(self.info); + } } } diff --git a/src/runtime/monitor/src/mon/thread.rs b/src/runtime/monitor/src/mon/thread.rs index 1fee074c..d777c41b 100644 --- a/src/runtime/monitor/src/mon/thread.rs +++ b/src/runtime/monitor/src/mon/thread.rs @@ -1,18 +1,26 @@ -use std::{collections::HashMap, mem::MaybeUninit, sync::Arc}; +use std::{ + cell::OnceCell, + collections::HashMap, + mem::MaybeUninit, + ptr::NonNull, + sync::{Arc, OnceLock}, +}; -use dynlink::tls::TlsRegion; +use dynlink::{compartment::Compartment, context::Context, tls::TlsRegion}; use twizzler_abi::{ object::NULLPAGE_SIZE, syscall::{sys_spawn, sys_thread_exit, ThreadSyncSleep, UpcallTargetSpawnOption}, thread::{ExecutionState, ThreadRepr}, upcall::{UpcallFlags, UpcallInfo, UpcallMode, UpcallOptions, UpcallTarget}, }; -use twizzler_runtime_api::{ObjID, SpawnError}; +use twizzler_runtime_api::{MapFlags, ObjID, SpawnError}; +use twz_rt::RuntimeThreadControl; -use super::space::MapHandle; +use super::space::{MapHandle, MapInfo, Space}; use crate::api::MONITOR_INSTANCE_ID; mod cleaner; +pub(crate) use cleaner::ThreadCleaner; /// Stack size for the supervisor upcall stack. pub const SUPER_UPCALL_STACK_SIZE: usize = 8 * 1024 * 1024; // 8MB @@ -28,10 +36,23 @@ pub const DEFAULT_TLS_ALIGN: usize = 0x1000; // 4K /// cleaner detects when a thread has exited and performs any final thread cleanup logic. pub struct ThreadMgr { all: HashMap, - cleaner: cleaner::ThreadCleaner, + cleaner: OnceLock, +} + +impl Default for ThreadMgr { + fn default() -> Self { + Self { + all: HashMap::default(), + cleaner: OnceLock::new(), + } + } } impl ThreadMgr { + pub(super) fn set_cleaner(&mut self, cleaner: cleaner::ThreadCleaner) { + self.cleaner.set(cleaner).ok().unwrap(); + } + fn do_remove(&mut self, thread: &ManagedThread) { self.all.remove(&thread.id); } @@ -68,13 +89,50 @@ impl ThreadMgr { .map_err(|_| SpawnError::KernelError) } - fn do_spawn(start: unsafe extern "C" fn(usize) -> !, arg: usize) -> Result { - todo!() + fn do_spawn( + &mut self, + space: &mut Space, + monitor_dynlink_comp: &mut Compartment, + start: unsafe extern "C" fn(usize) -> !, + arg: usize, + ) -> Result { + let super_tls = monitor_dynlink_comp + .build_tls_region(RuntimeThreadControl::default(), |layout| unsafe { + NonNull::new(std::alloc::alloc_zeroed(layout)) + }) + .map_err(|_| SpawnError::Other)?; + let super_thread_pointer = super_tls.get_thread_pointer_value(); + let super_stack = Box::new_zeroed_slice(SUPER_UPCALL_STACK_SIZE); + let id = unsafe { + Self::spawn_thread( + start as *const () as usize, + super_stack.as_ptr() as usize, + super_thread_pointer, + arg, + )? + }; + let repr = space + .map(MapInfo { + id, + flags: MapFlags::READ, + }) + .unwrap(); + Ok(Arc::new(ManagedThreadInner { + id, + repr: ManagedThreadRepr::new(repr), + super_stack, + super_tls, + })) } /// Start a thread, running the provided Box'd closure. The thread will be running in /// monitor-mode, and will have no connection to any compartment. - pub fn start_thread(main: Box) -> Result { + pub fn start_thread( + &mut self, + space: &mut Space, + monitor_dynlink_comp: &mut Compartment, + main: Box, + ) -> Result { let main_addr = Box::into_raw(Box::new(main)) as usize; unsafe extern "C" fn managed_thread_entry(main: usize) -> ! { { @@ -85,7 +143,7 @@ impl ThreadMgr { sys_thread_exit(0); } - Self::do_spawn(managed_thread_entry, main_addr) + self.do_spawn(space, monitor_dynlink_comp, managed_thread_entry, main_addr) } } @@ -123,6 +181,7 @@ impl core::fmt::Debug for ManagedThreadInner { impl Drop for ManagedThreadInner { fn drop(&mut self) { + // TODO tracing::trace!("dropping ManagedThread {}", self.id); } } diff --git a/src/runtime/monitor/src/mon/thread/cleaner.rs b/src/runtime/monitor/src/mon/thread/cleaner.rs index 63bf7124..d2497185 100644 --- a/src/runtime/monitor/src/mon/thread/cleaner.rs +++ b/src/runtime/monitor/src/mon/thread/cleaner.rs @@ -19,7 +19,7 @@ use super::ManagedThread; use crate::mon::get_monitor; /// Tracks threads that do not exit cleanly, so their monitor-internal resources can be cleaned up. -pub(super) struct ThreadCleaner { +pub(crate) struct ThreadCleaner { thread: std::thread::JoinHandle<()>, send: Sender, inner: Pin>, @@ -45,7 +45,7 @@ enum WaitOp { impl ThreadCleaner { /// Makes a new ThreadCleaner. - pub(super) fn new() -> Self { + pub(crate) fn new() -> Self { let (send, recv) = std::sync::mpsc::channel(); let data = Arc::pin(ThreadCleanerData::default()); let inner = data.clone(); diff --git a/src/runtime/twz-rt/src/lib.rs b/src/runtime/twz-rt/src/lib.rs index 3768d13e..f0c0f7ff 100644 --- a/src/runtime/twz-rt/src/lib.rs +++ b/src/runtime/twz-rt/src/lib.rs @@ -17,7 +17,9 @@ pub(crate) mod arch; pub use arch::rr_upcall_entry; mod runtime; -pub use runtime::{set_upcall_handler, CompartmentInitInfo, RuntimeThreadControl, OUR_RUNTIME}; +pub use runtime::{ + set_upcall_handler, CompartmentInitInfo, RuntimeState, RuntimeThreadControl, OUR_RUNTIME, +}; mod error; pub use error::*; diff --git a/src/runtime/twz-rt/src/runtime.rs b/src/runtime/twz-rt/src/runtime.rs index 2b11d0e1..ff28beca 100644 --- a/src/runtime/twz-rt/src/runtime.rs +++ b/src/runtime/twz-rt/src/runtime.rs @@ -53,11 +53,14 @@ bitflags::bitflags! { } impl ReferenceRuntime { - pub(crate) fn state(&self) -> RuntimeState { + /// Returns the runtime state flags. + pub fn state(&self) -> RuntimeState { RuntimeState::from_bits_truncate(self.state.load(Ordering::SeqCst)) } - fn set_runtime_ready(&self) { + /// Set the runtime ready state. If the runtime has not been initialized, the result is + /// undefined. + pub unsafe fn set_runtime_ready(&self) { self.state .fetch_or(RuntimeState::READY.bits(), Ordering::SeqCst); } diff --git a/src/runtime/twz-rt/src/runtime/alloc.rs b/src/runtime/twz-rt/src/runtime/alloc.rs index c8b6fa8f..dbb5acfb 100644 --- a/src/runtime/twz-rt/src/runtime/alloc.rs +++ b/src/runtime/twz-rt/src/runtime/alloc.rs @@ -92,7 +92,7 @@ fn create_and_map() -> Option<(usize, ObjID)> { .ok(); if let Some(slot) = slot { - Some((slot, id)) + Some((slot.slot, id)) } else { delete_obj(id); None @@ -117,7 +117,8 @@ impl OomHandler for RuntimeOom { .is_err() { delete_obj(id); - monitor_api::monitor_rt_object_unmap(slot).unwrap(); + monitor_api::monitor_rt_object_unmap(slot, id, MapFlags::READ | MapFlags::WRITE) + .unwrap(); return Err(()); } } diff --git a/src/runtime/twz-rt/src/runtime/core.rs b/src/runtime/twz-rt/src/runtime/core.rs index 0874530f..900b690b 100644 --- a/src/runtime/twz-rt/src/runtime/core.rs +++ b/src/runtime/twz-rt/src/runtime/core.rs @@ -122,8 +122,9 @@ impl CoreRuntime for ReferenceRuntime { preinit_println!("====== {}", TLS_TEST); if self.state().contains(RuntimeState::IS_MONITOR) { self.init_slots(); + } else { + unsafe { self.set_runtime_ready() }; } - self.set_runtime_ready(); } fn post_main_hook(&self) {} diff --git a/src/runtime/twz-rt/src/runtime/object.rs b/src/runtime/twz-rt/src/runtime/object.rs index d04ab229..dcb35df4 100644 --- a/src/runtime/twz-rt/src/runtime/object.rs +++ b/src/runtime/twz-rt/src/runtime/object.rs @@ -148,7 +148,11 @@ impl ObjectHandleManager { if !self.map().contains_key(&key) { self.map().insert( key, - LocalSlot::new(monitor_api::monitor_rt_object_map(key.0, key.1).unwrap()?), + LocalSlot::new( + monitor_api::monitor_rt_object_map(key.0, key.1) + .unwrap()? + .slot, + ), ); } @@ -164,7 +168,8 @@ impl ObjectHandleManager { let key = ObjectMapKey(handle.id.into(), handle.flags); if let Some(entry) = self.map().get(&key) { if entry.refs.fetch_sub(1, atomic::Ordering::SeqCst) == 1 { - monitor_api::monitor_rt_object_unmap(entry.number).unwrap(); + monitor_api::monitor_rt_object_unmap(entry.number, handle.id, handle.flags) + .unwrap(); self.map().remove(&key); } }