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 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 unsafe { __monitor_ready() };
60 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 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 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 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
200static 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}