1use std::io::{Read, Write};
2
3use embedded_io::ErrorType;
4use monitor_api::{CompartmentFlags, CompartmentHandle, CompartmentLoader, NewCompartmentFlags};
5use tracing::{info, warn};
6use twizzler::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 main() {
165 tracing::subscriber::set_global_default(
166 tracing_subscriber::fmt()
167 .with_max_level(tracing::Level::INFO)
168 .without_time()
169 .finish(),
170 )
171 .unwrap();
172
173 let mut autostart = None;
174 let mut start_unittest = false;
175 for arg in std::env::args().skip(1) {
176 match arg.as_str() {
177 "--tests" | "--bench" | "--benches" => start_unittest = true,
178 _ => autostart = Some(arg),
179 }
180 }
181
182 tracing::info!("starting logger");
183 let lbcomp: CompartmentHandle = CompartmentLoader::new(
184 "logboi",
185 "liblogboi_srv.so",
186 NewCompartmentFlags::EXPORT_GATES,
187 )
188 .args(&["logboi"])
189 .load()
190 .unwrap();
191 let mut flags = lbcomp.info().flags;
192 while !flags.contains(CompartmentFlags::READY) {
193 flags = lbcomp.wait(flags);
194 }
195 std::mem::forget(lbcomp);
196
197 initialize_devmgr();
198
199 let bootstrap_id = initialize_pager();
200
201 let root_id = initialize_namer(bootstrap_id);
202
203 tracing::info!("setting monitor nameroot: {}", root_id);
205 let _ = monitor_api::set_nameroot(root_id)
206 .inspect_err(|_| tracing::warn!("failed to set nameroot for monitor"));
207
208 initialize_cache();
209
210 if start_unittest {
211 run_tests();
213 }
214
215 let utils = [
216 "ls", "cat", "base64", "base32", "basename", "basenc", "cksum", "comm", "csplit", "cut",
217 "date", "echo", "expand", "factor", "false", "fmt", "fold", "ln", "nl", "numfmt", "od",
218 "paste", "pr", "printenv", "printf", "ptx", "seq", "shuf", "sleep", "sort", "sum", "tr",
219 "true", "tsort", "unexpand", "uniq", "yes",
220 ];
221 for util in utils {
222 let link = format!("/initrd/{}", util);
223 tracing::debug!("creating link: {}", link);
224 let _ = std::os::twizzler::fs::symlink("uuhelper", link)
225 .inspect_err(|e| tracing::warn!("failed to softlink util {}: {}", util, e));
226 }
227
228 println!("Hi, welcome to the basic twizzler test console.");
229
230 if let Some(autostart) = autostart {
231 println!("autostart: {}", autostart);
232 let comp = CompartmentLoader::new(&autostart, &autostart, NewCompartmentFlags::empty())
233 .args(&[&autostart])
234 .load();
235 if let Ok(comp) = comp {
236 let mut flags = comp.info().flags;
237 while !flags.contains(CompartmentFlags::EXITED) {
238 flags = comp.wait(flags);
239 }
240 } else {
241 warn!("failed to start {}", autostart);
242 }
243 }
244
245 println!("To run a program, type its name.");
246
247 let mut io = TwzIo;
248 let mut buffer = [0; 1024];
249 let mut history = [0; 1024];
250 let mut editor = noline::builder::EditorBuilder::from_slice(&mut buffer)
251 .with_slice_history(&mut history)
252 .build_sync(&mut io)
253 .unwrap();
254 loop {
255 let line = editor.readline("twz> ", &mut io).unwrap();
258 let cmd = line.split_whitespace().collect::<Vec<_>>();
259 if cmd.len() == 0 {
260 continue;
261 }
262
263 let cmd = cmd.into_iter().map(|s| as_env(s)).collect::<Vec<_>>();
265 let vars = cmd
266 .iter()
267 .filter_map(|r| match r {
268 Ok((k, v)) => Some((k, v)),
269 Err(_) => None,
270 })
271 .collect::<Vec<_>>();
272 let cmd = cmd
273 .iter()
274 .filter_map(|r| match r {
275 Ok(_) => None,
276 Err(s) => Some(s),
277 })
278 .collect::<Vec<_>>();
279
280 tracing::debug!("got env: {:?}, cmd: {:?}", vars, cmd);
281
282 let comp = CompartmentLoader::new(cmd[0], cmd[0], NewCompartmentFlags::empty())
283 .args(&cmd)
284 .env(vars.into_iter().map(|(k, v)| format!("{}={}", k, v)))
285 .load();
286 if let Ok(comp) = comp {
287 let mut flags = comp.info().flags;
288 while !flags.contains(CompartmentFlags::EXITED) {
289 flags = comp.wait(flags);
290 }
291 } else {
292 warn!("failed to start {}", cmd[0]);
293 }
294 }
295}
296
297fn as_env<'a>(s: &'a str) -> Result<(&'a str, &'a str), &'a str> {
298 let mut split = s.split("=");
299 Ok((split.next().ok_or(s)?, split.next().ok_or(s)?))
300}
301
302fn run_tests() {
324 let comp = CompartmentLoader::new("unittest", "unittest", NewCompartmentFlags::empty())
325 .args(&["unittest"])
326 .load()
327 .expect("failed to start unittest");
328 let mut flags = comp.info().flags;
329 while !flags.contains(CompartmentFlags::EXITED) {
330 flags = comp.wait(flags);
331 }
332
333 println!("unittests finished");
334
335 #[allow(deprecated)]
336 twizzler_abi::syscall::sys_debug_shutdown(0);
337}