1#![feature(linkage)]
6#![feature(thread_local)]
7#![feature(pointer_is_aligned_to)]
8#![feature(tuple_trait)]
9#![allow(unexpected_cfgs)]
10use std::{
11 alloc::Layout,
12 cell::UnsafeCell,
13 marker::{PhantomData, Tuple},
14 ptr::NonNull,
15 sync::{
16 atomic::{AtomicPtr, AtomicU32, AtomicU64, Ordering},
17 OnceLock,
18 },
19};
20
21pub use dynlink::{
22 context::NewCompartmentFlags,
23 tls::{Tcb, TlsRegion},
24};
25use secgate::{
26 util::{Descriptor, Handle},
27 Crossing, DynamicSecGate,
28};
29use twizzler_abi::{
30 object::{ObjID, MAX_SIZE, NULLPAGE_SIZE},
31 syscall::{sys_thread_sync, ThreadSync, ThreadSyncReference, ThreadSyncWake},
32};
33use twizzler_rt_abi::{
34 bindings::{binding_info, ctor_set},
35 debug::{DlPhdrInfo, LinkMap, LoadedImageId},
36 error::{ArgumentError, TwzError},
37 thread::ThreadSpawnArgs,
38};
39
40#[secgate::gatecall]
41pub fn monitor_rt_get_library_info(desc: Descriptor) -> Result<LibraryInfoRaw, TwzError> {}
42
43#[secgate::gatecall]
44pub fn monitor_rt_spawn_thread(
45 args: ThreadSpawnArgs,
46 thread_pointer: usize,
47 stack_pointer: usize,
48) -> Result<ObjID, TwzError> {
49}
50
51#[secgate::gatecall]
52pub fn monitor_rt_get_comp_config() -> Result<usize, TwzError> {}
53#[secgate::gatecall]
54pub fn monitor_rt_get_library_handle(
55 compartment: Option<Descriptor>,
56 lib_n: usize,
57) -> Result<Descriptor, TwzError> {
58}
59
60#[secgate::gatecall]
61pub fn monitor_rt_get_compartment_handle(compartment: ObjID) -> Result<Descriptor, TwzError> {}
62
63#[secgate::gatecall]
64pub fn monitor_rt_get_compartment_info(
65 desc: Option<Descriptor>,
66) -> Result<CompartmentInfoRaw, TwzError> {
67}
68
69#[secgate::gatecall]
70pub fn monitor_rt_compartment_dynamic_gate(
71 desc: Option<Descriptor>,
72 name_len: usize,
73) -> Result<usize, TwzError> {
74}
75
76#[secgate::gatecall]
77pub fn monitor_rt_get_compartment_deps(
78 desc: Option<Descriptor>,
79 dep_n: usize,
80) -> Result<Descriptor, TwzError> {
81}
82
83#[secgate::gatecall]
84pub fn monitor_rt_get_compartment_thread(
85 desc: Option<Descriptor>,
86 dep_n: usize,
87) -> Result<ThreadInfo, TwzError> {
88}
89
90#[secgate::gatecall]
91pub fn monitor_rt_lookup_compartment(name_len: usize) -> Result<Descriptor, TwzError> {}
92
93#[secgate::gatecall]
94pub fn monitor_rt_load_compartment(
95 root_object: ObjID,
96 name_len: u64,
97 args_len: u64,
98 env_len: u64,
99 flags: u32,
100 config: u64,
101) -> Result<Descriptor, TwzError> {
102}
103
104#[secgate::gatecall]
105pub fn monitor_rt_compartment_wait(desc: Option<Descriptor>, flags: u64) -> Result<u64, TwzError> {}
106
107#[secgate::gatecall]
108pub fn monitor_rt_drop_compartment_handle(desc: Descriptor) -> Result<(), TwzError> {}
109
110#[secgate::gatecall]
111pub fn monitor_rt_load_library(
112 compartment: Option<Descriptor>,
113 id: Option<ObjID>,
114 name_len: usize,
115) -> Result<(Descriptor, usize), TwzError> {
116}
117
118#[secgate::gatecall]
119pub fn monitor_rt_drop_library_handle(desc: Descriptor) -> Result<(), TwzError> {}
120
121#[secgate::gatecall]
122pub fn monitor_rt_object_map(
123 id: ObjID,
124 flags: twizzler_rt_abi::object::MapFlags,
125) -> Result<crate::MappedObjectAddrs, TwzError> {
126}
127
128#[secgate::gatecall]
129pub fn monitor_rt_object_pair_map(
130 id: ObjID,
131 flags: twizzler_rt_abi::object::MapFlags,
132 id2: ObjID,
133 flags2: twizzler_rt_abi::object::MapFlags,
134) -> Result<(crate::MappedObjectAddrs, crate::MappedObjectAddrs), TwzError> {
135}
136
137#[secgate::gatecall]
138pub fn monitor_rt_object_unmap(
139 id: ObjID,
140 flags: twizzler_rt_abi::object::MapFlags,
141) -> Result<(), TwzError> {
142}
143
144#[secgate::gatecall]
145pub fn monitor_rt_get_thread_simple_buffer() -> Result<ObjID, TwzError> {}
146#[secgate::gatecall]
147pub fn monitor_rt_comp_ctrl(cmd: MonitorCompControlCmd) -> Result<Option<i32>, TwzError> {}
148#[secgate::gatecall]
149pub fn monitor_rt_stats() -> Result<MonitorStats, TwzError> {}
150#[secgate::gatecall]
151pub fn monitor_rt_set_nameroot(root: ObjID) -> Result<(), TwzError> {}
152#[secgate::gatecall]
153pub fn monitor_rt_post_signal(
154 comp: Option<ObjID>,
155 signal: u64,
156 flags: PostSignalFlags,
157) -> Result<(), TwzError> {
158}
159
160#[secgate::gatecall]
161pub fn monitor_rt_libname_map(namelen: usize, id: ObjID) -> Result<(), TwzError> {}
162
163#[secgate::gatecall]
164pub fn monitor_rt_libname_unmap(namelen: Option<usize>, id: Option<ObjID>) -> Result<(), TwzError> {
165}
166
167#[secgate::gatecall]
168pub fn monitor_rt_set_controller(comp: ObjID, controller: ObjID) -> Result<(), TwzError> {}
169
170#[secgate::gatecall]
171pub fn monitor_rt_lookup_compartment_id(id: ObjID) -> Result<Descriptor, TwzError> {}
172
173#[secgate::gatecall]
179pub fn monitor_rt_lookup_symbol(
180 lib_desc: Option<Descriptor>,
181 name_len: usize,
182) -> Result<usize, TwzError> {
183}
184#[repr(C)]
187pub struct SharedCompConfig {
188 pub sctx: ObjID,
191 tls_template: AtomicPtr<TlsTemplateInfo>,
193 pub root_library_id: Option<LoadedImageId>,
195 pub posted_signals: AtomicU64,
196 pub loader_config: CompartmentLoaderConfig,
197}
198
199struct CompConfigFinder {
200 config: *const SharedCompConfig,
201}
202
203unsafe impl Sync for CompConfigFinder {}
206unsafe impl Send for CompConfigFinder {}
207
208static COMP_CONFIG: OnceLock<CompConfigFinder> = OnceLock::new();
209
210pub fn get_comp_config() -> &'static SharedCompConfig {
212 unsafe {
213 COMP_CONFIG
214 .get_or_init(|| CompConfigFinder {
215 config: monitor_rt_get_comp_config().unwrap() as *const _,
216 })
217 .config
218 .as_ref()
219 .unwrap()
220 }
221}
222
223pub fn set_comp_config(cfg: &'static SharedCompConfig) -> Result<(), ()> {
227 COMP_CONFIG
228 .set(CompConfigFinder { config: cfg })
229 .map_err(|_| ())
230}
231
232#[repr(C)]
234#[derive(Clone, Copy, Debug)]
235pub struct TlsTemplateInfo {
236 pub gen: u64,
237 pub layout: Layout,
238 pub alloc_base: NonNull<u8>,
239 pub tp_offset: usize,
240 pub dtv_offset: usize,
241 pub num_dtv_entries: usize,
242 pub module_top_offset: usize,
243}
244
245unsafe impl Send for TlsTemplateInfo {}
248unsafe impl Sync for TlsTemplateInfo {}
249
250impl From<TlsRegion> for TlsTemplateInfo {
251 fn from(value: TlsRegion) -> Self {
252 let offset = |ptr: NonNull<u8>| -> usize {
253 unsafe {
254 ptr.as_ptr()
255 .byte_offset_from(value.alloc_base.as_ptr())
256 .try_into()
257 .unwrap()
258 }
259 };
260 Self {
261 gen: value.gen,
262 layout: value.layout,
263 alloc_base: value.alloc_base,
264 num_dtv_entries: value.num_dtv_entries,
265 tp_offset: offset(value.thread_pointer),
266 dtv_offset: offset(value.dtv.cast()),
267 module_top_offset: offset(value.module_top),
268 }
269 }
270}
271
272impl TlsTemplateInfo {
273 pub unsafe fn init_new_tls_region<T>(&self, new: *mut u8, tcb_data: T) -> *mut Tcb<T> {
278 assert!(new.is_aligned_to(self.layout.align()));
279 core::ptr::copy_nonoverlapping(self.alloc_base.as_ptr(), new, self.layout.size());
281
282 let tcb = new.add(self.tp_offset) as *mut Tcb<T>;
283 let dtv_ptr = new.add(self.dtv_offset) as *mut *mut u8;
284 let dtv = core::slice::from_raw_parts_mut(dtv_ptr, self.num_dtv_entries);
285
286 for entry in dtv.iter_mut().skip(1) {
289 let offset = (*entry).byte_offset_from(self.alloc_base.as_ptr());
290 *entry = new.byte_offset(offset);
291 }
292
293 let dtv_0 = dtv_ptr as *mut u64;
295 *dtv_0 = self.gen;
296
297 {
299 let tcb = tcb.as_mut().unwrap();
300 tcb.dtv = dtv_ptr as *const usize;
301 tcb.self_ptr = tcb;
302 tcb.runtime_data = tcb_data;
303 }
304
305 tcb
306 }
307}
308
309impl SharedCompConfig {
310 pub fn new(
311 sctx: ObjID,
312 tls_template: *mut TlsTemplateInfo,
313 loader_config: CompartmentLoaderConfig,
314 ) -> Self {
315 Self {
316 sctx,
317 tls_template: AtomicPtr::new(tls_template),
318 root_library_id: None,
319 posted_signals: AtomicU64::new(0),
320 loader_config,
321 }
322 }
323
324 pub fn set_tls_template(&self, ptr: *mut TlsTemplateInfo) {
326 self.tls_template.store(ptr, Ordering::SeqCst);
327 }
328
329 pub fn get_tls_template(&self) -> *const TlsTemplateInfo {
331 self.tls_template.load(Ordering::SeqCst)
332 }
333
334 pub fn read_posted_signals(&self) -> u64 {
335 self.posted_signals.swap(0, Ordering::SeqCst)
336 }
337
338 pub fn peek_posted_signals(&self) -> u64 {
339 self.posted_signals.load(Ordering::SeqCst)
340 }
341
342 pub fn post_signal(&self, signal: u64) {
343 self.posted_signals.fetch_or(1 << signal, Ordering::SeqCst);
344 let _ = sys_thread_sync(
345 &mut [ThreadSync::new_wake(ThreadSyncWake::new(
346 ThreadSyncReference::Virtual(&self.posted_signals),
347 usize::MAX,
348 ))],
349 None,
350 );
351 }
352}
353
354#[derive(Debug)]
356pub struct LibraryInfo<'a> {
357 pub name: String,
359 pub compartment_id: ObjID,
361 pub objid: ObjID,
363 pub start: *const u8,
365 pub len: usize,
367 pub dl_info: DlPhdrInfo,
369 pub link_map: LinkMap,
371 pub slot: usize,
373 _pd: PhantomData<&'a ()>,
374 internal_name: Vec<u8>,
375}
376
377impl<'a> LibraryInfo<'a> {
378 pub fn from_raw(raw: LibraryInfoRaw) -> Self {
379 let name = lazy_sb::read_bytes_from_sb(raw.name_len);
380 let mut this = Self {
381 name: lazy_sb::read_string_from_sb(raw.name_len),
382 compartment_id: raw.compartment_id,
383 objid: raw.objid,
384 start: raw.start,
385 len: raw.len,
386 dl_info: raw.dl_info,
387 slot: raw.slot,
388 _pd: PhantomData,
389 internal_name: name,
390 link_map: raw.link_map,
391 };
392 this.dl_info.name = this.internal_name.as_ptr().cast();
393 this
394 }
395}
396
397#[derive(Debug)]
399pub struct LibraryHandle {
400 desc: Descriptor,
401}
402
403impl LibraryHandle {
404 pub fn info(&self) -> LibraryInfo<'_> {
406 LibraryInfo::from_raw(monitor_rt_get_library_info(self.desc).unwrap())
407 }
408
409 pub fn desc(&self) -> Descriptor {
411 self.desc
412 }
413
414 pub fn into_raw(self) -> Descriptor {
415 let desc = self.desc;
416 core::mem::forget(self);
417 desc
418 }
419}
420
421pub struct LibraryLoader<'a> {
423 id: Option<ObjID>,
424 name: String,
425 comp: Option<&'a CompartmentHandle>,
426}
427
428impl<'a> LibraryLoader<'a> {
429 pub fn new(name: impl ToString, id: Option<ObjID>) -> Self {
431 Self {
432 name: name.to_string(),
433 id,
434 comp: None,
435 }
436 }
437
438 pub fn in_compartment(&'a mut self, comp: &'a CompartmentHandle) -> &'a mut Self {
440 self.comp = Some(comp);
441 self
442 }
443
444 pub fn load(&self) -> Result<LibraryHandle, TwzError> {
446 let len = lazy_sb::write_bytes_to_sb(self.name.as_bytes());
447 let (desc, ctor_len): (Descriptor, usize) =
448 monitor_rt_load_library(self.comp.map(|comp| comp.desc).flatten(), self.id, len)?;
449
450 let ctors = lazy_sb::read_bytes_from_sb(ctor_len);
452 let ctor_slice = unsafe {
453 core::slice::from_raw_parts(
454 ctors.as_ptr().cast::<ctor_set>(),
455 ctor_len / core::mem::size_of::<ctor_set>(),
456 )
457 };
458 for ctor in ctor_slice {
459 unsafe {
460 let init_array = core::slice::from_raw_parts(ctor.init_array, ctor.init_array_len);
461 for func in init_array {
462 if let Some(f) = func {
463 f();
464 }
465 }
466 if let Some(f) = ctor.legacy_init {
467 f();
468 }
469 }
470 }
471
472 Ok(LibraryHandle { desc })
473 }
474}
475
476pub struct CompartmentHandle {
478 desc: Option<Descriptor>,
479}
480
481impl CompartmentHandle {
482 pub fn info(&self) -> CompartmentInfo<'_> {
484 CompartmentInfo::from_raw(monitor_rt_get_compartment_info(self.desc).unwrap())
485 }
486
487 pub fn desc(&self) -> Option<Descriptor> {
489 self.desc
490 }
491
492 pub unsafe fn dynamic_gate<A: Tuple + Crossing + Copy, R: Crossing + Copy>(
493 &self,
494 name: &str,
495 ) -> Result<DynamicSecGate<'_, A, R>, TwzError> {
496 let name_len = lazy_sb::write_bytes_to_sb(name.as_bytes());
497 let address = monitor_rt_compartment_dynamic_gate(self.desc, name_len)?;
498 Ok(DynamicSecGate::new(address))
499 }
500
501 pub fn signal(&self, sig: u64) -> Result<(), TwzError> {
502 let target = self.info().id;
503 monitor_rt_post_signal(Some(target), sig, PostSignalFlags::empty())
504 }
505}
506
507pub struct CompartmentLoader {
509 name: String,
510 root_object: ObjID,
511 args: Vec<String>,
512 env: Option<Vec<String>>,
513 flags: NewCompartmentFlags,
514 config: CompartmentLoaderConfig,
515 _fd_spec: Vec<binding_info>,
516}
517
518fn load_fd_specs_from_runtime() -> Vec<binding_info> {
519 let mut v = vec![binding_info::default(); 8];
520 loop {
521 let len =
522 unsafe { twizzler_rt_abi::bindings::twz_rt_fd_read_binds(v.as_mut_ptr(), v.len()) };
523 if len == v.len() {
524 v.extend_from_slice(&[binding_info::default(); 8]);
525 } else {
526 v.truncate(len);
527 break;
528 }
529 }
530 v
531}
532
533impl CompartmentLoader {
534 pub fn new(
536 compname: impl ToString,
537 exename: impl ToString,
538 root_object: ObjID,
539 flags: NewCompartmentFlags,
540 ) -> Self {
541 let mut config = CompartmentLoaderConfig::default();
542 let fd_spec = load_fd_specs_from_runtime();
543 config.with_fd_spec(&fd_spec);
544 Self {
545 name: format!("{}::{}", compname.to_string(), exename.to_string()),
546 flags,
547 env: None,
548 args: vec![],
549 config,
550 root_object,
551 _fd_spec: fd_spec,
552 }
553 }
554
555 pub fn with_controller(&mut self, con: ControllerOption) -> &mut Self {
556 self.config.controller = con;
557 self
558 }
559
560 pub fn with_fd_specs<'a>(&'a mut self, spec: &'a [binding_info]) -> &'a mut Self {
561 self.config.with_fd_spec(spec);
562 self
563 }
564
565 pub fn args<S: ToString>(&mut self, args: impl IntoIterator<Item = S>) -> &mut Self {
567 for arg in args.into_iter() {
568 self.args.push(arg.to_string())
569 }
570 self
571 }
572
573 pub fn env<S: ToString>(&mut self, env: impl IntoIterator<Item = S>) -> &mut Self {
575 self.env = Some(env.into_iter().map(|s| s.to_string()).collect());
576 self
577 }
578
579 pub fn load(&self) -> Result<CompartmentHandle, TwzError> {
581 fn get_current_env() -> Vec<String> {
582 std::env::vars()
583 .map(|(var, val)| format!("{}={}", var, val))
584 .collect()
585 }
586 let name_len = self.name.as_bytes().len();
587 let args_len = self
588 .args
589 .iter()
590 .fold(0, |acc, arg| acc + arg.as_bytes().len() + 1);
591 let env = self.env.clone().unwrap_or_else(|| get_current_env());
592 let envs_len = env
593 .iter()
594 .fold(0, |acc, arg| acc + arg.as_bytes().len() + 1);
595 let mut bytes = self.name.as_bytes().to_vec();
596 for arg in &self.args {
597 bytes.extend_from_slice(arg.as_bytes());
598 bytes.push(0);
599 }
600 for env in env {
601 bytes.extend_from_slice(env.as_bytes());
602 bytes.push(0);
603 }
604 let len = lazy_sb::write_bytes_to_sb(&bytes);
605 if len < envs_len + args_len + name_len {
606 return Err(ArgumentError::InvalidArgument.into());
607 }
608 let desc = monitor_rt_load_compartment(
609 self.root_object,
610 name_len as u64,
611 args_len as u64,
612 envs_len as u64,
613 self.flags.bits(),
614 (&self.config as *const _) as usize as u64,
615 )?;
616 Ok(CompartmentHandle { desc: Some(desc) })
617 }
618}
619
620impl Handle for CompartmentHandle {
621 type OpenError = TwzError;
622
623 type OpenInfo = ObjID;
624
625 fn open(info: Self::OpenInfo) -> Result<Self, Self::OpenError>
626 where
627 Self: Sized,
628 {
629 let desc = monitor_rt_get_compartment_handle(info)?;
630 Ok(CompartmentHandle { desc: Some(desc) })
631 }
632
633 fn release(&mut self) {
634 if let Some(desc) = self.desc {
635 let _ = monitor_rt_drop_compartment_handle(desc);
636 }
637 }
638}
639
640impl Drop for CompartmentHandle {
641 fn drop(&mut self) {
642 self.release();
643 }
644}
645
646impl Handle for LibraryHandle {
647 type OpenError = TwzError;
648
649 type OpenInfo = (Option<Descriptor>, usize);
650
651 fn open(info: Self::OpenInfo) -> Result<Self, Self::OpenError>
652 where
653 Self: Sized,
654 {
655 let desc = monitor_rt_get_library_handle(info.0, info.1)?;
656 Ok(LibraryHandle { desc })
657 }
658
659 fn release(&mut self) {
660 let _ = monitor_rt_drop_library_handle(self.desc);
661 }
662}
663
664impl Drop for LibraryHandle {
665 fn drop(&mut self) {
666 self.release()
667 }
668}
669
670#[derive(Clone, Debug)]
672pub struct CompartmentInfo<'a> {
673 pub name: String,
675 pub id: ObjID,
677 pub sctx: ObjID,
679 pub flags: CompartmentFlags,
681 pub nr_libs: usize,
683 pub exit_code: u64,
685 _pd: PhantomData<&'a ()>,
686}
687
688impl<'a> CompartmentInfo<'a> {
689 fn from_raw(raw: CompartmentInfoRaw) -> Self {
690 Self {
691 name: lazy_sb::read_string_from_sb(raw.name_len),
692 id: raw.id,
693 sctx: raw.sctx,
694 flags: CompartmentFlags::from_bits_truncate(raw.flags),
695 nr_libs: raw.nr_libs,
696 exit_code: raw.exit_code,
697 _pd: PhantomData,
698 }
699 }
700}
701
702impl CompartmentHandle {
703 pub fn current() -> Self {
705 Self { desc: None }
706 }
707
708 pub fn lookup(name: impl AsRef<str>) -> Result<Self, TwzError> {
710 let name_len = lazy_sb::write_bytes_to_sb(name.as_ref().as_bytes());
711 Ok(Self {
712 desc: Some(monitor_rt_lookup_compartment(name_len)?),
713 })
714 }
715
716 pub fn lookup_id(name: ObjID) -> Result<Self, TwzError> {
718 Ok(Self {
719 desc: Some(monitor_rt_lookup_compartment_id(name)?),
720 })
721 }
722
723 pub fn deps(&self) -> CompartmentDepsIter<'_> {
725 CompartmentDepsIter::new(self)
726 }
727
728 pub fn root(&self) -> LibraryHandle {
730 self.libs().next().unwrap()
731 }
732
733 pub fn libs(&self) -> LibraryIter<'_> {
735 LibraryIter::new(self)
736 }
737
738 pub fn threads(&self) -> CompartmentThreadsIter<'_> {
740 CompartmentThreadsIter::new(self)
741 }
742
743 pub fn wait(&self, flags: CompartmentFlags) -> CompartmentFlags {
744 CompartmentFlags::from_bits_truncate(
745 monitor_rt_compartment_wait(self.desc(), flags.bits()).unwrap(),
746 )
747 }
748}
749
750pub struct LibraryIter<'a> {
752 n: usize,
753 comp: &'a CompartmentHandle,
754}
755
756impl<'a> LibraryIter<'a> {
757 fn new(comp: &'a CompartmentHandle) -> Self {
758 Self { n: 0, comp }
759 }
760}
761
762impl<'a> Iterator for LibraryIter<'a> {
763 type Item = LibraryHandle;
764
765 fn next(&mut self) -> Option<Self::Item> {
766 let handle = LibraryHandle::open((self.comp.desc, self.n)).ok();
767 if handle.is_some() {
768 self.n += 1;
769 }
770 handle
771 }
772}
773
774pub struct CompartmentDepsIter<'a> {
776 n: usize,
777 comp: &'a CompartmentHandle,
778}
779
780impl<'a> CompartmentDepsIter<'a> {
781 fn new(comp: &'a CompartmentHandle) -> Self {
782 Self { n: 0, comp }
783 }
784}
785
786impl<'a> Iterator for CompartmentDepsIter<'a> {
787 type Item = CompartmentHandle;
788
789 fn next(&mut self) -> Option<Self::Item> {
790 let desc = monitor_rt_get_compartment_deps(self.comp.desc, self.n).ok()?;
791 self.n += 1;
792 Some(CompartmentHandle { desc: Some(desc) })
793 }
794
795 fn nth(&mut self, n: usize) -> Option<Self::Item> {
796 self.n += n;
797 self.next()
798 }
799}
800
801pub struct CompartmentThreadsIter<'a> {
803 n: usize,
804 comp: &'a CompartmentHandle,
805}
806
807impl<'a> CompartmentThreadsIter<'a> {
808 fn new(comp: &'a CompartmentHandle) -> Self {
809 Self { n: 0, comp }
810 }
811}
812
813impl<'a> Iterator for CompartmentThreadsIter<'a> {
814 type Item = ThreadInfo;
815
816 fn next(&mut self) -> Option<Self::Item> {
817 let info = monitor_rt_get_compartment_thread(self.comp.desc, self.n).ok()?;
818 self.n += 1;
819 Some(info)
820 }
821
822 fn nth(&mut self, n: usize) -> Option<Self::Item> {
823 self.n += n;
824 self.next()
825 }
826}
827
828bitflags::bitflags! {
829 #[derive(Clone, Debug, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
831 pub struct CompartmentFlags : u64 {
832 const READY = 0x1;
834 const IS_BINARY = 0x2;
836 const THREAD_CAN_EXIT = 0x4;
838 const STARTED = 0x8;
840 const DESTRUCTED = 0x10;
842 const EXITED = 0x20;
844 }
845}
846
847#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Debug)]
849pub struct MappedObjectAddrs {
850 pub slot: usize,
851 pub start: usize,
852 pub meta: usize,
853}
854
855impl MappedObjectAddrs {
856 pub fn new(slot: usize) -> Self {
857 Self {
858 start: slot * MAX_SIZE,
859 meta: (slot + 1) * MAX_SIZE - NULLPAGE_SIZE,
860 slot,
861 }
862 }
863}
864
865pub fn stats() -> Option<MonitorStats> {
867 monitor_rt_stats().ok()
868}
869
870mod lazy_sb {
871 use std::cell::{OnceCell, RefCell};
875
876 use secgate::util::SimpleBuffer;
877 use twizzler_rt_abi::object::MapFlags;
878
879 struct LazyThreadSimpleBuffer {
880 sb: OnceCell<SimpleBuffer>,
881 }
882
883 impl LazyThreadSimpleBuffer {
884 const fn new() -> Self {
885 Self {
886 sb: OnceCell::new(),
887 }
888 }
889
890 fn init() -> SimpleBuffer {
891 let id = super::monitor_rt_get_thread_simple_buffer()
892 .expect("failed to get per-thread monitor simple buffer");
893 let oh =
894 twizzler_rt_abi::object::twz_rt_map_object(id, MapFlags::READ | MapFlags::WRITE)
895 .unwrap();
896 SimpleBuffer::new(oh)
897 }
898
899 fn read(&mut self, buf: &mut [u8]) -> usize {
900 let sb = self.sb.get_or_init(|| Self::init());
901 sb.read(buf)
902 }
903
904 fn write(&mut self, buf: &[u8]) -> usize {
905 if self.sb.get().is_none() {
906 self.sb.set(Self::init()).unwrap();
908 }
909 let sb = self.sb.get_mut().unwrap();
910 sb.write(buf)
911 }
912 }
913
914 #[thread_local]
915 static LAZY_SB: RefCell<LazyThreadSimpleBuffer> = RefCell::new(LazyThreadSimpleBuffer::new());
916
917 pub(super) fn read_string_from_sb(len: usize) -> String {
918 let mut buf = vec![0u8; len];
919 let len = LAZY_SB.borrow_mut().read(&mut buf);
920 String::from_utf8_lossy(&buf[0..len]).to_string()
921 }
922
923 pub(super) fn read_bytes_from_sb(len: usize) -> Vec<u8> {
924 let mut buf = vec![0u8; len];
925 let len = LAZY_SB.borrow_mut().read(&mut buf);
926 buf.truncate(len);
927 buf
928 }
929
930 pub(super) fn write_bytes_to_sb(buf: &[u8]) -> usize {
931 LAZY_SB.borrow_mut().write(buf)
932 }
933}
934
935pub const THREAD_STARTED: u32 = 1;
936#[repr(C)]
937pub struct RuntimeThreadControl {
938 pub id: UnsafeCell<u32>,
939 pub did_exit: UnsafeCell<u32>,
940 pub internal_lock: AtomicU32,
942 pub flags: AtomicU32,
943 pub stack_canary: u64,
944 pub libc_data: [u64; 16],
945}
946
947impl Default for RuntimeThreadControl {
948 fn default() -> Self {
949 Self::new(0)
950 }
951}
952
953impl RuntimeThreadControl {
954 pub const fn new(id: u32) -> Self {
955 Self {
956 internal_lock: AtomicU32::new(0),
957 flags: AtomicU32::new(0),
958 id: UnsafeCell::new(id),
959 did_exit: UnsafeCell::new(0),
960 stack_canary: 0,
961 libc_data: [0; 16],
962 }
963 }
964
965 fn write_lock(&self) {
966 loop {
967 let old = self.internal_lock.fetch_or(1, Ordering::Acquire);
968 if old == 0 {
969 break;
970 }
971 }
972 }
973
974 fn write_unlock(&self) {
975 self.internal_lock.fetch_and(!1, Ordering::Release);
976 }
977
978 fn read_lock(&self) {
979 loop {
980 let old = self.internal_lock.fetch_add(2, Ordering::Acquire);
981 if old > i32::MAX as u32 {
983 twizzler_rt_abi::core::twz_rt_abort();
984 }
985 if old & 1 == 0 {
986 break;
987 }
988 }
989 }
990
991 fn read_unlock(&self) {
992 self.internal_lock.fetch_sub(2, Ordering::Release);
993 }
994
995 pub fn set_id(&self, id: u32) {
996 self.write_lock();
997 unsafe {
998 *self.id.get().as_mut().unwrap() = id;
999 }
1000 self.write_unlock();
1001 }
1002
1003 pub fn id(&self) -> u32 {
1004 self.read_lock();
1005 let id = unsafe { *self.id.get().as_ref().unwrap() };
1006 self.read_unlock();
1007 id
1008 }
1009}
1010
1011pub fn post_signal(
1012 target: Option<ObjID>,
1013 signal: u64,
1014 flags: PostSignalFlags,
1015) -> Result<(), TwzError> {
1016 monitor_rt_post_signal(target, signal, flags)
1017}
1018
1019#[derive(Copy, Clone, Debug)]
1020#[repr(C)]
1021pub struct MonitorStats {
1022 pub space: SpaceStats,
1023 pub thread_mgr: ThreadMgrStats,
1024 pub comp_mgr: CompartmentMgrStats,
1025 pub handles: HandleStats,
1026 pub dynlink: DynlinkStats,
1027}
1028
1029#[derive(Copy, Clone, Debug)]
1030#[repr(C)]
1031pub struct SpaceStats {
1032 pub mapped: usize,
1033}
1034
1035#[derive(Copy, Clone, Debug)]
1036#[repr(C)]
1037pub struct ThreadMgrStats {
1038 pub nr_threads: usize,
1039}
1040
1041#[derive(Copy, Clone, Debug)]
1042#[repr(C)]
1043pub struct CompartmentMgrStats {
1044 pub nr_compartments: usize,
1045}
1046
1047#[derive(Copy, Clone, Debug)]
1048#[repr(C)]
1049pub struct HandleStats {
1050 pub nr_comp_handles: usize,
1051 pub nr_lib_handles: usize,
1052}
1053
1054#[derive(Copy, Clone, Debug)]
1055#[repr(C)]
1056pub struct DynlinkStats {
1057 pub nr_libs: usize,
1058 pub nr_comps: usize,
1059}
1060
1061#[derive(Debug, Copy, Clone)]
1062#[repr(C)]
1063#[allow(dead_code)]
1064pub enum MonitorCompControlCmd {
1065 RuntimeReady,
1066 RuntimePostMain,
1067}
1068
1069#[repr(C)]
1070#[derive(Clone, Copy, Debug)]
1071pub struct LibraryInfoRaw {
1072 pub name_len: usize,
1073 pub compartment_id: ObjID,
1074 pub objid: ObjID,
1075 pub slot: usize,
1076 pub start: *const u8,
1077 pub len: usize,
1078 pub dl_info: DlPhdrInfo,
1079 pub link_map: LinkMap,
1080 pub desc: Descriptor,
1081}
1082
1083unsafe impl Crossing for LibraryInfoRaw {}
1084
1085#[repr(C)]
1086#[derive(Clone, Copy, Debug)]
1087pub struct CompartmentInfoRaw {
1088 pub name_len: usize,
1089 pub id: ObjID,
1090 pub sctx: ObjID,
1091 pub flags: u64,
1092 pub nr_libs: usize,
1093 pub exit_code: u64,
1095}
1096
1097#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Copy)]
1098#[repr(C)]
1099pub struct ThreadInfo {
1100 pub repr_id: ObjID,
1101}
1102
1103pub const MONITOR_INSTANCE_ID: ObjID = ObjID::new(0);
1105
1106bitflags::bitflags! {
1107 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1108 pub struct PostSignalFlags : u32 {
1109 const GROUP = 1;
1110 const CONTROLLER = 2;
1111 }
1112}
1113
1114#[repr(C)]
1115#[derive(Default, Copy, Clone, Debug)]
1116#[allow(dead_code)]
1117pub enum ControllerOption {
1118 #[default]
1119 Inherit,
1120 NoController,
1121 Object(ObjID),
1122}
1123
1124#[repr(C)]
1125#[derive(Default, Copy, Clone, Debug)]
1126#[allow(dead_code)]
1127pub struct CompartmentLoaderConfig {
1128 pub controller: ControllerOption,
1129 pub fd_spec: *const binding_info,
1130 pub fd_spec_len: usize,
1131}
1132
1133impl CompartmentLoaderConfig {
1134 #[allow(dead_code)]
1135 pub fn with_controller(&mut self, controller: ControllerOption) -> &mut Self {
1136 self.controller = controller;
1137 self
1138 }
1139
1140 #[allow(dead_code)]
1141 pub fn with_fd_spec<'a>(&'a mut self, spec: &'a [binding_info]) -> &'a mut Self {
1142 self.fd_spec = spec.as_ptr();
1143 self.fd_spec_len = spec.len();
1144 self
1145 }
1146
1147 #[allow(dead_code)]
1148 pub fn fd_spec(&self) -> &[binding_info] {
1149 unsafe { core::slice::from_raw_parts(self.fd_spec, self.fd_spec_len) }
1150 }
1151}
1152
1153pub fn libname_map(name: &str, id: ObjID) -> Result<(), TwzError> {
1154 let namelen = lazy_sb::write_bytes_to_sb(name.as_bytes());
1155 monitor_rt_libname_map(namelen, id)
1156}
1157
1158pub fn libname_unmap(name: Option<&str>, id: Option<ObjID>) -> Result<(), TwzError> {
1159 let namelen = name.map(|name| lazy_sb::write_bytes_to_sb(name.as_bytes()));
1160 monitor_rt_libname_unmap(namelen, id)
1161}
1162
1163pub fn lookup_library_by_name(name: &str) -> Result<secgate::util::Descriptor, TwzError> {
1165 LibraryHandle::open((None, lazy_sb::write_bytes_to_sb(name.as_bytes())))
1166 .map(|handle| handle.desc())
1167}
1168
1169pub fn lookup_symbol_by_name(
1172 lib_desc: Option<secgate::util::Descriptor>,
1173 name: &str,
1174) -> Result<usize, TwzError> {
1175 let name_len = lazy_sb::write_bytes_to_sb(name.as_bytes());
1176 monitor_rt_lookup_symbol(lib_desc, name_len)
1177}