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        // Find env vars
264        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
302/*
303fn get_kernel_init_info() -> &'static KernelInitInfo {
304    unsafe {
305        (((twizzler_abi::slot::RESERVED_KERNEL_INIT * MAX_SIZE) + NULLPAGE_SIZE)
306            as *const KernelInitInfo)
307            .as_ref()
308            .unwrap()
309    }
310}
311
312fn find_init_name(name: &str) -> Option<ObjID> {
313    let init_info = get_kernel_init_info();
314    for n in init_info.names() {
315        if n.name() == name {
316            return Some(n.id());
317        }
318    }
319    None
320}
321*/
322
323fn 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}