init/
main.rs

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    // Set new nameroot for the monitor
204    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        // Load and wait for tests to complete
212        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 mstats = monitor_api::stats().unwrap();
256        //println!("{:?}", mstats);
257        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 background = cmd.iter().any(|s| *s == "&");
264
265        // Find env vars
266        let cmd = cmd.into_iter().map(|s| as_env(s)).collect::<Vec<_>>();
267        let vars = cmd
268            .iter()
269            .filter_map(|r| match r {
270                Ok((k, v)) => Some((k, v)),
271                Err(_) => None,
272            })
273            .collect::<Vec<_>>();
274        let cmd = cmd
275            .iter()
276            .filter_map(|r| match r {
277                Ok(_) => None,
278                Err(s) => Some(s),
279            })
280            .collect::<Vec<_>>();
281
282        tracing::debug!("got env: {:?}, cmd: {:?}", vars, cmd);
283
284        let comp = CompartmentLoader::new(cmd[0], cmd[0], NewCompartmentFlags::empty())
285            .args(&cmd)
286            .env(vars.into_iter().map(|(k, v)| format!("{}={}", k, v)))
287            .load();
288        if let Ok(comp) = comp {
289            if background {
290                tracing::info!("continuing compartment {} in background", cmd[0]);
291            } else {
292                let mut flags = comp.info().flags;
293                while !flags.contains(CompartmentFlags::EXITED) {
294                    flags = comp.wait(flags);
295                }
296            }
297        } else {
298            warn!("failed to start {}", cmd[0]);
299        }
300    }
301}
302
303fn as_env<'a>(s: &'a str) -> Result<(&'a str, &'a str), &'a str> {
304    let mut split = s.split("=");
305    Ok((split.next().ok_or(s)?, split.next().ok_or(s)?))
306}
307
308/*
309fn get_kernel_init_info() -> &'static KernelInitInfo {
310    unsafe {
311        (((twizzler_abi::slot::RESERVED_KERNEL_INIT * MAX_SIZE) + NULLPAGE_SIZE)
312            as *const KernelInitInfo)
313            .as_ref()
314            .unwrap()
315    }
316}
317
318fn find_init_name(name: &str) -> Option<ObjID> {
319    let init_info = get_kernel_init_info();
320    for n in init_info.names() {
321        if n.name() == name {
322            return Some(n.id());
323        }
324    }
325    None
326}
327*/
328
329fn run_tests() {
330    let comp = CompartmentLoader::new("unittest", "unittest", NewCompartmentFlags::empty())
331        .args(&["unittest"])
332        .load()
333        .expect("failed to start unittest");
334    let mut flags = comp.info().flags;
335    while !flags.contains(CompartmentFlags::EXITED) {
336        println!("waiting for comp state change: {:?}", flags);
337        flags = comp.wait(flags);
338    }
339
340    println!("unittests finished");
341
342    #[allow(deprecated)]
343    twizzler_abi::syscall::sys_debug_shutdown(0);
344}