//! What init starts, in order: the system's boot policy, as data. use types::budget::Limits; /// Whether a program holds the session: who is signed in, signing out. #[derive(Clone, Copy, PartialEq, Eq)] pub enum Session { No, /// For itself only (the shell). Own, /// To pass on to apps granted `session` (the permission manager). PassOn, } /// A board device init hands to a program over its endpoint. #[derive(Clone, Copy, PartialEq, Eq)] pub enum Device { Gpu, Input, Keystore, Random, } /// A storage grant: a folder (or the whole disk, `b""`) and whether it may /// be changed. With `user`, the path is inside the signed-in user's folder. #[derive(Clone, Copy)] pub struct Scope { pub path: &'static [u8], pub write: bool, pub user: bool, } const fn disk(path: &'static [u8], write: bool) -> Scope { Scope { path, write, user: false } } const fn users(path: &'static [u8], write: bool) -> Scope { Scope { path, write, user: true } } pub struct Program { pub name: &'static str, pub file: &'static [u8], pub limits: Limits, /// Its stack, in pages. pub stack_pages: usize, /// Serves an endpoint, which it finds in slot 0. pub serves: bool, /// Handed over in this order, after it starts. pub devices: &'static [Device], /// Earlier programs' endpoints it may call, in its next slots; each /// program's copy carries its own badge, so a server can tell them apart. pub uses: &'static [&'static str], /// Storage it may reach, in the slots after `uses`. pub storage: &'static [Scope], /// Takes the console over from init; everyone else prints through it. pub console: bool, /// May have init spawn programs, whose limits together stay within this. pub spawns: Option, /// May halt the machine. pub system_control: bool, /// The session (`types::spawn::SIGN_OUT`, `WHO`), in the next slot. pub session: Session, /// Takes Ctrl+C: a terminal copy with `types::terminal::CONTROL`, last. pub takes_ctrl_c: bool, /// Started again if it dies (see init's supervise.rs). pub restart: bool, /// Its clients keep state in it (a subscription, focus, a handle), so /// they are restarted after it is. pub restarts_clients: bool, /// Pinged by the watchdog (see init's watchdog.rs): not if a handler of /// its waits for the user, which a ping cannot tell from a hang. pub pinged: bool, } /// Enough for a small program: its image, stack and a little heap. pub const SMALL: Limits = Limits { pages: 64, endpoints: 2, notifications: 2, regions: 2, }; const fn server(name: &'static str, file: &'static [u8], limits: Limits) -> Program { Program { name, file, limits, stack_pages: crate::load::STACK_PAGES, serves: true, devices: &[], uses: &[], storage: &[], console: false, spawns: None, system_control: false, session: Session::No, takes_ctrl_c: false, restart: true, restarts_clients: false, pinged: true, } } /// Started on every boot. The log server comes first so the rest can print. pub const SERVERS: &[Program] = &[ Program { console: true, ..server("log", b"bin/log", SMALL) }, // The display subscribes to it. Program { devices: &[Device::Input], restarts_clients: true, ..server("input", b"bin/input", Limits { regions: 4, ..SMALL }) }, // The input server's only client: it passes input on to the app in focus. Program { devices: &[Device::Gpu], uses: &["input"], // The themes, read once at start. storage: &[disk(b"themes", false)], // Its clients subscribe and take focus. restarts_clients: true, // Its windows' state (input queues among it) is ~10 KiB, and the // server is built on the stack. stack_pages: 14, // The framebuffer is ~1000 pages at 1280x800, and so is each of // the (at most 8) windows' pixel buffers, which it owns. ..server("display", b"bin/display", Limits { pages: 9300, regions: 13, ..SMALL }) }, // Text on the display, lines from the keyboard (it takes input focus). // Its clients wait on lines and Ctrl+C. It draws its own text now, // beside a screenful of grid. Program { uses: &["display"], restarts_clients: true, stack_pages: 8, ..server("terminal", b"bin/terminal", SMALL) }, server("session", b"bin/session", SMALL), ]; /// Started for each sign-in, before anything that touches a user's files. /// It holds the screen (through the terminal), its keystore and randomness, /// and exits once it has handed over who is in and their key. pub const GATEKEEPER: Program = Program { uses: &["terminal"], devices: &[Device::Keystore, Device::Random], // A user's record is KiBs, and it handles a few at once. stack_pages: 12, // It exits once it has handed over; a new one runs at each sign-in. restart: false, // argon2's 16 MiB, its image and a little more. ..server("gatekeeper", b"bin/gatekeeper", Limits { pages: 4096 + 160, regions: 6, ..SMALL }) }; /// Started for each signed-in user, and stopped when they sign out. The /// permission manager is the only one that equips apps (docs/apps.md): it /// reaches the user's apps, their data and decisions, and the system's apps /// (read-only), and runs apps through init. pub const SESSION: &[Program] = &[Program { uses: &["terminal", "display"], storage: &[users(b"", true), disk(b"apps", false)], // Room for several apps at a time (24 MiB between them). spawns: Some(Limits { pages: 6144, endpoints: 12, notifications: 12, regions: 12 }), // The shell holds handles to the apps it ran, which die with it. restarts_clients: true, session: Session::PassOn, // Installing waits for the user's consent. pinged: false, ..server("permission", b"bin/permission", Limits { pages: 96, ..SMALL }) }]; /// Run on the test image after the SMP self-test, instead of the desktop: /// spawns through init, then reports and halts. `flaky` dies when asked, /// for spawntest to see it restarted. pub const TESTS: &[Program] = &[server("flaky", b"bin/flaky", SMALL), Program { serves: false, // The permission manager, to run an app the way the shell does. uses: &["permission", "flaky"], storage: &[disk(b"", true), users(b"home", true)], spawns: Some(Limits { pages: 128, endpoints: 2, notifications: 2, regions: 2 }), system_control: true, restart: false, ..server("spawntest", b"bin/spawntest", SMALL) }]; /// The desktop; the test image runs the SMP self-test instead. The shell /// holds the user's files and asks the permission manager to run apps; /// it holds nothing to give them beyond that, and may sign the user out. pub const DESKTOP: &[Program] = &[Program { serves: false, uses: &["terminal", "permission"], storage: &[users(b"home", true)], session: Session::Own, takes_ctrl_c: true, ..server("shell", b"bin/shell", SMALL) }];