feat(userspace): shell runs programs (ls, cat) via spawn w/ terminal+storage+args page; ext4 holes read as zeros; storage re-attach same buffer
This commit is contained in:
@@ -1,11 +1,27 @@
|
||||
//! The word a process's first thread gets in `a0`: the slots of the
|
||||
//! capabilities any process may be handed at start (console, log endpoint).
|
||||
//! Each field is slot + 1 in one byte; 0 means none.
|
||||
//! capabilities any process may be handed at start, and whether it has an
|
||||
//! arguments page. Each slot field is slot + 1 in one byte; 0 means none.
|
||||
|
||||
use crate::bounded::CapSlot;
|
||||
|
||||
const CONSOLE_SHIFT: u32 = 0;
|
||||
const LOG_SHIFT: u32 = 8;
|
||||
const STORAGE_SHIFT: u32 = 16;
|
||||
const ARGS_BIT: usize = 1 << 24;
|
||||
|
||||
/// Where the arguments page sits: the program's arguments, NUL separated,
|
||||
/// the first its name. Below the stack, which ends at the image.
|
||||
pub const ARGS_VA: usize = 0x8000;
|
||||
pub const ARGS_SIZE: usize = 4096;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub struct StartArg {
|
||||
pub console: Option<CapSlot>,
|
||||
/// Where `println!` goes: the log server, or a terminal.
|
||||
pub log: Option<CapSlot>,
|
||||
pub storage: Option<CapSlot>,
|
||||
pub args: bool,
|
||||
}
|
||||
|
||||
fn field(arg: usize, shift: u32) -> Option<CapSlot> {
|
||||
let v = (arg >> shift) & 0xFF;
|
||||
@@ -16,16 +32,22 @@ fn put(slot: Option<CapSlot>, shift: u32) -> usize {
|
||||
slot.map_or(0, |s| (s.value() as usize + 1) << shift)
|
||||
}
|
||||
|
||||
pub fn encode(console: Option<CapSlot>, log: Option<CapSlot>) -> usize {
|
||||
put(console, CONSOLE_SHIFT) | put(log, LOG_SHIFT)
|
||||
}
|
||||
impl StartArg {
|
||||
pub fn encode(&self) -> usize {
|
||||
put(self.console, CONSOLE_SHIFT)
|
||||
| put(self.log, LOG_SHIFT)
|
||||
| put(self.storage, STORAGE_SHIFT)
|
||||
| if self.args { ARGS_BIT } else { 0 }
|
||||
}
|
||||
|
||||
pub fn console(arg: usize) -> Option<CapSlot> {
|
||||
field(arg, CONSOLE_SHIFT)
|
||||
}
|
||||
|
||||
pub fn log(arg: usize) -> Option<CapSlot> {
|
||||
field(arg, LOG_SHIFT)
|
||||
pub fn decode(arg: usize) -> Self {
|
||||
Self {
|
||||
console: field(arg, CONSOLE_SHIFT),
|
||||
log: field(arg, LOG_SHIFT),
|
||||
storage: field(arg, STORAGE_SHIFT),
|
||||
args: arg & ARGS_BIT != 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -33,11 +55,14 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn slots_round_trip_and_zero_is_none() {
|
||||
let (c, l) = (CapSlot::new(0), CapSlot::new(63));
|
||||
let arg = encode(c, l);
|
||||
assert_eq!((console(arg), log(arg)), (c, l));
|
||||
assert_eq!((console(0), log(0)), (None, None));
|
||||
assert_eq!(log(encode(c, None)), None);
|
||||
fn every_field_round_trips_and_zero_is_none() {
|
||||
let a = StartArg {
|
||||
console: CapSlot::new(0),
|
||||
log: CapSlot::new(63),
|
||||
storage: CapSlot::new(5),
|
||||
args: true,
|
||||
};
|
||||
assert_eq!(StartArg::decode(a.encode()), a);
|
||||
assert_eq!(StartArg::decode(0), StartArg::default());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user