monitor/mon/compartment/
compthread.rs

1use std::time::Instant;
2
3use dynlink::{compartment::MONITOR_COMPARTMENT_ID, context::Context};
4use miette::IntoDiagnostic;
5use twizzler_abi::{
6    object::MAX_SIZE,
7    upcall::{ResumeFlags, UpcallFrame},
8};
9use twizzler_rt_abi::object::ObjID;
10
11use crate::mon::{
12    space::MapHandle,
13    thread::{ManagedThread, ThreadMgr, DEFAULT_STACK_SIZE, STACK_SIZE_MIN_ALIGN},
14};
15
16#[allow(dead_code)]
17pub struct CompThread {
18    pub(crate) stack_object: StackObject,
19    pub(crate) thread: ManagedThread,
20}
21
22impl CompThread {
23    /// Start a new thread using the given stack, in the provided security context instance, using
24    /// the start function.
25    #[allow(clippy::too_many_arguments)]
26    pub fn new(
27        tmgr: &mut ThreadMgr,
28        dynlink: &mut Context,
29        stack: StackObject,
30        instance: ObjID,
31        main_thread_comp: Option<ObjID>,
32        entry: usize,
33        arg: usize,
34        suspend_on_start: bool,
35    ) -> miette::Result<Self> {
36        let _start = Instant::now();
37        let frame = stack.get_entry_frame(instance, entry, arg);
38        let start = move || {
39            let _enter = Instant::now();
40            tracing::trace!("thread entry took {}ms", (_enter - _start).as_millis());
41            twizzler_abi::syscall::sys_sctx_attach(instance).unwrap();
42
43            let flags = if suspend_on_start {
44                ResumeFlags::SUSPEND
45            } else {
46                ResumeFlags::empty()
47            };
48            unsafe { twizzler_abi::syscall::sys_thread_resume_from_upcall(&frame, flags) };
49        };
50        let mon = dynlink.get_compartment_mut(MONITOR_COMPARTMENT_ID).unwrap();
51        let mt = tmgr
52            .start_thread(mon, Box::new(start), main_thread_comp, instance)
53            .into_diagnostic()?;
54        Ok(Self {
55            stack_object: stack,
56            thread: mt,
57        })
58    }
59}
60
61pub(crate) struct StackObject {
62    handle: MapHandle,
63    stack_size: usize,
64}
65
66impl StackObject {
67    /// Make a new stack object from a given handle and stack size.
68    pub fn new(handle: MapHandle, stack_size: usize) -> miette::Result<Self> {
69        // Find the stack size, with max and min values, and correct alignment.
70        let stack_size = stack_size
71            .clamp(DEFAULT_STACK_SIZE, MAX_SIZE / 2)
72            .next_multiple_of(STACK_SIZE_MIN_ALIGN);
73
74        Ok(Self { handle, stack_size })
75    }
76
77    /// Get the start start address for the compartment.
78    pub fn stack_comp_start(&self) -> usize {
79        self.handle.addrs().start
80    }
81
82    /// Get the stack size.
83    pub fn stack_size(&self) -> usize {
84        self.stack_size
85    }
86
87    // This works for architectures where the stack grows down. If your architecture does not use a
88    // downward-growing stack, implement this function differently.
89    #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
90    /// Get the initial stack pointer.
91    pub fn initial_stack_ptr(&self) -> usize {
92        self.stack_comp_start() + self.stack_size
93    }
94
95    /// Get the entry frame for this thread into a given compartment.
96    pub fn get_entry_frame(&self, ctx: ObjID, entry: usize, arg: usize) -> UpcallFrame {
97        UpcallFrame::new_entry_frame(
98            self.initial_stack_ptr(),
99            self.stack_size(),
100            0,
101            ctx,
102            entry,
103            arg,
104        )
105    }
106}