diff --git a/Cargo.lock b/Cargo.lock index 212cd724..fcacb0e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3266,6 +3266,7 @@ dependencies = [ "rprompt", "tracing", "tracing-subscriber", + "twizzler", "twizzler-abi", "twizzler-futures", "twizzler-object", @@ -3674,6 +3675,14 @@ dependencies = [ "heapsize-derive", ] +[[package]] +name = "ls" +version = "0.1.0" +dependencies = [ + "clap", + "naming", +] + [[package]] name = "managed" version = "0.8.0" @@ -3949,7 +3958,7 @@ dependencies = [ name = "naming-test" version = "0.1.0" dependencies = [ - "naming", + "naming-core", ] [[package]] @@ -6061,6 +6070,8 @@ name = "twizzler" version = "0.99.0" dependencies = [ "bitflags 2.8.0", + "monitor-api", + "secgate", "thiserror 2.0.11", "twizzler-abi", "twizzler-rt-abi", diff --git a/src/abi b/src/abi index 0e5735fc..a5e1e869 160000 --- a/src/abi +++ b/src/abi @@ -1 +1 @@ -Subproject commit 0e5735fc902cb8f9327b2612703b5af0048a9fce +Subproject commit a5e1e8696d4fb5b7bf3ab906be4409a5fcc1f81a diff --git a/src/bin/bootstrap/src/main.rs b/src/bin/bootstrap/src/main.rs index fb7ceab9..e0e5e208 100644 --- a/src/bin/bootstrap/src/main.rs +++ b/src/bin/bootstrap/src/main.rs @@ -1,9 +1,9 @@ use std::process::exit; use dynlink::{ - compartment::MONITOR_COMPARTMENT_ID, + compartment::{CompartmentId, MONITOR_COMPARTMENT_ID}, context::{runtime::RuntimeInitInfo, NewCompartmentFlags}, - engines::{Backing, ContextEngine}, + engines::{Backing, ContextEngine, LoadCtx}, library::{AllowedGates, UnloadedLibrary}, symbol::LookupFlags, DynlinkError, DynlinkErrorKind, @@ -33,8 +33,10 @@ impl ContextEngine for Engine { &mut self, src: &Backing, ld: &[dynlink::engines::LoadDirective], + _comp_id: CompartmentId, + _load_ctx: &mut LoadCtx, ) -> Result, dynlink::DynlinkError> { - dynlink::engines::twizzler::load_segments(src, ld) + dynlink::engines::twizzler::load_segments(src, ld, 0.into()) } fn load_object(&mut self, unlib: &UnloadedLibrary) -> Result { @@ -74,7 +76,12 @@ fn start_runtime(_runtime_monitor: ObjID, _runtime_library: ObjID) -> ! { .unwrap(); let monitor_id = ctx - .load_library_in_compartment(monitor_comp_id, unlib, AllowedGates::PublicInclSelf) + .load_library_in_compartment( + monitor_comp_id, + unlib, + AllowedGates::PublicInclSelf, + &mut LoadCtx::default(), + ) .unwrap()[0] .lib; @@ -121,6 +128,7 @@ fn start_runtime(_runtime_monitor: ObjID, _runtime_library: ObjID) -> ! { } info.used_slots = used; + std::mem::forget(ctx); debug!("jumping to {:x}", value); (ptr)(rtinfo_ptr as usize); diff --git a/src/bin/init/Cargo.toml b/src/bin/init/Cargo.toml index d9f2c3a6..83a928eb 100644 --- a/src/bin/init/Cargo.toml +++ b/src/bin/init/Cargo.toml @@ -19,3 +19,4 @@ polling = "3.6.0" futures = "*" twizzler-futures = { path = "../../lib/twizzler-futures" } monitor-api = { path = "../../rt/monitor-api" } +twizzler = { path = "../../lib/twizzler" } diff --git a/src/bin/init/src/main.rs b/src/bin/init/src/main.rs index cbb238ba..0ac23cb2 100644 --- a/src/bin/init/src/main.rs +++ b/src/bin/init/src/main.rs @@ -143,6 +143,8 @@ fn main() { println!("If you wanted line-editing, you've come to the wrong place."); println!("To run a program, type its name."); loop { + //let mstats = monitor_api::stats().unwrap(); + //println!("{:?}", mstats); let reply = rprompt::prompt_reply_stdout("> ").unwrap(); let cmd: Vec<&str> = reply.split_whitespace().collect(); if cmd.len() == 0 { diff --git a/src/kernel/src/memory/context/virtmem.rs b/src/kernel/src/memory/context/virtmem.rs index fa9d245b..ea0e6e42 100644 --- a/src/kernel/src/memory/context/virtmem.rs +++ b/src/kernel/src/memory/context/virtmem.rs @@ -176,6 +176,13 @@ impl VirtContext { .expect("cannot get arch mapper for unattached security context")) } + pub fn print_objects(&self) { + let slots = self.slots.lock(); + for obj in &slots.objs { + logln!("{} => {:?}", obj.0, obj.1); + } + } + pub fn register_sctx(&self, sctx: ObjID, arch: ArchContext) { let mut secctx = self.secctx.lock(); if secctx.contains_key(&sctx) { @@ -715,7 +722,14 @@ pub fn page_fault(addr: VirtAddr, cause: MemoryAccessKind, flags: PageFaultFlags )); if info.obj.use_pager() { - crate::pager::get_object_page(&info.obj, page_number); + let mut obj_page_tree = info.obj.lock_page_tree(); + if matches!( + obj_page_tree.get_page(page_number, false), + PageStatus::NoPage + ) { + drop(obj_page_tree); + crate::pager::get_object_page(&info.obj, page_number); + } } let mut obj_page_tree = info.obj.lock_page_tree(); diff --git a/src/kernel/src/memory/frame.rs b/src/kernel/src/memory/frame.rs index 22e1494e..d399ee32 100755 --- a/src/kernel/src/memory/frame.rs +++ b/src/kernel/src/memory/frame.rs @@ -34,8 +34,7 @@ use alloc::vec::Vec; use core::{ - intrinsics::size_of, - mem::transmute, + mem::{size_of, transmute}, sync::atomic::{AtomicU8, Ordering}, }; diff --git a/src/kernel/src/memory/mod.rs b/src/kernel/src/memory/mod.rs index acd7e2c8..4dfdeb53 100755 --- a/src/kernel/src/memory/mod.rs +++ b/src/kernel/src/memory/mod.rs @@ -8,6 +8,7 @@ pub mod frame; pub mod pagetables; pub use arch::{PhysAddr, VirtAddr}; +use twizzler_abi::object::NULLPAGE_SIZE; use self::context::{KernelMemoryContext, UserContext}; @@ -25,6 +26,20 @@ pub struct MemoryRegion { pub kind: MemoryRegionKind, } +impl MemoryRegion { + pub fn split(mut self, len: usize) -> Option<(MemoryRegion, MemoryRegion)> { + let len = len.next_multiple_of(NULLPAGE_SIZE); + if self.length <= len { + return None; + } + let mut second = self; + second.start = self.start.offset(len).ok()?; + second.length -= len; + self.length = len; + Some((self, second)) + } +} + pub fn init(boot_info: &B) { frame::init(boot_info.memory_regions()); let kc = context::kernel_context(); diff --git a/src/kernel/src/obj/mod.rs b/src/kernel/src/obj/mod.rs index 28a0d2ba..555469db 100644 --- a/src/kernel/src/obj/mod.rs +++ b/src/kernel/src/obj/mod.rs @@ -12,7 +12,7 @@ use range::PageStatus; use twizzler_abi::{ meta::MetaFlags, object::{ObjID, MAX_SIZE}, - syscall::LifetimeType, + syscall::{CreateTieSpec, LifetimeType}, }; use self::{pages::Page, thread_sync::SleepInfo}; @@ -32,6 +32,7 @@ pub mod pages; pub mod pagevec; pub mod range; pub mod thread_sync; +pub mod ties; const OBJ_DELETED: u32 = 1; pub struct Object { @@ -42,6 +43,7 @@ pub struct Object { pin_info: Mutex, contexts: Mutex, lifetime_type: LifetimeType, + ties: Vec, } #[derive(Default)] @@ -234,7 +236,7 @@ impl Object { Some((v, token)) } - pub fn new(id: ObjID, lifetime_type: LifetimeType) -> Self { + pub fn new(id: ObjID, lifetime_type: LifetimeType, ties: &[CreateTieSpec]) -> Self { Self { id, flags: AtomicU32::new(0), @@ -242,6 +244,7 @@ impl Object { sleep_info: Mutex::new(SleepInfo::new()), pin_info: Mutex::new(PinInfo::default()), contexts: Mutex::new(ContextInfo::default()), + ties: ties.to_vec(), lifetime_type, } } @@ -250,6 +253,7 @@ impl Object { Self::new( calculate_new_id(0.into(), MetaFlags::default()), LifetimeType::Volatile, + &[], ) } @@ -277,6 +281,12 @@ impl Object { } } +impl Drop for Object { + fn drop(&mut self) { + //logln!("Dropping object {}", self.id); + } +} + #[derive(Clone, Copy, Debug)] pub enum InvalidateMode { Full, @@ -329,6 +339,7 @@ struct ObjectManager { } bitflags::bitflags! { + #[derive(Debug)] pub struct LookupFlags: u32 { const ALLOW_DELETED = 1; } @@ -368,20 +379,21 @@ impl ObjectManager { } } - fn lookup_object(&self, id: ObjID, flags: LookupFlags) -> LookupResult { + fn lookup_object(&self, id: ObjID, _flags: LookupFlags) -> LookupResult { if self.no_exist.lock().contains(&id) { return LookupResult::WasDeleted; } - self.map + if let Some(res) = self + .map .lock() .get(&id) - .map_or(LookupResult::NotFound, |obj| { - if !obj.is_pending_delete() || flags.contains(LookupFlags::ALLOW_DELETED) { - LookupResult::Found(obj.clone()) - } else { - LookupResult::WasDeleted - } - }) + .map(|obj| LookupResult::Found(obj.clone())) + { + return res; + } + ties::TIE_MGR + .lookup_object(id) + .map_or(LookupResult::NotFound, |obj| LookupResult::Found(obj)) } fn register_object(&self, obj: Arc) { @@ -390,6 +402,26 @@ impl ObjectManager { } } +pub fn scan_deleted() { + let dobjs = { + let mut om = OBJ_MANAGER.map.lock(); + om.extract_if(|_, obj| { + if obj.is_pending_delete() { + let ctx = obj.contexts.lock(); + let pin = obj.pin_info.lock(); + + ctx.contexts.len() == 0 && pin.pins.len() == 0 + } else { + false + } + }) + .collect::>() + }; + for dobj in dobjs { + ties::TIE_MGR.delete_object(dobj.1); + } +} + lazy_static::lazy_static! { static ref OBJ_MANAGER: ObjectManager = ObjectManager::new(); } @@ -401,6 +433,7 @@ pub fn lookup_object(id: ObjID, flags: LookupFlags) -> LookupResult { pub fn register_object(obj: Arc) { let om = &OBJ_MANAGER; + ties::TIE_MGR.create_object_ties(obj.id(), obj.ties.iter().map(|tie| tie.id)); om.register_object(obj); } diff --git a/src/kernel/src/obj/pages.rs b/src/kernel/src/obj/pages.rs index cec2af78..12499b04 100644 --- a/src/kernel/src/obj/pages.rs +++ b/src/kernel/src/obj/pages.rs @@ -40,8 +40,8 @@ impl Drop for Page { FrameOrWired::Frame(f) => { free_frame(f); } - // Note: this could be a wired, but freeable page (see kernel quick control objects). - FrameOrWired::Wired(_) => todo!(), + // TODO: this could be a wired, but freeable page (see kernel quick control objects). + FrameOrWired::Wired(_) => {} } } } diff --git a/src/kernel/src/obj/range.rs b/src/kernel/src/obj/range.rs index 2ff394e4..e61559d0 100644 --- a/src/kernel/src/obj/range.rs +++ b/src/kernel/src/obj/range.rs @@ -134,6 +134,7 @@ pub struct PageRangeTree { tree: NonOverlappingIntervalTree, } +#[derive(Debug)] pub enum PageStatus { Ready(PageRef, bool), NoPage, diff --git a/src/kernel/src/obj/thread_sync.rs b/src/kernel/src/obj/thread_sync.rs index f1367cc8..448c1bc5 100644 --- a/src/kernel/src/obj/thread_sync.rs +++ b/src/kernel/src/obj/thread_sync.rs @@ -3,12 +3,25 @@ use alloc::collections::BTreeMap; use twizzler_abi::syscall::{ThreadSyncFlags, ThreadSyncOp}; use super::Object; -use crate::thread::{current_thread_ref, ThreadRef}; +use crate::{ + syscall::sync::add_to_requeue, + thread::{current_thread_ref, ThreadRef}, +}; struct SleepEntry { threads: BTreeMap, } +impl Drop for SleepEntry { + fn drop(&mut self) { + while let Some(t) = self.threads.pop_first() { + if t.1.reset_sync_sleep() { + add_to_requeue(t.1); + } + } + } +} + pub struct SleepInfo { words: BTreeMap, } diff --git a/src/kernel/src/obj/ties.rs b/src/kernel/src/obj/ties.rs new file mode 100644 index 00000000..e886bec1 --- /dev/null +++ b/src/kernel/src/obj/ties.rs @@ -0,0 +1,192 @@ +use alloc::{ + collections::{btree_map::BTreeMap, btree_set::BTreeSet}, + vec::Vec, +}; +use core::fmt::Debug; + +use twizzler_abi::object::ObjID; + +use super::ObjectRef; +use crate::mutex::Mutex; + +pub struct TiesStatic { + inner: Mutex>, +} + +impl TiesStatic { + pub const fn new() -> Self { + Self { + inner: Mutex::new(Ties::new()), + } + } + + pub fn delete_object(&self, obj: ObjectRef) { + self.inner.lock().delete_value(obj.id(), obj); + } + + pub fn create_object_ties(&self, created_id: ObjID, ties: impl IntoIterator) { + let ties = ties.into_iter().collect::>(); + if ties.is_empty() { + return; + } + self.inner.lock().insert_ties(created_id, ties); + } + + pub fn lookup_object(&self, id: ObjID) -> Option { + self.inner.lock().lookup_deleted(id) + } +} + +pub(super) static TIE_MGR: TiesStatic = TiesStatic::new(); + +#[derive(Default)] +struct Ties { + ties: BTreeMap>, + pending_delete: BTreeMap, +} + +impl Ties { + const fn new() -> Self { + Self { + ties: BTreeMap::new(), + pending_delete: BTreeMap::new(), + } + } + + pub fn insert_ties(&mut self, obj: K, deps: impl IntoIterator) { + for val in deps.into_iter() { + self.ties.entry(obj).or_default().insert(val); + } + } + + fn remove_tie(&mut self, obj: K, tie: K) { + self.ties.entry(obj).or_default().remove(&tie); + } + + fn remove_all_ties(&mut self, obj: K) { + self.ties.entry(obj).or_default().clear(); + } + + fn delete_ties(&mut self, target: K) { + for (objid, set) in self.ties.iter_mut() { + set.remove(&target); + if set.is_empty() { + self.pending_delete.remove(&objid); + } + } + } + + pub fn delete_value(&mut self, id: K, val: V) { + self.delete_ties(id); + let _ = self + .ties + .extract_if(|_, val| val.is_empty()) + .collect::>(); + if self.ties.get(&id).map_or(0, |set| set.len()) > 0 { + self.pending_delete.insert(id, val); + } + } +} + +impl Ties { + pub fn lookup_deleted(&self, id: K) -> Option { + self.pending_delete.get(&id).cloned() + } +} + +#[cfg(test)] +mod tests { + use alloc::sync::Arc; + use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; + + use twizzler_kernel_macros::kernel_test; + + use super::*; + + struct Bar { + id: u32, + dest: Arc, + } + + impl Debug for Bar { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Bar") + .field("id", &self.id) + .finish_non_exhaustive() + } + } + + impl Drop for Bar { + fn drop(&mut self) { + self.dest.store(true, Ordering::SeqCst); + } + } + + static BAR_ID: AtomicU32 = AtomicU32::new(1); + impl Default for Bar { + fn default() -> Self { + Self::new( + Arc::new(AtomicBool::default()), + BAR_ID.fetch_add(1, core::sync::atomic::Ordering::SeqCst), + ) + } + } + + impl Bar { + fn new(dest: Arc, id: u32) -> Self { + Self { dest, id } + } + + fn tracker(&self) -> BarTracker { + BarTracker { + id: self.id, + tracker: self.dest.clone(), + } + } + } + + struct BarTracker { + id: u32, + tracker: Arc, + } + + impl BarTracker { + fn is_destroyed(&self) -> bool { + self.tracker.load(Ordering::SeqCst) + } + } + + fn test_ties(ties: &mut Ties) { + let x = Bar::default(); + let x_tracker = x.tracker(); + let y = Bar::default(); + let y_tracker = y.tracker(); + let z = Bar::default(); + let z_tracker = z.tracker(); + let zz = Bar::default(); + let zz_tracker = zz.tracker(); + ties.insert_ties(y.id, [x.id]); + ties.insert_ties(z.id, [y.id]); + ties.insert_ties(zz.id, [y.id]); + + ties.delete_value(z.id, z); + ties.delete_value(y.id, y); + ties.delete_value(zz.id, zz); + + assert!(!x_tracker.is_destroyed()); + assert!(!y_tracker.is_destroyed()); + assert!(z_tracker.is_destroyed()); + assert!(zz_tracker.is_destroyed()); + + ties.delete_value(x.id, x); + + assert!(x_tracker.is_destroyed()); + assert!(y_tracker.is_destroyed()); + } + + #[kernel_test] + fn test_ties_kt() { + let mut ties = Ties::default(); + test_ties(&mut ties); + } +} diff --git a/src/kernel/src/pager.rs b/src/kernel/src/pager.rs index 19e46fc3..4780b1b8 100644 --- a/src/kernel/src/pager.rs +++ b/src/kernel/src/pager.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use inflight::InflightManager; use request::ReqKind; -use twizzler_abi::object::ObjID; +use twizzler_abi::object::{ObjID, NULLPAGE_SIZE}; use crate::{ memory::{MemoryRegion, MemoryRegionKind}, @@ -20,20 +20,58 @@ mod request; pub use queues::init_pager_queue; pub use request::Request; -static PAGER_MEMORY: Once = Once::new(); +static PAGER_MEMORY: Once> = Once::new(); + +const MAX_RESERVE_KERNEL: usize = 1024 * 1024 * 1024; // 1G pub fn pager_select_memory_regions(regions: &[MemoryRegion]) -> Vec { let mut fa_regions = Vec::new(); + let mut pager_regions = Vec::new(); + let total = regions.iter().fold(0, |acc, val| { + if val.kind == MemoryRegionKind::UsableRam { + acc + val.length + } else { + acc + } + }); + let mut reserved = 0; for reg in regions { if matches!(reg.kind, MemoryRegionKind::UsableRam) { // TODO: don't just pick one, and don't just pick the first one. - if PAGER_MEMORY.poll().is_none() { - PAGER_MEMORY.call_once(|| *reg); + if reserved >= MAX_RESERVE_KERNEL { + pager_regions.push(*reg); + } else if reg.length > NULLPAGE_SIZE * 2 { + let (first, second) = (*reg).split(reg.length / 2).unwrap(); + reserved += first.length; + fa_regions.push(first); + pager_regions.push(second); } else { + reserved += reg.length; fa_regions.push(*reg); } } } + let total_pager = pager_regions.iter().fold(0, |acc, val| { + if val.kind == MemoryRegionKind::UsableRam { + acc + val.length + } else { + acc + } + }); + let total_kernel = fa_regions.iter().fold(0, |acc, val| { + if val.kind == MemoryRegionKind::UsableRam { + acc + val.length + } else { + acc + } + }); + logln!( + "[kernel::pager] split memory: {} MB pager / {} MB kernel", + total_pager / (1024 * 1024), + total_kernel / (1024 * 1024) + ); + assert_eq!(total, total_pager + total_kernel); + PAGER_MEMORY.call_once(|| pager_regions); fa_regions } diff --git a/src/kernel/src/pager/queues.rs b/src/kernel/src/pager/queues.rs index 7abf07ce..6f60534c 100644 --- a/src/kernel/src/pager/queues.rs +++ b/src/kernel/src/pager/queues.rs @@ -75,7 +75,7 @@ pub(super) fn pager_request_handler_main() { PagerRequest::Ready => { let reg = PAGER_MEMORY .poll() - .map(|pm| (pm.start.raw(), pm.length)) + .map(|pm| (pm[0].start.raw(), pm[0].length)) .unwrap_or((0, 0)); INFLIGHT_MGR.lock().set_ready(); CompletionToPager::new(twizzler_abi::pager::PagerCompletionData::DramPages( @@ -121,7 +121,7 @@ pub(super) fn pager_compl_handler_main() { } } twizzler_abi::pager::KernelCompletionData::ObjectInfoCompletion(obj_info) => { - let obj = Object::new(obj_info.obj_id, LifetimeType::Persistent); + let obj = Object::new(obj_info.obj_id, LifetimeType::Persistent, &[]); crate::obj::register_object(Arc::new(obj)); INFLIGHT_MGR.lock().cmd_ready(obj_info.obj_id, false); } diff --git a/src/kernel/src/syscall/mod.rs b/src/kernel/src/syscall/mod.rs index 70d9b176..07d5c056 100644 --- a/src/kernel/src/syscall/mod.rs +++ b/src/kernel/src/syscall/mod.rs @@ -228,6 +228,19 @@ pub fn syscall_entry(context: &mut T) { // logln!("RECEIVED SYSCALL {}", context.num()); match context.num().into() { Syscall::ObjectUnmap => { + let hi = context.arg0(); + let lo = context.arg1(); + let slot = context.arg2::() as usize; + let handle = ObjID::from_parts([hi, lo]); + let handle = if handle.raw() == 0 { + None + } else { + Some(handle) + }; + let result = object::sys_object_unmap(handle, slot); + crate::obj::scan_deleted(); + let (code, val) = convert_result_to_codes(result, zero_ok, one_err); + context.set_return_values(code, val); context.set_return_values(1u64, 0u64); } Syscall::Null => { diff --git a/src/kernel/src/syscall/object.rs b/src/kernel/src/syscall/object.rs index 9585ac5e..7a6a9418 100644 --- a/src/kernel/src/syscall/object.rs +++ b/src/kernel/src/syscall/object.rs @@ -7,17 +7,17 @@ use twizzler_abi::{ meta::MetaFlags, object::{ObjID, Protections}, syscall::{ - CreateTieSpec, HandleType, MapFlags, MapInfo, NewHandleError, ObjectControlCmd, - ObjectCreate, ObjectCreateError, ObjectMapError, ObjectReadMapError, ObjectSource, - SctxAttachError, + CreateTieSpec, DeleteFlags, HandleType, MapFlags, MapInfo, NewHandleError, + ObjectControlCmd, ObjectCreate, ObjectCreateError, ObjectCreateFlags, ObjectMapError, + ObjectReadMapError, ObjectSource, SctxAttachError, }, }; use crate::{ arch::context::ArchContext, - memory::context::{Context, ContextRef}, + memory::context::{virtmem::Slot, Context, ContextRef, UserContext}, mutex::Mutex, - obj::{calculate_new_id, LookupFlags, Object, ObjectRef}, + obj::{calculate_new_id, lookup_object, LookupFlags, Object, ObjectRef}, once::Once, security::get_sctx, thread::{current_memory_context, current_thread_ref}, @@ -26,12 +26,15 @@ use crate::{ pub fn sys_object_create( create: &ObjectCreate, srcs: &[ObjectSource], - _ties: &[CreateTieSpec], + ties: &[CreateTieSpec], ) -> Result { let id = calculate_new_id(create.kuid, MetaFlags::default()); - let obj = Arc::new(Object::new(id, create.lt)); + let obj = Arc::new(Object::new(id, create.lt, ties)); if obj.use_pager() { crate::pager::create_object(id); + if create.flags.contains(ObjectCreateFlags::DELETE) { + object_ctrl(id, ObjectControlCmd::Delete(DeleteFlags::empty())); + } return Ok(obj.id()); } for src in srcs { @@ -50,6 +53,9 @@ pub fn sys_object_create( } } crate::obj::register_object(obj.clone()); + if create.flags.contains(ObjectCreateFlags::DELETE) { + object_ctrl(id, ObjectControlCmd::Delete(DeleteFlags::empty())); + } Ok(obj.id()) } @@ -78,6 +84,16 @@ pub fn sys_object_map( Ok(slot) } +pub fn sys_object_unmap(handle: Option, slot: usize) -> Result { + let vm = if let Some(handle) = handle { + get_vmcontext_from_handle(handle).ok_or(0u64)? + } else { + current_memory_context().unwrap() + }; + vm.remove_object(Slot::try_from(slot).map_err(|_| 0u64)?); + Ok(0) +} + pub fn sys_object_readmap(handle: ObjID, slot: usize) -> Result { let vm = if handle.raw() == 0 { current_memory_context().unwrap() @@ -201,7 +217,15 @@ pub fn object_ctrl(id: ObjID, cmd: ObjectControlCmd) -> (u64, u64) { crate::pager::sync_object(id); } ObjectControlCmd::Delete(_) => { - crate::pager::del_object(id); + let mut invoke_pager = true; + if let Some(obj) = lookup_object(id, LookupFlags::empty()).ok_or(()).ok() { + invoke_pager = obj.use_pager(); + obj.mark_for_delete(); + } + if invoke_pager { + crate::pager::del_object(id); + } + crate::obj::scan_deleted(); } _ => {} } diff --git a/src/lib/dynlink/src/context/load.rs b/src/lib/dynlink/src/context/load.rs index a1751f05..8d2e2818 100644 --- a/src/lib/dynlink/src/context/load.rs +++ b/src/lib/dynlink/src/context/load.rs @@ -14,7 +14,7 @@ use super::{Context, LoadedOrUnloaded}; use crate::{ compartment::{Compartment, CompartmentId}, context::NewCompartmentFlags, - engines::{LoadDirective, LoadFlags}, + engines::{LoadCtx, LoadDirective, LoadFlags}, library::{AllowedGates, Library, LibraryId, SecgateInfo, UnloadedLibrary}, tls::TlsModule, DynlinkError, DynlinkErrorKind, HeaderError, @@ -129,6 +129,7 @@ impl Context { unlib: UnloadedLibrary, idx: NodeIndex, allowed_gates: AllowedGates, + load_ctx: &mut LoadCtx, ) -> Result { let backing = self.engine.load_object(&unlib)?; let elf = backing.get_elf()?; @@ -225,7 +226,9 @@ impl Context { .collect(); // call the system impl to actually map things - let backings = self.engine.load_segments(&backing, &directives)?; + let backings = self + .engine + .load_segments(&backing, &directives, comp_id, load_ctx)?; if backings.is_empty() { return Err(DynlinkErrorKind::NewBackingFail.into()); } @@ -341,6 +344,7 @@ impl Context { root_unlib: UnloadedLibrary, idx: NodeIndex, allowed_gates: AllowedGates, + load_ctx: &mut LoadCtx, ) -> Result, DynlinkError> { let root_comp_name = self.get_compartment(comp_id)?.name.clone(); debug!( @@ -350,7 +354,7 @@ impl Context { let mut ids = vec![]; // First load the main library. let lib = self - .load(comp_id, root_unlib.clone(), idx, allowed_gates) + .load(comp_id, root_unlib.clone(), idx, allowed_gates, load_ctx) .map_err(|e| { DynlinkError::new_collect( DynlinkErrorKind::LibraryLoadFail { @@ -361,6 +365,7 @@ impl Context { })?; ids.push((&lib).into()); + tracing::debug!("enumerating deps for {}", lib); // Second, go through deps let deps = self.enumerate_needed(&lib).map_err(|e| { DynlinkError::new_collect( @@ -424,7 +429,7 @@ impl Context { AllowedGates::Public }; let mut recs = self - .load_library(load_comp, dep_unlib.clone(), idx, allowed_gates) + .load_library(load_comp, dep_unlib.clone(), idx, allowed_gates, load_ctx) .map_err(|e| { DynlinkError::new_collect( DynlinkErrorKind::LibraryLoadFail { @@ -448,6 +453,7 @@ impl Context { deps, )?; + tracing::debug!("HERE"); assert_eq!(idx, lib.idx); self.library_deps[idx] = LoadedOrUnloaded::Loaded(lib); Ok(ids) @@ -459,6 +465,7 @@ impl Context { comp_id: CompartmentId, unlib: UnloadedLibrary, allowed_gates: AllowedGates, + load_ctx: &mut LoadCtx, ) -> Result, DynlinkError> { let idx = self.add_library(unlib.clone()); // Step 1: insert into the compartment's library names. @@ -474,6 +481,6 @@ impl Context { comp.library_names.insert(unlib.name.clone(), idx); // Step 2: load the library. This call recurses on dependencies. - self.load_library(comp_id, unlib.clone(), idx, allowed_gates) + self.load_library(comp_id, unlib.clone(), idx, allowed_gates, load_ctx) } } diff --git a/src/lib/dynlink/src/engines/mod.rs b/src/lib/dynlink/src/engines/mod.rs index fe801c5e..ef6dab98 100644 --- a/src/lib/dynlink/src/engines/mod.rs +++ b/src/lib/dynlink/src/engines/mod.rs @@ -1,11 +1,18 @@ pub mod twizzler; +use std::collections::HashMap; + use elf::{endian::NativeEndian, ParseError}; use twizzler_abi::object::{MAX_SIZE, NULLPAGE_SIZE}; +use twizzler_object::ObjID; use twizzler_rt_abi::object::{self, ObjectHandle}; use crate::{compartment::CompartmentId, library::UnloadedLibrary, DynlinkError}; +#[derive(Default)] +pub struct LoadCtx { + pub set: HashMap, +} /// System-specific implementation functions for the dynamic linker, mostly /// involving loading objects. pub trait ContextEngine { @@ -14,6 +21,8 @@ pub trait ContextEngine { &mut self, src: &Backing, ld: &[LoadDirective], + comp_id: CompartmentId, + load_ctx: &mut LoadCtx, ) -> Result, DynlinkError>; /// Load a single object, based on the given unloaded library. @@ -50,8 +59,15 @@ pub struct Backing { obj: object::ObjectHandle, } +impl Drop for Backing { + fn drop(&mut self) { + tracing::debug!("drop backing: {:?}: {:p}", self.obj.id(), self.obj.start()); + } +} + impl Backing { pub fn new(inner: ObjectHandle) -> Self { + tracing::debug!("new backing: {:?}: {:p}", inner.id(), inner.start()); Self { obj: inner } } } diff --git a/src/lib/dynlink/src/engines/twizzler.rs b/src/lib/dynlink/src/engines/twizzler.rs index bb3a1efb..abf05403 100644 --- a/src/lib/dynlink/src/engines/twizzler.rs +++ b/src/lib/dynlink/src/engines/twizzler.rs @@ -2,9 +2,11 @@ use itertools::{Either, Itertools}; use twizzler_abi::{ object::{MAX_SIZE, NULLPAGE_SIZE}, syscall::{ - sys_object_create, BackingType, LifetimeType, ObjectCreate, ObjectCreateFlags, ObjectSource, + sys_object_create, BackingType, CreateTieFlags, CreateTieSpec, LifetimeType, ObjectCreate, + ObjectCreateFlags, ObjectSource, }, }; +use twizzler_object::ObjID; use twizzler_rt_abi::object::MapFlags; use super::{Backing, LoadDirective, LoadFlags}; @@ -18,12 +20,16 @@ fn within_object(slot: usize, addr: usize) -> bool { /// Load segments according to Twizzler requirements. Helper function for implementing a /// ContextEngine. -pub fn load_segments(src: &Backing, ld: &[LoadDirective]) -> Result, DynlinkError> { +pub fn load_segments( + src: &Backing, + ld: &[LoadDirective], + instance: ObjID, +) -> Result, DynlinkError> { let create_spec = ObjectCreate::new( BackingType::Normal, LifetimeType::Volatile, None, - ObjectCreateFlags::empty(), + ObjectCreateFlags::DELETE, ); let build_copy_cmd = |directive: &LoadDirective| { @@ -106,11 +112,26 @@ pub fn load_segments(src: &Backing, ld: &[LoadDirective]) -> Result let data_cmds = DynlinkError::collect(DynlinkErrorKind::NewBackingFail, data_cmds)?; let text_cmds = DynlinkError::collect(DynlinkErrorKind::NewBackingFail, text_cmds)?; - let data_id = sys_object_create(create_spec, &data_cmds, &[]) - .map_err(|_| DynlinkErrorKind::NewBackingFail)?; + let data_id = sys_object_create( + create_spec, + &data_cmds, + &[CreateTieSpec::new(instance, CreateTieFlags::empty())], + ) + .map_err(|_| DynlinkErrorKind::NewBackingFail)?; - let text_id = sys_object_create(create_spec, &text_cmds, &[]) - .map_err(|_| DynlinkErrorKind::NewBackingFail)?; + let text_id = sys_object_create( + create_spec, + &text_cmds, + &[CreateTieSpec::new(instance, CreateTieFlags::empty())], + ) + .map_err(|_| DynlinkErrorKind::NewBackingFail)?; + + tracing::trace!( + "mapped segments in instance {} to {}, {}", + instance, + text_id, + data_id + ); #[allow(deprecated)] let (text_handle, data_handle) = twizzler_rt_abi::object::twz_rt_map_two_objects( diff --git a/src/lib/dynlink/src/library.rs b/src/lib/dynlink/src/library.rs index 765eb9f4..52840010 100644 --- a/src/lib/dynlink/src/library.rs +++ b/src/lib/dynlink/src/library.rs @@ -407,7 +407,7 @@ impl Debug for Library { impl Drop for Library { fn drop(&mut self) { - tracing::debug!("dynlink: drop library: {:?}", self); + //tracing::warn!("dynlink: drop library: {:?}", self); } } diff --git a/src/lib/twizzler-abi/src/syscall/create.rs b/src/lib/twizzler-abi/src/syscall/create.rs index a8f7a2c6..74569aab 100644 --- a/src/lib/twizzler-abi/src/syscall/create.rs +++ b/src/lib/twizzler-abi/src/syscall/create.rs @@ -69,6 +69,7 @@ bitflags! { /// Flags to pass to the object create system call. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)] pub struct ObjectCreateFlags: u32 { + const DELETE = 1; } } diff --git a/src/lib/twizzler/Cargo.toml b/src/lib/twizzler/Cargo.toml index 2802bc6e..3215b9e1 100644 --- a/src/lib/twizzler/Cargo.toml +++ b/src/lib/twizzler/Cargo.toml @@ -8,3 +8,5 @@ bitflags = "2" thiserror = "2" twizzler-rt-abi = "0.99" twizzler-abi = { path = "../../lib/twizzler-abi" } +monitor-api = { path = "../../rt/monitor-api" } +secgate = { path = "../../lib/secgate" } diff --git a/src/lib/twizzler/src/collections/vec.rs b/src/lib/twizzler/src/collections/vec.rs index cd54034a..0bc2eb2c 100644 --- a/src/lib/twizzler/src/collections/vec.rs +++ b/src/lib/twizzler/src/collections/vec.rs @@ -289,6 +289,18 @@ pub struct VecObject { obj: Object>, } +impl From>> for VecObject { + fn from(value: Object>) -> Self { + Self { obj: value } + } +} + +impl VecObject { + pub fn object(&self) -> &Object> { + &self.obj + } +} + impl VecObject { pub fn push_sc(&mut self, val: T) -> crate::tx::Result<()> { let tx = self.obj.clone().tx()?; diff --git a/src/lib/twizzler/src/lib.rs b/src/lib/twizzler/src/lib.rs index 7249b2fd..8368bf31 100644 --- a/src/lib/twizzler/src/lib.rs +++ b/src/lib/twizzler/src/lib.rs @@ -9,3 +9,5 @@ pub mod marker; pub mod object; pub mod ptr; pub mod tx; + +mod pager; diff --git a/src/lib/twizzler/src/object/builder.rs b/src/lib/twizzler/src/object/builder.rs index 9e031e2b..bd5a357b 100644 --- a/src/lib/twizzler/src/object/builder.rs +++ b/src/lib/twizzler/src/object/builder.rs @@ -1,7 +1,7 @@ use std::{alloc::AllocError, marker::PhantomData, mem::MaybeUninit}; use thiserror::Error; -use twizzler_abi::syscall::{ObjectCreate, ObjectCreateError}; +use twizzler_abi::syscall::{LifetimeType, ObjectCreate, ObjectCreateError}; use twizzler_rt_abi::object::{MapError, MapFlags}; use super::Object; @@ -36,6 +36,12 @@ impl ObjectBuilder { _pd: PhantomData, } } + + /// Make the object persistent. + pub fn persist(mut self) -> Self { + self.spec.lt = LifetimeType::Persistent; + self + } } impl ObjectBuilder { @@ -51,9 +57,12 @@ impl ObjectBuilder { { let id = twizzler_abi::syscall::sys_object_create(self.spec, &[], &[]) .map_err(CreateError::from)?; + let mut flags = MapFlags::READ | MapFlags::WRITE; + if self.spec.lt == LifetimeType::Persistent { + flags.insert(MapFlags::PERSIST); + } let mu_object = unsafe { - Object::>::map_unchecked(id, MapFlags::READ | MapFlags::WRITE) - .map_err(CreateError::from) + Object::>::map_unchecked(id, flags).map_err(CreateError::from) }?; let object = ctor(mu_object.tx()?)?; object.commit() diff --git a/src/lib/twizzler/src/pager.rs b/src/lib/twizzler/src/pager.rs new file mode 100644 index 00000000..da1579e4 --- /dev/null +++ b/src/lib/twizzler/src/pager.rs @@ -0,0 +1,33 @@ +use std::sync::OnceLock; + +use monitor_api::CompartmentHandle; +use secgate::DynamicSecGate; +use twizzler_abi::object::ObjID; + +struct PagerAPI { + _handle: &'static CompartmentHandle, + full_sync_call: DynamicSecGate<'static, (ObjID,), ()>, +} + +static PAGER_API: OnceLock = OnceLock::new(); + +fn pager_api() -> &'static PagerAPI { + PAGER_API.get_or_init(|| { + let handle = Box::leak(Box::new( + CompartmentHandle::lookup("pager-srv").expect("failed to open pager compartment"), + )); + let full_sync_call = unsafe { + handle + .dynamic_gate::<(ObjID,), ()>("full_object_sync") + .expect("failed to find full object sync gate call") + }; + PagerAPI { + _handle: handle, + full_sync_call, + } + }) +} + +pub fn sync_object(id: ObjID) { + (pager_api().full_sync_call)(id).unwrap() +} diff --git a/src/lib/twizzler/src/ptr/resolved.rs b/src/lib/twizzler/src/ptr/resolved.rs index c06a44e7..71287430 100644 --- a/src/lib/twizzler/src/ptr/resolved.rs +++ b/src/lib/twizzler/src/ptr/resolved.rs @@ -192,7 +192,7 @@ impl<'a, T> RefSlice<'a, T> { unsafe { core::slice::from_raw_parts(raw_ptr, self.len) } } - pub fn get(&self, idx: usize) -> Option> { + pub fn get(&self, idx: usize) -> Option> { let ptr = self.as_slice().get(idx)?; Some(unsafe { Ref::from_raw_parts(ptr, self.ptr.handle) }) } diff --git a/src/lib/twizzler/src/tx/object.rs b/src/lib/twizzler/src/tx/object.rs index 2b730c40..9331c694 100644 --- a/src/lib/twizzler/src/tx/object.rs +++ b/src/lib/twizzler/src/tx/object.rs @@ -27,6 +27,10 @@ impl TxObject { pub fn commit(self) -> Result> { let handle = self.handle; + let flags = handle.map_flags(); + if flags.contains(MapFlags::PERSIST) { + crate::pager::sync_object(handle.id()); + } let new_obj = unsafe { Object::map_unchecked(handle.id(), MapFlags::READ | MapFlags::WRITE) }?; // TODO: commit tx diff --git a/src/rt/monitor-api/src/lib.rs b/src/rt/monitor-api/src/lib.rs index 6c5ca41b..b259c842 100644 --- a/src/rt/monitor-api/src/lib.rs +++ b/src/rt/monitor-api/src/lib.rs @@ -584,7 +584,7 @@ bitflags::bitflags! { } /// Contains raw mapping addresses, for use when translating to object handles for the runtime. -#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq)] +#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Debug)] pub struct MappedObjectAddrs { pub slot: usize, pub start: usize, diff --git a/src/rt/monitor/secapi/gates.rs b/src/rt/monitor/secapi/gates.rs index c959e27b..1764be61 100644 --- a/src/rt/monitor/secapi/gates.rs +++ b/src/rt/monitor/secapi/gates.rs @@ -318,6 +318,35 @@ pub fn monitor_rt_object_map( } } +#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))] +#[cfg_attr( + not(feature = "secgate-impl"), + secgate::secure_gate(options(info, api)) +)] +pub fn monitor_rt_object_pair_map( + info: &secgate::GateCallInfo, + id: ObjID, + flags: twizzler_rt_abi::object::MapFlags, + id2: ObjID, + flags2: twizzler_rt_abi::object::MapFlags, +) -> Result<(crate::MappedObjectAddrs, crate::MappedObjectAddrs), MapError> { + use crate::mon::space::MapInfo; + if unsafe { !__is_monitor_ready() } { + return Err(MapError::Other); + } + let monitor = crate::mon::get_monitor(); + monitor + .map_pair( + info.source_context().unwrap_or(MONITOR_INSTANCE_ID), + MapInfo { id, flags }, + MapInfo { + id: id2, + flags: flags2, + }, + ) + .map(|(one, two)| (one.addrs(), two.addrs())) +} + #[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))] #[cfg_attr( not(feature = "secgate-impl"), diff --git a/src/rt/monitor/src/dlengine.rs b/src/rt/monitor/src/dlengine.rs index 7e7745b6..d633e633 100644 --- a/src/rt/monitor/src/dlengine.rs +++ b/src/rt/monitor/src/dlengine.rs @@ -1,24 +1,46 @@ use dynlink::{ - compartment::MONITOR_COMPARTMENT_ID, - engines::{Backing, ContextEngine}, + compartment::{CompartmentId, MONITOR_COMPARTMENT_ID}, + engines::{Backing, ContextEngine, LoadCtx}, library::UnloadedLibrary, DynlinkError, DynlinkErrorKind, }; use twizzler_abi::{ aux::KernelInitInfo, object::{MAX_SIZE, NULLPAGE_SIZE}, + syscall::{BackingType, ObjectCreate, ObjectCreateFlags}, }; use twizzler_rt_abi::object::{MapFlags, ObjID}; pub struct Engine; +fn get_new_sctx_instance(_sctx: ObjID) -> ObjID { + // TODO: we don't support real sctx instances yet + twizzler_abi::syscall::sys_object_create( + ObjectCreate::new( + BackingType::Normal, + twizzler_abi::syscall::LifetimeType::Volatile, + None, + ObjectCreateFlags::empty(), + ), + &[], + &[], + ) + .unwrap() +} + impl ContextEngine for Engine { fn load_segments( &mut self, src: &Backing, ld: &[dynlink::engines::LoadDirective], + comp_id: CompartmentId, + load_ctx: &mut LoadCtx, ) -> Result, dynlink::DynlinkError> { - dynlink::engines::twizzler::load_segments(src, ld) + let instance = *load_ctx + .set + .entry(comp_id) + .or_insert_with(|| get_new_sctx_instance(1.into())); + dynlink::engines::twizzler::load_segments(src, ld, instance) } fn load_object(&mut self, unlib: &UnloadedLibrary) -> Result { diff --git a/src/rt/monitor/src/main.rs b/src/rt/monitor/src/main.rs index 39658012..7b74f340 100644 --- a/src/rt/monitor/src/main.rs +++ b/src/rt/monitor/src/main.rs @@ -9,7 +9,7 @@ use dynlink::context::NewCompartmentFlags; use miette::IntoDiagnostic; use monitor_api::{CompartmentFlags, CompartmentHandle, CompartmentLoader}; use tracing::{debug, info, warn, Level}; -use tracing_subscriber::{fmt::format::FmtSpan, FmtSubscriber}; +use tracing_subscriber::FmtSubscriber; use twizzler_abi::object::NULLPAGE_SIZE; use twizzler_rt_abi::object::MapFlags; @@ -36,7 +36,6 @@ pub fn main() { let subscriber = FmtSubscriber::builder() .with_max_level(Level::INFO) .with_target(false) - .with_span_events(FmtSpan::ACTIVE) .without_time() .finish(); diff --git a/src/rt/monitor/src/mon/compartment.rs b/src/rt/monitor/src/mon/compartment.rs index d2304266..f6870dbf 100644 --- a/src/rt/monitor/src/mon/compartment.rs +++ b/src/rt/monitor/src/mon/compartment.rs @@ -197,6 +197,7 @@ impl CompartmentMgr { impl super::Monitor { /// Get CompartmentInfo for this caller. Note that this will write to the compartment-thread's /// simple buffer. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn get_compartment_info( &self, instance: ObjID, @@ -230,6 +231,7 @@ impl super::Monitor { /// Get CompartmentInfo for this caller. Note that this will write to the compartment-thread's /// simple buffer. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn get_compartment_gate_address( &self, instance: ObjID, @@ -261,6 +263,7 @@ impl super::Monitor { } /// Open a compartment handle for this caller compartment. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn get_compartment_handle(&self, caller: ObjID, compartment: ObjID) -> Option { let (_, _, ref mut comps, _, _, ref mut ch) = *self.locks.lock(ThreadKey::get().unwrap()); let comp = comps.get_mut(compartment)?; @@ -278,6 +281,7 @@ impl super::Monitor { } /// Open a compartment handle for this caller compartment. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn lookup_compartment( &self, instance: ObjID, @@ -297,6 +301,7 @@ impl super::Monitor { ) } + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn compartment_wait(&self, caller: ObjID, desc: Option, flags: u64) -> u64 { let Some(instance) = ({ let comphandles = self._compartment_handles.write(ThreadKey::get().unwrap()); @@ -312,6 +317,7 @@ impl super::Monitor { } /// Open a handle to the n'th dependency compartment of a given compartment. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn get_compartment_deps( &self, caller: ObjID, @@ -331,6 +337,7 @@ impl super::Monitor { } /// Load a new compartment with a root library ID, and return a compartment handle. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn load_compartment( &self, caller: ObjID, @@ -403,6 +410,7 @@ impl super::Monitor { } /// Drop a compartment handle. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn drop_compartment_handle(&self, caller: ObjID, desc: Descriptor) { let (_, _, ref mut cmgr, ref mut dynlink, _, ref mut comp_handles) = *self.locks.lock(ThreadKey::get().unwrap()); @@ -414,6 +422,7 @@ impl super::Monitor { cmgr.process_cleanup_queue(&mut *dynlink); } + #[tracing::instrument(skip(self, f), level = tracing::Level::DEBUG)] pub fn update_compartment_flags( &self, instance: ObjID, @@ -423,22 +432,27 @@ impl super::Monitor { cmp.update_compartment_flags(instance, f) } + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn load_compartment_flags(&self, instance: ObjID) -> u64 { - let cmp = self.comp_mgr.read(ThreadKey::get().unwrap()); + let cmp = self.comp_mgr.write(ThreadKey::get().unwrap()); cmp.load_compartment_flags(instance) } + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn wait_for_compartment_state_change(&self, instance: ObjID, state: u64) { - let cmp = self.comp_mgr.read(ThreadKey::get().unwrap()); - let Some(sl) = cmp.wait_for_compartment_state_change(instance, state) else { - return; + let sl = { + let cmp = self.comp_mgr.write(ThreadKey::get().unwrap()); + let Some(sl) = cmp.wait_for_compartment_state_change(instance, state) else { + return; + }; + + if sl.ready() { + return; + } + drop(cmp); + sl }; - if sl.ready() { - return; - } - drop(cmp); - let _ = sys_thread_sync(&mut [ThreadSync::new_sleep(sl)], None); } } diff --git a/src/rt/monitor/src/mon/compartment/loader.rs b/src/rt/monitor/src/mon/compartment/loader.rs index 0f7fd7e8..dee8af8e 100644 --- a/src/rt/monitor/src/mon/compartment/loader.rs +++ b/src/rt/monitor/src/mon/compartment/loader.rs @@ -3,12 +3,12 @@ use std::{collections::HashSet, ffi::CStr, ptr::null_mut}; use dynlink::{ compartment::CompartmentId, context::{Context, LoadIds, NewCompartmentFlags}, + engines::LoadCtx, library::{AllowedGates, LibraryId, UnloadedLibrary}, DynlinkError, }; use happylock::ThreadKey; use monitor_api::SharedCompConfig; -use twizzler_abi::syscall::{BackingType, ObjectCreate, ObjectCreateFlags}; use twizzler_rt_abi::{ core::{CtorSet, RuntimeInfo}, object::{MapFlags, ObjID}, @@ -107,21 +107,6 @@ impl Drop for RunCompLoader { const RUNTIME_NAME: &str = "libtwz_rt.so"; -fn get_new_sctx_instance(_sctx: ObjID) -> ObjID { - // TODO: we don't support real sctx instances yet - twizzler_abi::syscall::sys_object_create( - ObjectCreate::new( - BackingType::Normal, - twizzler_abi::syscall::LifetimeType::Volatile, - None, - ObjectCreateFlags::empty(), - ), - &[], - &[], - ) - .unwrap() -} - impl RunCompLoader { // the runtime library might be in the dependency tree from the shared object files. // if not, we need to insert it. @@ -129,14 +114,19 @@ impl RunCompLoader { dynlink: &mut Context, root_id: LibraryId, comp_id: CompartmentId, + load_ctx: &mut LoadCtx, ) -> Result { if let Some(id) = dynlink.lookup_library(comp_id, RUNTIME_NAME) { return Ok(id); } let rt_unlib = UnloadedLibrary::new(RUNTIME_NAME); - let loads = - dynlink.load_library_in_compartment(comp_id, rt_unlib, AllowedGates::Private)?; + let loads = dynlink.load_library_in_compartment( + comp_id, + rt_unlib, + AllowedGates::Private, + load_ctx, + )?; dynlink.add_manual_dependency(root_id, loads[0].lib); Ok(loads[0].lib) } @@ -161,10 +151,12 @@ impl RunCompLoader { } else { AllowedGates::Private }; + let mut load_ctx = LoadCtx::default(); let loads = UnloadOnDrop(dynlink.load_library_in_compartment( root_comp_id, root_unlib.clone(), allowed_gates, + &mut load_ctx, )?); // The dynamic linker gives us a list of loaded libraries, and which compartments they ended @@ -181,15 +173,16 @@ impl RunCompLoader { cache.insert(load.comp); // Inject the runtime library, careful to collect the error and keep going. - let rt_id = match Self::maybe_inject_runtime(dynlink, load.lib, load.comp) { - Ok(id) => id, - Err(e) => return Some(Err(e)), - }; + let rt_id = + match Self::maybe_inject_runtime(dynlink, load.lib, load.comp, &mut load_ctx) { + Ok(id) => id, + Err(e) => return Some(Err(e)), + }; Some(LoadInfo::new( dynlink, load.lib, rt_id, - get_new_sctx_instance(1.into()), + *load_ctx.set.get(&load.comp).unwrap(), false, )) } else { @@ -205,7 +198,7 @@ impl RunCompLoader { )?; let root_id = loads.0[0].lib; - let rt_id = Self::maybe_inject_runtime(dynlink, root_id, root_comp_id)?; + let rt_id = Self::maybe_inject_runtime(dynlink, root_id, root_comp_id, &mut load_ctx)?; dynlink.relocate_all(root_id)?; let is_binary = dynlink.get_library(root_id)?.is_binary(); @@ -213,7 +206,7 @@ impl RunCompLoader { dynlink, root_id, rt_id, - get_new_sctx_instance(1.into()), + *load_ctx.set.get(&root_comp_id).unwrap(), is_binary, )?; // We don't want to drop anymore, since now drop-cleanup will be handled by RunCompLoader. diff --git a/src/rt/monitor/src/mon/compartment/runcomp.rs b/src/rt/monitor/src/mon/compartment/runcomp.rs index 39d590b5..30590353 100644 --- a/src/rt/monitor/src/mon/compartment/runcomp.rs +++ b/src/rt/monitor/src/mon/compartment/runcomp.rs @@ -11,7 +11,8 @@ use monitor_api::{CompartmentFlags, RuntimeThreadControl, SharedCompConfig, TlsT use secgate::util::SimpleBuffer; use talc::{ErrOnOom, Talc}; use twizzler_abi::syscall::{ - ThreadSync, ThreadSyncFlags, ThreadSyncOp, ThreadSyncReference, ThreadSyncSleep, ThreadSyncWake, + DeleteFlags, ObjectControlCmd, ThreadSync, ThreadSyncFlags, ThreadSyncOp, ThreadSyncReference, + ThreadSyncSleep, ThreadSyncWake, }; use twizzler_rt_abi::{ core::{CompartmentInitInfo, CtorSet, InitInfoPtrs, RuntimeInfo, RUNTIME_INIT_COMP}, @@ -61,6 +62,11 @@ pub struct RunComp { impl Drop for RunComp { fn drop(&mut self) { // TODO: check if we need to do anything. + let _ = twizzler_abi::syscall::sys_object_ctrl( + self.instance, + ObjectControlCmd::Delete(DeleteFlags::empty()), + ) + .inspect_err(|e| tracing::warn!("failed to delete instance on RunComp drop: {}", e)); } } @@ -177,9 +183,15 @@ impl RunComp { } /// Unmap and object from this compartment. - pub fn unmap_object(&mut self, info: MapInfo) { - let _ = self.mapped_objects.remove(&info); - // Unmapping handled by dropping + pub fn unmap_object(&mut self, info: MapInfo) -> Option { + let x = self.mapped_objects.remove(&info); + if x.is_none() { + tracing::warn!( + "tried to comp-unmap an object that was not mapped by compartment: {:?}", + info + ); + } + x } /// Get a pointer to the compartment config. diff --git a/src/rt/monitor/src/mon/mod.rs b/src/rt/monitor/src/mon/mod.rs index a20946cc..3b94fd2a 100644 --- a/src/rt/monitor/src/mon/mod.rs +++ b/src/rt/monitor/src/mon/mod.rs @@ -150,6 +150,7 @@ impl Monitor { } /// Start a managed monitor thread. + #[tracing::instrument(skip(self, main), level = tracing::Level::DEBUG)] pub fn start_thread(&self, main: Box) -> Result { let key = ThreadKey::get().unwrap(); let locks = &mut *self.locks.lock(key); @@ -161,6 +162,7 @@ impl Monitor { } /// Spawn a thread into a given compartment, using initial thread arguments. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn spawn_compartment_thread( &self, instance: ObjID, @@ -183,12 +185,14 @@ impl Monitor { } /// Get the compartment config for the given compartment. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn get_comp_config(&self, sctx: ObjID) -> Option<*const SharedCompConfig> { - let comps = self.comp_mgr.read(ThreadKey::get().unwrap()); + let comps = self.comp_mgr.write(ThreadKey::get().unwrap()); Some(comps.get(sctx)?.comp_config_ptr()) } /// Map an object into a given compartment. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn map_object(&self, sctx: ObjID, info: MapInfo) -> Result { let handle = self.space.write(ThreadKey::get().unwrap()).map(info)?; @@ -198,15 +202,44 @@ impl Monitor { Ok(handle) } + /// Map a pair of objects into a given compartment. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] + pub fn map_pair( + &self, + sctx: ObjID, + info: MapInfo, + info2: MapInfo, + ) -> Result<(MapHandle, MapHandle), MapError> { + let (handle, handle2) = self + .space + .write(ThreadKey::get().unwrap()) + .map_pair(info, info2)?; + + 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)?; + let handle2 = rc.map_object(info2, handle2)?; + Ok((handle, handle2)) + } + /// Unmap an object from a given compartmen. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn unmap_object(&self, sctx: ObjID, info: MapInfo) { - self.unmapper - .get() - .unwrap() - .background_unmap_object_from_comp(sctx, info); + let Some(key) = ThreadKey::get() else { + tracing::warn!("todo: recursive locked unmap"); + return; + }; + + let mut comp_mgr = self.comp_mgr.write(key); + if let Some(comp) = comp_mgr.get_mut(sctx) { + let handle = comp.unmap_object(info); + drop(comp_mgr); + drop(handle); + } } /// Get the object ID for this compartment-thread's simple buffer. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn get_thread_simple_buffer(&self, sctx: ObjID, thread: ObjID) -> Option { let mut locks = self.locks.lock(ThreadKey::get().unwrap()); let (ref mut space, _, ref mut comps, _, _, _) = *locks; @@ -216,6 +249,7 @@ impl Monitor { } /// Write bytes to this per-compartment thread's simple buffer. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn _write_thread_simple_buffer( &self, sctx: ObjID, @@ -230,6 +264,7 @@ impl Monitor { } /// Read bytes from this per-compartment thread's simple buffer. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn read_thread_simple_buffer( &self, sctx: ObjID, @@ -244,6 +279,7 @@ impl Monitor { } /// Read the name of a compartment. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn comp_name(&self, id: ObjID) -> Option { self.comp_mgr .read(ThreadKey::get().unwrap()) @@ -252,6 +288,7 @@ impl Monitor { } /// Perform a compartment control action on the calling compartment. + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn compartment_ctrl( &self, info: &secgate::GateCallInfo, @@ -289,9 +326,10 @@ impl Monitor { if self.update_compartment_flags(src, |state| Some(state | COMP_READY)) { tracing::debug!( - "runtime main thread reached compartment ready state in {}", + "runtime main thread reached compartment ready state in {}: {:x}", self.comp_name(src) - .unwrap_or_else(|| String::from("unknown")) + .unwrap_or_else(|| String::from("unknown")), + state ); break if state & COMP_IS_BINARY == 0 { Some(0) diff --git a/src/rt/monitor/src/mon/space.rs b/src/rt/monitor/src/mon/space.rs index 0b03d042..4ce0ed71 100644 --- a/src/rt/monitor/src/mon/space.rs +++ b/src/rt/monitor/src/mon/space.rs @@ -4,8 +4,8 @@ use miette::IntoDiagnostic; use monitor_api::MappedObjectAddrs; use twizzler_abi::syscall::{ sys_object_create, sys_object_ctrl, sys_object_map, sys_object_unmap, BackingType, - CreateTieSpec, DeleteFlags, LifetimeType, ObjectControlCmd, ObjectCreate, ObjectCreateFlags, - ObjectSource, UnmapFlags, + CreateTieFlags, CreateTieSpec, DeleteFlags, LifetimeType, ObjectControlCmd, ObjectCreate, + ObjectCreateFlags, ObjectSource, UnmapFlags, }; use twizzler_object::Protections; use twizzler_rt_abi::object::{MapError, MapFlags, ObjID}; @@ -53,7 +53,7 @@ fn mapflags_into_prot(flags: MapFlags) -> Protections { extern "C-unwind" { fn __monitor_get_slot() -> isize; - fn __monitor_get_pair(one: *mut usize, two: *mut usize) -> bool; + fn __monitor_get_slot_pair(one: *mut usize, two: *mut usize) -> bool; fn __monitor_release_pair(one: usize, two: usize); fn __monitor_release_slot(slot: usize); } @@ -106,6 +106,70 @@ impl Space { Ok(Arc::new(MapHandleInner::new(info, item.addrs))) } + /// Map a pair of objects into the space. + pub fn map_pair( + &mut self, + info: MapInfo, + info2: MapInfo, + ) -> Result<(MapHandle, MapHandle), MapError> { + // Not yet mapped, so allocate a slot and map it. + let mut one = 0; + let mut two = 0; + if !unsafe { __monitor_get_slot_pair(&mut one, &mut two) } { + return Err(MapError::OutOfResources); + } + + let Ok(_) = sys_object_map( + None, + info.id, + one, + mapflags_into_prot(info.flags), + twizzler_abi::syscall::MapFlags::empty(), + ) else { + unsafe { + __monitor_release_pair(one, two); + } + return Err(MapError::Other); + }; + + let Ok(_) = sys_object_map( + None, + info2.id, + two, + mapflags_into_prot(info2.flags), + twizzler_abi::syscall::MapFlags::empty(), + ) else { + let _ = sys_object_unmap(None, one, UnmapFlags::empty()) + .inspect_err(|e| tracing::warn!("failed to unmap first in pair on error: {}", e)); + unsafe { + __monitor_release_pair(one, two); + } + return Err(MapError::Other); + }; + + let map = MappedObject { + addrs: MappedObjectAddrs::new(one), + handle_count: 0, + }; + let map2 = MappedObject { + addrs: MappedObjectAddrs::new(two), + handle_count: 0, + }; + self.maps.insert(info, map); + self.maps.insert(info2, map2); + // Unwrap-Ok: just inserted. + let item = self.maps.get_mut(&info).unwrap(); + item.handle_count += 1; + let addrs = item.addrs; + let item2 = self.maps.get_mut(&info2).unwrap(); + item2.handle_count += 1; + let addrs2 = item2.addrs; + Ok(( + Arc::new(MapHandleInner::new(info, addrs)), + Arc::new(MapHandleInner::new(info2, addrs2)), + )) + } + /// Remove an object from the space. The actual unmapping syscall only happens once the returned /// value from this function is dropped. pub fn handle_drop(&mut self, info: MapInfo) -> Option { @@ -120,6 +184,7 @@ impl Space { } // Decrement and maybe actually unmap. + tracing::debug!("drop: {:?}: handle count: {}", info, item.handle_count); item.handle_count -= 1; if item.handle_count == 0 { let slot = item.addrs.slot; @@ -166,10 +231,10 @@ impl Space { BackingType::Normal, LifetimeType::Volatile, Some(instance), - ObjectCreateFlags::empty(), + ObjectCreateFlags::DELETE, ), &[], - &[], + &[CreateTieSpec::new(instance, CreateTieFlags::empty())], map_flags, ) } diff --git a/src/rt/monitor/src/mon/space/handle.rs b/src/rt/monitor/src/mon/space/handle.rs index 3c869861..11a0246e 100644 --- a/src/rt/monitor/src/mon/space/handle.rs +++ b/src/rt/monitor/src/mon/space/handle.rs @@ -9,6 +9,7 @@ use crate::mon::get_monitor; /// A handle for an object mapped into the address space. This handle is owning, and when dropped, /// the mapping is sent to the background unmapping thread. +#[derive(Debug)] pub struct MapHandleInner { info: MapInfo, map: MappedObjectAddrs, diff --git a/src/rt/monitor/src/mon/space/unmapper.rs b/src/rt/monitor/src/mon/space/unmapper.rs index 82780c0a..137561ae 100644 --- a/src/rt/monitor/src/mon/space/unmapper.rs +++ b/src/rt/monitor/src/mon/space/unmapper.rs @@ -1,7 +1,5 @@ use std::{panic::catch_unwind, sync::mpsc::Sender, thread::JoinHandle}; -use twizzler_object::ObjID; - use super::MapInfo; use crate::mon::get_monitor; @@ -13,7 +11,6 @@ pub struct Unmapper { #[derive(Copy, Clone, Debug)] pub enum UnmapCommand { - CompDrop(ObjID, MapInfo), SpaceUnmap(MapInfo), } @@ -28,15 +25,10 @@ impl Unmapper { let key = happylock::ThreadKey::get().unwrap(); match receiver.recv() { Ok(info) => { + tracing::debug!("unmapper command {:?}", info); if catch_unwind(|| { let monitor = get_monitor(); match info { - UnmapCommand::CompDrop(id, info) => { - let mut cmgr = monitor.comp_mgr.write(key); - if let Some(comp) = cmgr.get_mut(id) { - comp.unmap_object(info); - } - } UnmapCommand::SpaceUnmap(info) => { let mut space = monitor.space.write(key); space.handle_drop(info); @@ -72,21 +64,4 @@ impl Unmapper { tracing::warn!("failed to enqueue Unmap {:?} onto cleaner thread", info); } } - - /// Enqueue a mapping to be unmapped. - pub fn background_unmap_object_from_comp(&self, comp: ObjID, info: MapInfo) { - // If the receiver is down, this will fail, but that also shouldn't happen, unless the - // call to clean_call above panics. In any case, handle this gracefully. - if self - .sender - .send(UnmapCommand::CompDrop(comp, info)) - .is_err() - { - tracing::warn!( - "failed to enqueue CompDrop {}::{:?} onto cleaner thread", - comp, - info - ); - } - } } diff --git a/src/rt/monitor/src/mon/stat.rs b/src/rt/monitor/src/mon/stat.rs index 7e7e5a31..facca4ec 100644 --- a/src/rt/monitor/src/mon/stat.rs +++ b/src/rt/monitor/src/mon/stat.rs @@ -6,6 +6,7 @@ use super::Monitor; use crate::gates::{DynlinkStats, HandleStats, MonitorStats}; impl Monitor { + #[tracing::instrument(skip(self), level = tracing::Level::DEBUG)] pub fn stats(&self) -> MonitorStats { let ( ref mut space, diff --git a/src/rt/monitor/src/mon/thread.rs b/src/rt/monitor/src/mon/thread.rs index 2ca98724..1c818c51 100644 --- a/src/rt/monitor/src/mon/thread.rs +++ b/src/rt/monitor/src/mon/thread.rs @@ -37,6 +37,8 @@ pub const STACK_SIZE_MIN_ALIGN: usize = 0x1000; // 4K pub struct ThreadMgr { all: HashMap, cleaner: OnceLock, + next_id: u32, + id_stack: Vec, } impl Default for ThreadMgr { @@ -44,17 +46,52 @@ impl Default for ThreadMgr { Self { all: HashMap::default(), cleaner: OnceLock::new(), + next_id: 1, + id_stack: Vec::new(), } } } +struct IdDropper<'a> { + mgr: &'a mut ThreadMgr, + id: u32, +} + +impl<'a> IdDropper<'a> { + pub fn freeze(self) -> u32 { + let id = self.id; + std::mem::forget(self); + id + } +} + +impl<'a> Drop for IdDropper<'a> { + fn drop(&mut self) { + self.mgr.release_super_tid(self.id); + } +} + impl ThreadMgr { pub(super) fn set_cleaner(&mut self, cleaner: cleaner::ThreadCleaner) { self.cleaner.set(cleaner).ok().unwrap(); } + fn next_super_tid(&mut self) -> IdDropper<'_> { + let id = self.id_stack.pop().unwrap_or_else(|| { + let id = self.next_id; + self.next_id += 1; + id + }); + IdDropper { mgr: self, id } + } + + fn release_super_tid(&mut self, id: u32) { + self.id_stack.push(id); + } + fn do_remove(&mut self, thread: &ManagedThread) { self.all.remove(&thread.id); + self.release_super_tid(thread.super_tid); if let Some(cleaner) = self.cleaner.get() { cleaner.untrack(thread.id); } @@ -111,6 +148,11 @@ impl ThreadMgr { NonNull::new(std::alloc::alloc_zeroed(layout)) }) .map_err(|_| SpawnError::Other)?; + let super_tid = self.next_super_tid().freeze(); + unsafe { + let tcb = super_tls.get_thread_control_block::(); + (*tcb).runtime_data.set_id(super_tid); + } let super_thread_pointer = super_tls.get_thread_pointer_value(); let super_stack = Box::new_zeroed_slice(SUPER_UPCALL_STACK_SIZE); let id = unsafe { @@ -129,6 +171,7 @@ impl ThreadMgr { .unwrap(); Ok(Arc::new(ManagedThreadInner { id, + super_tid, repr: ManagedThreadRepr::new(repr), _super_stack: super_stack, _super_tls: super_tls, @@ -175,6 +218,7 @@ impl ThreadMgr { pub struct ManagedThreadInner { /// The ID of the thread. pub id: ObjID, + pub super_tid: u32, /// The thread repr. pub(crate) repr: ManagedThreadRepr, _super_stack: Box<[MaybeUninit]>, @@ -206,7 +250,6 @@ 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/rt/reference/src/runtime/object.rs b/src/rt/reference/src/runtime/object.rs index 3352292b..c4a8ce1b 100644 --- a/src/rt/reference/src/runtime/object.rs +++ b/src/rt/reference/src/runtime/object.rs @@ -2,10 +2,7 @@ use std::{ffi::c_void, sync::atomic::AtomicU64}; use handlecache::HandleCache; use tracing::warn; -use twizzler_abi::{ - object::{Protections, MAX_SIZE, NULLPAGE_SIZE}, - syscall::{sys_object_map, ObjectMapError}, -}; +use twizzler_abi::object::{MAX_SIZE, NULLPAGE_SIZE}; use twizzler_rt_abi::{ bindings::object_handle, object::{MapError, MapFlags, ObjID, ObjectHandle}, @@ -15,20 +12,6 @@ use super::ReferenceRuntime; mod handlecache; -fn mapflags_into_prot(flags: MapFlags) -> Protections { - let mut prot = Protections::empty(); - if flags.contains(MapFlags::READ) { - prot.insert(Protections::READ); - } - if flags.contains(MapFlags::WRITE) { - prot.insert(Protections::WRITE); - } - if flags.contains(MapFlags::EXEC) { - prot.insert(Protections::EXEC); - } - prot -} - #[repr(C)] pub(crate) struct RuntimeHandleInfo { refs: AtomicU64, @@ -61,18 +44,6 @@ pub(crate) fn new_object_handle(id: ObjID, slot: usize, flags: MapFlags) -> Obje } } -fn map_sys_err(sys_err: ObjectMapError) -> MapError { - // TODO (dbittman): in a future PR, I plan to cleanup all the error handling between the API and - // ABI crates. - match sys_err { - ObjectMapError::Unknown => MapError::Other, - ObjectMapError::ObjectNotFound => MapError::NoSuchObject, - ObjectMapError::InvalidSlot => MapError::InvalidArgument, - ObjectMapError::InvalidProtections => MapError::PermissionDenied, - ObjectMapError::InvalidArgument => MapError::InvalidArgument, - } -} - impl ReferenceRuntime { #[tracing::instrument(ret, skip(self), level = "trace")] pub fn map_object(&self, id: ObjID, flags: MapFlags) -> Result { @@ -83,7 +54,10 @@ impl ReferenceRuntime { #[tracing::instrument(skip(self), level = "trace")] pub fn release_handle(&self, handle: *mut object_handle) { - self.object_manager.lock().release(handle) + self.object_manager.lock().release(handle); + if self.is_monitor().is_some() { + self.object_manager.lock().cache.flush(); + } } pub fn get_object_handle_from_ptr(&self, ptr: *const u8) -> Option { @@ -128,33 +102,13 @@ impl ReferenceRuntime { in_id_b: ObjID, in_flags_b: MapFlags, ) -> Result<(ObjectHandle, ObjectHandle), MapError> { - let (slot_a, slot_b) = self.allocate_pair().ok_or(MapError::OutOfResources)?; - - let prot_a = mapflags_into_prot(in_flags_a); - let prot_b = mapflags_into_prot(in_flags_b); - - sys_object_map( - None, - in_id_a, - slot_a, - prot_a, - twizzler_abi::syscall::MapFlags::empty(), - ) - .map_err(map_sys_err)?; - - sys_object_map( - None, - in_id_b, - slot_b, - prot_b, - twizzler_abi::syscall::MapFlags::empty(), - ) - .map_err(map_sys_err)?; + let mapping = + monitor_api::monitor_rt_object_pair_map(in_id_a, in_flags_a, in_id_b, in_flags_b) + .unwrap()?; - Ok(( - new_object_handle(in_id_a, slot_a, in_flags_a), - new_object_handle(in_id_b, slot_b, in_flags_b), - )) + let handle = new_object_handle(in_id_a, mapping.0.slot, in_flags_a); + let handle2 = new_object_handle(in_id_b, mapping.1.slot, in_flags_b); + Ok((handle, handle2)) } } diff --git a/src/rt/reference/src/runtime/object/handlecache.rs b/src/rt/reference/src/runtime/object/handlecache.rs index 055844a7..a665331a 100644 --- a/src/rt/reference/src/runtime/object/handlecache.rs +++ b/src/rt/reference/src/runtime/object/handlecache.rs @@ -73,7 +73,7 @@ impl HandleCache { self.slotmap.insert(slot, map); } - fn do_remove(&mut self, item: object_handle) { + fn do_remove(&mut self, item: &object_handle) { let slot = (item.start as usize) / MAX_SIZE; do_unmap(&item); self.slotmap.remove(&slot); @@ -82,23 +82,26 @@ impl HandleCache { /// Release a handle. Must only be called from runtime handle release (internal_refs == 0). pub fn release(&mut self, handle: &object_handle) { let map = ObjectMapKey::from_raw_handle(handle); - trace!("release {:?}", map); + tracing::debug!("release {:?}", map); if let Some(handle) = self.active.remove(&map) { // If queue is full, evict. if self.queued.len() >= QUEUE_LEN { let (oldmap, old) = self.queued.remove(0); trace!("evict {:?}", oldmap); - self.do_remove(old); + self.do_remove(&old); } self.queued.push((map, handle)); + } else { + self.do_remove(handle); } } /// Flush all items in the inactive queue. - pub fn _flush(&mut self) { + pub fn flush(&mut self) { let to_remove = self.queued.drain(..).collect::>(); for item in to_remove { - self.do_remove(item.1); + tracing::trace!("flush: remove: {}", item.0 .0); + self.do_remove(&item.1); } } } diff --git a/src/rt/reference/src/runtime/thread/mgr.rs b/src/rt/reference/src/runtime/thread/mgr.rs index dc21d326..b090e99d 100644 --- a/src/rt/reference/src/runtime/thread/mgr.rs +++ b/src/rt/reference/src/runtime/thread/mgr.rs @@ -169,7 +169,7 @@ impl ReferenceRuntime { let stack_size = args.stack_size; let arg_raw = Box::into_raw(args) as usize; - trace!( + tracing::trace!( "spawning thread {} with stack {:x}, entry {:x}, and TLS {:p}", id.id, stack_raw, @@ -186,7 +186,6 @@ impl ReferenceRuntime { let thid: ObjID = { let res: secgate::SecGateReturn> = monitor_api::monitor_rt_spawn_thread(new_args, tls as usize, stack_raw); - //let res = monitor_api::monitor_rt_spawn_thread(new_args, tls as usize, stack_raw); match res { secgate::SecGateReturn::Success(id) => ObjID::from(id?), _ => return Err(SpawnError::Other), diff --git a/src/srv/pager-srv/object-store/src/object_store.rs b/src/srv/pager-srv/object-store/src/object_store.rs index 2572659a..c8e85247 100644 --- a/src/srv/pager-srv/object-store/src/object_store.rs +++ b/src/srv/pager-srv/object-store/src/object_store.rs @@ -245,6 +245,10 @@ fn get_symmetric_cipher_from_key(disk_offset: u64, key: [u8; 32]) -> Result Result<(), Error> { let _unused = LOCK.lock().unwrap(); + { + // ensure these init now. + let _ = get_khf_locks(); + } let b64 = encode_obj_id(obj_id); let mut fs = FS.get().unwrap().lock().unwrap(); let subdir = get_dir_path(&mut fs, &b64)?; diff --git a/src/srv/pager-srv/src/data.rs b/src/srv/pager-srv/src/data.rs index eab89c46..a637e8d7 100644 --- a/src/srv/pager-srv/src/data.rs +++ b/src/srv/pager-srv/src/data.rs @@ -57,6 +57,13 @@ impl PerObjectInner { } } + pub fn lookup(&self, obj_range: ObjectRange) -> Option { + let key = obj_range.start / PAGE; + self.page_map + .get(&key) + .map(|ppd| PhysRange::new(ppd.paddr, PAGE)) + } + pub fn pages(&self) -> impl Iterator + '_ { self.page_map .iter() @@ -88,10 +95,16 @@ impl PerObject { self.inner.lock().unwrap().track(obj_range, phys_range); } + pub fn lookup(&self, obj_range: ObjectRange) -> Option { + self.inner.lock().unwrap().lookup(obj_range) + } + pub async fn sync( &self, rq: &Arc>, ) -> Result<()> { + let nulls = [0; PAGE as usize]; + object_store::write_all(self.id.raw(), &nulls, 0).unwrap(); let (pages, mpages) = { let inner = self.inner.lock().unwrap(); let total = inner.page_map.len() + inner.meta_page_map.len(); @@ -252,6 +265,19 @@ impl PagerData { id: ObjID, obj_range: ObjectRange, ) -> Result { + { + // See if we already allocated + let mut inner = self.inner.lock().unwrap(); + let po = inner.get_per_object(id); + if let Some(phys_range) = po.lookup(obj_range) { + tracing::debug!( + "already paged memory page for ObjID {:?}, ObjectRange {:?}", + id, + obj_range + ); + return Ok(phys_range); + } + } tracing::debug!( "allocating memory page for ObjID {:?}, ObjectRange {:?}", id, @@ -268,7 +294,7 @@ impl PagerData { phys_range }; page_in(rq, id, obj_range, phys_range, false).await?; - tracing::trace!("memory page allocated successfully"); + tracing::debug!("memory page allocated successfully: {:?}", phys_range); return Ok(phys_range); } @@ -283,6 +309,7 @@ impl PagerData { rq: &Arc>, id: ObjID, ) { + tracing::debug!("sync: {:?}", id); let po = { let mut inner = self.inner.lock().unwrap(); inner.get_per_object(id).clone() @@ -290,5 +317,6 @@ impl PagerData { let _ = po.sync(rq).await.inspect_err(|e| { tracing::warn!("sync failed for {}: {}", id, e); }); + object_store::advance_epoch().unwrap(); } } diff --git a/src/srv/pager-srv/src/helpers.rs b/src/srv/pager-srv/src/helpers.rs index b30812dd..84b30200 100644 --- a/src/srv/pager-srv/src/helpers.rs +++ b/src/srv/pager-srv/src/helpers.rs @@ -55,9 +55,9 @@ pub async fn page_in( } else { obj_range.start }; - tracing::trace!("read_exact: offset: {}", start); + tracing::debug!("read_exact: offset: {}", start); let res = object_store::read_exact(obj_id.raw(), &mut buf, start) - .inspect_err(|e| tracing::trace!("error in read from object store: {}", e)); + .inspect_err(|e| tracing::debug!("error in read from object store: {}", e)); if res.is_err() { buf.fill(0); } @@ -75,7 +75,7 @@ pub async fn page_out( assert_eq!(obj_range.len(), 0x1000); assert_eq!(phys_range.len(), 0x1000); - tracing::trace!("pageout: {}: {:?} {:?}", obj_id, obj_range, phys_range); + tracing::debug!("pageout: {}: {:?} {:?}", obj_id, obj_range, phys_range); let mut buf = [0; 0x1000]; physrw::read_physical_pages(rq, &mut buf, phys_range).await?; let start = if meta { @@ -83,7 +83,7 @@ pub async fn page_out( } else { obj_range.start }; - tracing::trace!("write_all: offset: {}", start); + tracing::debug!("write_all: offset: {}", start); object_store::write_all(obj_id.raw(), &buf, start) .inspect_err(|e| tracing::warn!("error in write to object store: {}", e)) .into_diagnostic() diff --git a/src/srv/pager-srv/src/lib.rs b/src/srv/pager-srv/src/lib.rs index a532bee6..786e7f8e 100644 --- a/src/srv/pager-srv/src/lib.rs +++ b/src/srv/pager-srv/src/lib.rs @@ -4,7 +4,7 @@ use std::sync::{Arc, OnceLock}; use async_executor::Executor; -use futures::executor::block_on; +use async_io::block_on; use twizzler_abi::pager::{ CompletionToKernel, CompletionToPager, PagerCompletionData, PhysRange, RequestFromKernel, RequestFromPager, @@ -247,6 +247,7 @@ fn do_pager_start(q1: ObjID, q2: ObjID) { tracing::info!("pager ready"); let _ = PAGER_DATA.set((data, sq)); + /* object_store::unlink_object(777); let res = object_store::create_object(777).unwrap(); @@ -275,12 +276,9 @@ pub fn pager_start(q1: ObjID, q2: ObjID) { #[secgate::secure_gate] pub fn full_object_sync(id: ObjID) { - EXECUTOR - .get() - .unwrap() - .spawn(async move { - let pager = PAGER_DATA.get().unwrap(); - pager.0.sync(&pager.1, id) - }) - .detach(); + let task = EXECUTOR.get().unwrap().spawn(async move { + let pager = PAGER_DATA.get().unwrap(); + pager.0.sync(&pager.1, id).await + }); + block_on(EXECUTOR.get().unwrap().run(async { task.await })); } diff --git a/src/srv/pager-srv/src/physrw.rs b/src/srv/pager-srv/src/physrw.rs index d52c66ad..121d0872 100644 --- a/src/srv/pager-srv/src/physrw.rs +++ b/src/srv/pager-srv/src/physrw.rs @@ -21,6 +21,7 @@ async fn do_physrw_request( phys: PhysRange, write_phys: bool, ) -> miette::Result<()> { + tracing::debug!("phys rw req: offset = {}", offset); let request = RequestFromPager::new(PagerRequest::CopyUserPhys { target_object, offset, diff --git a/tools/xtask/src/qemu.rs b/tools/xtask/src/qemu.rs index 90adba3f..bf903ebb 100644 --- a/tools/xtask/src/qemu.rs +++ b/tools/xtask/src/qemu.rs @@ -41,7 +41,7 @@ impl QemuCommand { pub fn config(&mut self, options: &QemuOptions, image_info: ImageInfo) { // Set up the basic stuff, memory and bios, etc. - self.cmd.arg("-m").arg("2048,slots=4,maxmem=8G"); + self.cmd.arg("-m").arg("4096,slots=4,maxmem=8G"); // configure architechture specific parameters self.arch_config(options);