1use std::io::{Read, Write};
2
3use embedded_io::ErrorType;
4use monitor_api::{CompartmentFlags, CompartmentHandle, CompartmentLoader, NewCompartmentFlags};
5use tracing::{info, warn};
6use twizzler::{error::RawTwzError, object::RawObject};
7use twizzler_abi::{
8 object::ObjID,
9 pager::{CompletionToKernel, CompletionToPager, RequestFromKernel, RequestFromPager},
10 syscall::{sys_new_handle, NewHandleFlags},
11};
12use twizzler_queue::Queue;
13
14struct TwzIo;
15
16impl ErrorType for TwzIo {
17 type Error = std::io::Error;
18}
19
20impl embedded_io::Read for TwzIo {
21 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
22 let len = std::io::stdin().read(buf)?;
23
24 Ok(len)
25 }
26}
27
28impl embedded_io::Write for TwzIo {
29 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
30 std::io::stdout().write(buf)
31 }
32
33 fn flush(&mut self) -> Result<(), Self::Error> {
34 std::io::stdout().flush()
35 }
36}
37
38fn initialize_pager() -> ObjID {
39 info!("starting pager");
40 const DEFAULT_PAGER_QUEUE_LEN: usize = 1024;
41 let queue_obj = unsafe {
42 twizzler::object::ObjectBuilder::<()>::default()
43 .build_ctor(|obj| {
44 twizzler_queue::Queue::<RequestFromKernel, CompletionToKernel>::init(
45 obj.handle(),
46 DEFAULT_PAGER_QUEUE_LEN,
47 DEFAULT_PAGER_QUEUE_LEN,
48 )
49 })
50 .expect("failed to create pager queue")
51 };
52 let queue = Queue::<RequestFromKernel, CompletionToKernel>::from(queue_obj.into_handle());
53
54 sys_new_handle(
55 queue.handle().id(),
56 twizzler_abi::syscall::HandleType::PagerQueue,
57 NewHandleFlags::empty(),
58 )
59 .expect("failed to setup pager queue");
60
61 let queue2_obj = unsafe {
62 twizzler::object::ObjectBuilder::<()>::default()
63 .build_ctor(|obj| {
64 twizzler_queue::Queue::<RequestFromPager, CompletionToPager>::init(
65 obj.handle(),
66 DEFAULT_PAGER_QUEUE_LEN,
67 DEFAULT_PAGER_QUEUE_LEN,
68 )
69 })
70 .expect("failed to create pager queue")
71 };
72 let queue2 = Queue::<RequestFromPager, CompletionToPager>::from(queue2_obj.into_handle());
73 sys_new_handle(
74 queue2.handle().id(),
75 twizzler_abi::syscall::HandleType::PagerQueue,
76 NewHandleFlags::empty(),
77 )
78 .unwrap();
79
80 let pager_comp: CompartmentHandle = monitor_api::CompartmentLoader::new(
81 "pager-srv",
82 "libpager_srv.so",
83 monitor_api::NewCompartmentFlags::EXPORT_GATES,
84 )
85 .args(["pager-srv"])
86 .load()
87 .expect("failed to start pager");
88
89 let pager_start = unsafe {
90 pager_comp
91 .dynamic_gate::<(ObjID, ObjID), ObjID>("pager_start")
92 .unwrap()
93 };
94 let bootstrap_id = pager_start(queue.handle().id(), queue2.handle().id()).unwrap();
95 std::mem::forget(pager_comp);
96 bootstrap_id
97}
98
99fn initialize_namer(bootstrap: ObjID) -> ObjID {
100 info!("starting namer");
101 let nmcomp: CompartmentHandle = CompartmentLoader::new(
102 "naming",
103 "libnaming_srv.so",
104 NewCompartmentFlags::EXPORT_GATES,
105 )
106 .args(&["naming"])
107 .load()
108 .expect("failed to initialize namer");
109 let mut flags = nmcomp.info().flags;
110 while !flags.contains(CompartmentFlags::READY) {
111 flags = nmcomp.wait(flags);
112 }
113
114 let namer_start = unsafe {
115 nmcomp
116 .dynamic_gate::<(ObjID,), ObjID>("namer_start")
117 .unwrap()
118 };
119 let root_id = namer_start(bootstrap);
120 tracing::info!("naming ready");
121 std::mem::forget(nmcomp);
122 root_id.ok().expect("failed to start namer")
123}
124
125fn initialize_devmgr() {
126 info!("starting device manager");
127 let devcomp: CompartmentHandle = CompartmentLoader::new(
128 "devmgr",
129 "libdevmgr_srv.so",
130 NewCompartmentFlags::EXPORT_GATES,
131 )
132 .args(&["devmgr"])
133 .load()
134 .expect("failed to initialize device manager");
135 let mut flags = devcomp.info().flags;
136 while !flags.contains(CompartmentFlags::READY) {
137 flags = devcomp.wait(flags);
138 }
139
140 let devmgr_start = unsafe { devcomp.dynamic_gate::<(), ()>("devmgr_start").unwrap() };
141 devmgr_start().unwrap();
142 tracing::info!("device manager ready");
143 std::mem::forget(devcomp);
144}
145
146fn initialize_cache() {
147 info!("starting cache service");
148 let comp: CompartmentHandle = CompartmentLoader::new(
149 "cache",
150 "libcache_srv.so",
151 NewCompartmentFlags::EXPORT_GATES,
152 )
153 .args(&["cache-srv"])
154 .load()
155 .expect("failed to initialize cache manager");
156 let mut flags = comp.info().flags;
157 while !flags.contains(CompartmentFlags::READY) {
158 flags = comp.wait(flags);
159 }
160 tracing::info!("cache manager ready");
161 std::mem::forget(comp);
162}
163
164fn initialize_display() {
165 info!("starting display manager");
166 let comp: CompartmentHandle = CompartmentLoader::new(
167 "display",
168 "libdisplay_srv.so",
169 NewCompartmentFlags::EXPORT_GATES,
170 )
171 .args(&["display-srv"])
172 .load()
173 .expect("failed to initialize display manager");
174 let mut flags = comp.info().flags;
175 while !flags.contains(CompartmentFlags::READY) {
176 flags = comp.wait(flags);
177 }
178 let start_display = unsafe {
179 comp.dynamic_gate::<(), RawTwzError>("start_display")
180 .unwrap()
181 };
182 let _ = start_display();
183 tracing::info!("display manager ready");
184 std::mem::forget(comp);
185}
186
187fn main() {
188 tracing::subscriber::set_global_default(
189 tracing_subscriber::fmt()
190 .with_max_level(tracing::Level::INFO)
191 .without_time()
192 .finish(),
193 )
194 .unwrap();
195
196 let mut autostart = None;
197 let mut start_unittest = false;
198 for arg in std::env::args().skip(1) {
199 match arg.as_str() {
200 "--tests" | "--bench" | "--benches" => start_unittest = true,
201 _ => autostart = Some(arg),
202 }
203 }
204
205 tracing::info!("starting logger");
206 let lbcomp: CompartmentHandle = CompartmentLoader::new(
207 "logboi",
208 "liblogboi_srv.so",
209 NewCompartmentFlags::EXPORT_GATES,
210 )
211 .args(&["logboi"])
212 .load()
213 .unwrap();
214 let mut flags = lbcomp.info().flags;
215 while !flags.contains(CompartmentFlags::READY) {
216 flags = lbcomp.wait(flags);
217 }
218 std::mem::forget(lbcomp);
219
220 initialize_devmgr();
221
222 let bootstrap_id = initialize_pager();
223
224 let root_id = initialize_namer(bootstrap_id);
225
226 tracing::info!("setting monitor nameroot: {}", root_id);
228 let _ = monitor_api::set_nameroot(root_id)
229 .inspect_err(|_| tracing::warn!("failed to set nameroot for monitor"));
230
231 initialize_cache();
232 initialize_display();
233
234 if start_unittest {
235 run_tests();
237 }
238
239 let utils = [
240 "ls", "cat", "base64", "base32", "basename", "basenc", "cksum", "comm", "csplit", "cut",
241 "date", "echo", "expand", "factor", "false", "fmt", "fold", "ln", "nl", "numfmt", "od",
242 "paste", "pr", "printenv", "printf", "ptx", "seq", "shuf", "sleep", "sort", "sum", "tr",
243 "true", "tsort", "unexpand", "uniq", "yes",
244 ];
245 for util in utils {
246 let link = format!("/initrd/{}", util);
247 tracing::debug!("creating link: {}", link);
248 let _ = std::os::twizzler::fs::symlink("uuhelper", link)
249 .inspect_err(|e| tracing::warn!("failed to softlink util {}: {}", util, e));
250 }
251
252 println!("Hi, welcome to the basic twizzler test console.");
253
254 if let Some(autostart) = autostart {
255 println!("autostart: {}", autostart);
256 let comp = CompartmentLoader::new(&autostart, &autostart, NewCompartmentFlags::empty())
257 .args(&[&autostart])
258 .load();
259 if let Ok(comp) = comp {
260 let mut flags = comp.info().flags;
261 while !flags.contains(CompartmentFlags::EXITED) {
262 flags = comp.wait(flags);
263 }
264 } else {
265 warn!("failed to start {}", autostart);
266 }
267 }
268
269 println!("To run a program, type its name.");
270
271 let mut io = TwzIo;
272 let mut buffer = [0; 1024];
273 let mut history = [0; 1024];
274 let mut editor = noline::builder::EditorBuilder::from_slice(&mut buffer)
275 .with_slice_history(&mut history)
276 .build_sync(&mut io)
277 .unwrap();
278 loop {
279 let line = editor.readline("twz> ", &mut io).unwrap();
282 let cmd = line.split_whitespace().collect::<Vec<_>>();
283 if cmd.len() == 0 {
284 continue;
285 }
286
287 let background = cmd.iter().any(|s| *s == "&");
288
289 let cmd = cmd.into_iter().map(|s| as_env(s)).collect::<Vec<_>>();
291 let vars = cmd
292 .iter()
293 .filter_map(|r| match r {
294 Ok((k, v)) => Some((k, v)),
295 Err(_) => None,
296 })
297 .collect::<Vec<_>>();
298 let cmd = cmd
299 .iter()
300 .filter_map(|r| match r {
301 Ok(_) => None,
302 Err(s) => Some(s),
303 })
304 .collect::<Vec<_>>();
305
306 tracing::debug!("got env: {:?}, cmd: {:?}", vars, cmd);
307
308 let comp = CompartmentLoader::new(cmd[0], cmd[0], NewCompartmentFlags::empty())
309 .args(&cmd)
310 .env(vars.into_iter().map(|(k, v)| format!("{}={}", k, v)))
311 .load();
312 if let Ok(comp) = comp {
313 if background {
314 tracing::info!("continuing compartment {} in background", cmd[0]);
315 } else {
316 let mut flags = comp.info().flags;
317 while !flags.contains(CompartmentFlags::EXITED) {
318 flags = comp.wait(flags);
319 }
320 }
321 } else {
322 warn!("failed to start {}", cmd[0]);
323 }
324 }
325}
326
327fn as_env<'a>(s: &'a str) -> Result<(&'a str, &'a str), &'a str> {
328 let mut split = s.split("=");
329 Ok((split.next().ok_or(s)?, split.next().ok_or(s)?))
330}
331
332fn run_tests() {
354 let comp = CompartmentLoader::new("unittest", "unittest", NewCompartmentFlags::empty())
355 .args(&["unittest"])
356 .load()
357 .expect("failed to start unittest");
358 let mut flags = comp.info().flags;
359 while !flags.contains(CompartmentFlags::EXITED) {
360 println!("waiting for comp state change: {:?}", flags);
361 flags = comp.wait(flags);
362 }
363
364 println!("unittests finished");
365
366 #[allow(deprecated)]
367 twizzler_abi::syscall::sys_debug_shutdown(0);
368}