monitor/
main.rs

1#![feature(naked_functions)]
2#![feature(thread_local)]
3#![feature(new_zeroed_alloc)]
4#![feature(iterator_try_collect)]
5#![feature(linkage)]
6
7use dynlink::context::NewCompartmentFlags;
8use miette::IntoDiagnostic;
9use monitor_api::{CompartmentFlags, CompartmentHandle, CompartmentLoader};
10use tracing::{debug, info, warn, Level};
11use tracing_subscriber::FmtSubscriber;
12use twizzler_abi::object::NULLPAGE_SIZE;
13use twizzler_rt_abi::object::MapFlags;
14
15mod dlengine;
16pub mod init;
17mod mon;
18mod upcall;
19
20pub use monitor_api::MappedObjectAddrs;
21
22#[path = "../secapi/gates.rs"]
23mod gates;
24
25extern crate dynlink;
26extern crate twizzler_runtime;
27
28extern "C-unwind" {
29    fn __monitor_ready();
30}
31
32pub fn main() {
33    // For early init, if something breaks, we really want to see everything...
34    std::env::set_var("RUST_BACKTRACE", "full");
35    let subscriber = FmtSubscriber::builder()
36        .with_max_level(Level::INFO)
37        .with_target(false)
38        .without_time()
39        .finish();
40
41    tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
42
43    miette::set_hook(Box::new(|_| {
44        Box::new(miette::NarratableReportHandler::new().with_cause_chain())
45    }))
46    .unwrap();
47
48    debug!("monitor entered, discovering dynlink context");
49    let init =
50        init::bootstrap_dynlink_context().expect("failed to discover initial dynlink context");
51
52    let mon = mon::Monitor::new(init);
53    mon::set_monitor(mon);
54
55    debug!("ok, starting monitor proper");
56    // Safety: the monitor is ready, and so we can set our runtime as ready to use the monitor.
57    unsafe { __monitor_ready() };
58    // Had to wait till now to be able to spawn threads.
59    mon::get_monitor().start_background_threads();
60
61    std::env::set_var("RUST_BACKTRACE", "1");
62    unsafe {
63        twizzler_rt_abi::bindings::twz_rt_set_upcall_handler(Some(
64            crate::upcall::upcall_monitor_handler_entry,
65        ))
66    };
67
68    let main_thread = std::thread::spawn(monitor_init);
69    let _r = main_thread.join().unwrap().map_err(|e| {
70        tracing::error!("{:?}", e);
71    });
72    warn!("monitor main thread exited");
73}
74
75fn monitor_init() -> miette::Result<()> {
76    // If we have monitor tests to run, do so.
77    if let Some(ki_name) = dlengine::get_kernel_init_info()
78        .names()
79        .iter()
80        .find(|iname| iname.name() == "monitor_test_info")
81    {
82        info!("starting monitor tests [{}]", ki_name.name());
83        // Read the monitor test binary name.
84        const MAX_NAMELEN: usize = 0x1000;
85        let info =
86            twizzler_rt_abi::object::twz_rt_map_object(ki_name.id(), MapFlags::READ).unwrap();
87        let test_name_slice =
88            unsafe { core::slice::from_raw_parts(info.start().add(NULLPAGE_SIZE), MAX_NAMELEN) };
89        let first_null = test_name_slice
90            .iter()
91            .position(|x| *x == 0)
92            .unwrap_or(MAX_NAMELEN - 1);
93        let test_name = String::from_utf8_lossy(&test_name_slice[0..first_null]);
94        debug!("monitor test binary: {}", test_name);
95        if let Some(_ki_name) = dlengine::get_kernel_init_info()
96            .names()
97            .iter()
98            .find(|iname| iname.name() == test_name)
99        {
100            // Load and wait for tests to complete
101            let comp: CompartmentHandle =
102                CompartmentLoader::new("montest", test_name, NewCompartmentFlags::empty())
103                    .args(&["montest", "--test-threads=1"])
104                    .load()
105                    .into_diagnostic()?;
106            let mut flags = comp.info().flags;
107            while !flags.contains(CompartmentFlags::EXITED) {
108                flags = comp.wait(flags);
109            }
110        } else {
111            tracing::error!("failed to start monitor tests: {}", ki_name.name());
112        }
113    }
114
115    info!("monitor early init completed, starting init");
116    let mut args = vec!["init".to_string()];
117    for arg in std::env::args() {
118        args.push(arg);
119    }
120    let comp: CompartmentHandle =
121        CompartmentLoader::new("init", "init", NewCompartmentFlags::empty())
122            .args(&args)
123            .load()
124            .into_diagnostic()?;
125    let mut flags = comp.info().flags;
126    while !flags.contains(CompartmentFlags::EXITED) {
127        flags = comp.wait(flags);
128    }
129
130    tracing::warn!("init exited");
131
132    Ok(())
133}