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 std::alloc::GlobalAlloc;
8
9use dynlink::context::NewCompartmentFlags;
10use miette::IntoDiagnostic;
11use monitor_api::{CompartmentFlags, CompartmentHandle, CompartmentLoader};
12use tracing::{debug, info, warn, Level};
13use tracing_subscriber::FmtSubscriber;
14use twizzler_abi::{object::NULLPAGE_SIZE, simple_mutex::Mutex};
15use twizzler_rt_abi::object::MapFlags;
16
17mod dlengine;
18pub mod init;
19mod mon;
20mod upcall;
21
22pub use monitor_api::MappedObjectAddrs;
23
24#[path = "../secapi/gates.rs"]
25mod gates;
26
27extern crate dynlink;
28extern crate twizzler_runtime;
29
30extern "C-unwind" {
31    fn __monitor_ready();
32}
33
34pub fn main() {
35    // For early init, if something breaks, we really want to see everything...
36    std::env::set_var("RUST_BACKTRACE", "full");
37    let subscriber = FmtSubscriber::builder()
38        .with_max_level(Level::INFO)
39        .with_target(false)
40        .without_time()
41        .finish();
42
43    tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
44
45    miette::set_hook(Box::new(|_| {
46        Box::new(miette::NarratableReportHandler::new().with_cause_chain())
47    }))
48    .unwrap();
49
50    debug!("monitor entered, discovering dynlink context");
51    let init =
52        init::bootstrap_dynlink_context().expect("failed to discover initial dynlink context");
53
54    let mon = mon::Monitor::new(init);
55    mon::set_monitor(mon);
56
57    debug!("ok, starting monitor proper");
58    // Safety: the monitor is ready, and so we can set our runtime as ready to use the monitor.
59    unsafe { __monitor_ready() };
60    // Had to wait till now to be able to spawn threads.
61    mon::get_monitor().start_background_threads();
62
63    std::env::set_var("RUST_BACKTRACE", "1");
64    unsafe {
65        twizzler_rt_abi::bindings::twz_rt_set_upcall_handler(Some(
66            crate::upcall::upcall_monitor_handler_entry,
67        ))
68    };
69
70    let main_thread = std::thread::spawn(monitor_init);
71    let _r = main_thread.join().unwrap().map_err(|e| {
72        tracing::error!("{:?}", e);
73    });
74    warn!("monitor main thread exited");
75}
76
77fn monitor_init() -> miette::Result<()> {
78    // If we have monitor tests to run, do so.
79    if let Some(ki_name) = dlengine::get_kernel_init_info()
80        .names()
81        .iter()
82        .find(|iname| iname.name() == "monitor_test_info")
83    {
84        info!("starting monitor tests [{}]", ki_name.name());
85        // Read the monitor test binary name.
86        const MAX_NAMELEN: usize = 0x1000;
87        let info =
88            twizzler_rt_abi::object::twz_rt_map_object(ki_name.id(), MapFlags::READ).unwrap();
89        let test_name_slice =
90            unsafe { core::slice::from_raw_parts(info.start().add(NULLPAGE_SIZE), MAX_NAMELEN) };
91        let first_null = test_name_slice
92            .iter()
93            .position(|x| *x == 0)
94            .unwrap_or(MAX_NAMELEN - 1);
95        let test_name = String::from_utf8_lossy(&test_name_slice[0..first_null]);
96        debug!("monitor test binary: {}", test_name);
97        if let Some(_ki_name) = dlengine::get_kernel_init_info()
98            .names()
99            .iter()
100            .find(|iname| iname.name() == test_name)
101        {
102            // Load and wait for tests to complete
103            let comp: CompartmentHandle =
104                CompartmentLoader::new("montest", test_name, NewCompartmentFlags::empty())
105                    .args(&["montest", "--test-threads=1"])
106                    .load()
107                    .into_diagnostic()?;
108            let mut flags = comp.info().flags;
109            while !flags.contains(CompartmentFlags::EXITED) {
110                flags = comp.wait(flags);
111            }
112        } else {
113            tracing::error!("failed to start monitor tests: {}", ki_name.name());
114        }
115    }
116
117    info!("monitor early init completed, starting init",);
118    let mut args = vec!["init".to_string()];
119    for arg in std::env::args() {
120        args.push(arg);
121    }
122    let comp: CompartmentHandle =
123        CompartmentLoader::new("init", "init", NewCompartmentFlags::empty())
124            .args(&args)
125            .load()
126            .into_diagnostic()?;
127    let mut flags = comp.info().flags;
128    while !flags.contains(CompartmentFlags::EXITED) {
129        flags = comp.wait(flags);
130    }
131
132    tracing::warn!("init exited");
133
134    Ok(())
135}
136
137struct MonAlloc {
138    track: Mutex<Track>,
139}
140
141struct Track {
142    ips: [usize; 4096],
143    count: [usize; 4096],
144    idx: usize,
145}
146
147#[allow(dead_code)]
148impl Track {
149    const fn new() -> Self {
150        Self {
151            ips: [0; 4096],
152            count: [0; 4096],
153            idx: 0,
154        }
155    }
156
157    fn insert(&mut self, ip: *mut u8) {
158        let addr = ip.addr() + 1;
159        let existing = self.ips.iter().position(|i| *i == addr);
160        if let Some(existing) = existing {
161            self.count[existing] += 1;
162        } else if self.idx < 4096 {
163            self.ips[self.idx] = addr;
164            self.count[self.idx] = 1;
165            self.idx += 1;
166        } else {
167            twizzler_abi::klog_println!("dropping ip {:x}", addr);
168        }
169    }
170
171    fn reset(&mut self) {
172        self.idx = 0;
173        self.ips.fill(0);
174        self.count.fill(0);
175    }
176
177    fn print(&self) {
178        for pair in self.ips[0..self.idx]
179            .iter()
180            .zip(self.count[0..self.idx].iter())
181        {
182            twizzler_abi::klog_println!("==> {:x} {}", pair.0, pair.1);
183        }
184    }
185}
186
187use twizzler_rt_abi::alloc::AllocFlags;
188unsafe impl GlobalAlloc for MonAlloc {
189    #[track_caller]
190    unsafe fn alloc(&self, layout: std::alloc::Layout) -> *mut u8 {
191        twizzler_rt_abi::alloc::twz_rt_malloc(layout, AllocFlags::empty())
192            .unwrap_or(core::ptr::null_mut())
193    }
194
195    unsafe fn dealloc(&self, ptr: *mut u8, layout: std::alloc::Layout) {
196        twizzler_rt_abi::alloc::twz_rt_dealloc(ptr, layout, AllocFlags::empty());
197    }
198}
199
200//#[global_allocator]
201static MA: MonAlloc = MonAlloc {
202    track: Mutex::new(Track::new()),
203};
204
205pub fn print_alloc_stats() {
206    MA.track.lock().print();
207}
208
209pub fn reset_alloc_stats() {
210    MA.track.lock().reset();
211}