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::{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    // Set new nameroot for the monitor
227    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        // Load and wait for tests to complete
236        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 mstats = monitor_api::stats().unwrap();
280        //println!("{:?}", mstats);
281        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        // Find env vars
290        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
332/*
333fn get_kernel_init_info() -> &'static KernelInitInfo {
334    unsafe {
335        (((twizzler_abi::slot::RESERVED_KERNEL_INIT * MAX_SIZE) + NULLPAGE_SIZE)
336            as *const KernelInitInfo)
337            .as_ref()
338            .unwrap()
339    }
340}
341
342fn find_init_name(name: &str) -> Option<ObjID> {
343    let init_info = get_kernel_init_info();
344    for n in init_info.names() {
345        if n.name() == name {
346            return Some(n.id());
347        }
348    }
349    None
350}
351*/
352
353fn 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}