mirror of
https://github.com/AmbiML/sparrow-kata-full.git
synced 2025-08-17 12:46:59 +00:00
Merge "kata-shell; overhaul command processing"
GitOrigin-RevId: 6fe5b9078cd47083ae834e81482576272f7b9b7e
This commit is contained in:
parent
6d8badf052
commit
6850f3b3e0
@ -11,13 +11,28 @@ build = "build.rs"
|
|||||||
sel4-config = { path = "../../kata-os-common/src/sel4-config" }
|
sel4-config = { path = "../../kata-os-common/src/sel4-config" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = [
|
||||||
|
"TEST_GLOBAL_ALLOCATOR",
|
||||||
|
"TEST_MEMORY_MANAGER",
|
||||||
|
"TEST_ML_COORDINATOR",
|
||||||
|
"TEST_PANIC",
|
||||||
|
"TEST_TIMER_SERVICE",
|
||||||
|
]
|
||||||
CONFIG_DEBUG_BUILD = []
|
CONFIG_DEBUG_BUILD = []
|
||||||
CONFIG_KERNEL_MCS = []
|
CONFIG_KERNEL_MCS = []
|
||||||
|
# Commands that are likely not useful
|
||||||
|
FRINGE_CMDS = []
|
||||||
|
# Runtime tests for various services (please keep sorted)
|
||||||
|
TEST_GLOBAL_ALLOCATOR = []
|
||||||
|
TEST_MEMORY_MANAGER = []
|
||||||
|
TEST_ML_COORDINATOR = []
|
||||||
|
TEST_PANIC = []
|
||||||
|
TEST_TIMER_SERVICE = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crc = { version = "1.4.0", default_features = false }
|
crc = { version = "1.4.0", default_features = false }
|
||||||
cpio = { git = "https://github.com/rcore-os/cpio" }
|
cpio = { git = "https://github.com/rcore-os/cpio" }
|
||||||
|
hashbrown = { version = "0.11", features = ["ahash-compile-time-rng"] }
|
||||||
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }
|
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }
|
||||||
kata-io = { path = "../kata-io" }
|
kata-io = { path = "../kata-io" }
|
||||||
kata-line-reader = { path = "../kata-line-reader" }
|
kata-line-reader = { path = "../kata-line-reader" }
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
// Infrequently used shell commands
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::fmt::Write;
|
||||||
|
use crate::CmdFn;
|
||||||
|
use crate::CommandError;
|
||||||
|
use crate::rz;
|
||||||
|
|
||||||
|
use kata_io as io;
|
||||||
|
use kata_security_interface::kata_security_echo;
|
||||||
|
|
||||||
|
pub fn add_cmds(cmds: &mut HashMap::<&str, CmdFn>) {
|
||||||
|
cmds.extend([
|
||||||
|
("add", add_command as CmdFn),
|
||||||
|
("echo", echo_command as CmdFn),
|
||||||
|
("clear", clear_command as CmdFn),
|
||||||
|
("rz", rz_command as CmdFn),
|
||||||
|
("scecho", scecho_command as CmdFn),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements a binary float addition command.
|
||||||
|
///
|
||||||
|
/// This is a toy to demonstrate that the CLI can operate on some very basic
|
||||||
|
/// dynamic input and that the Rust runtime provides floating point arithmetic
|
||||||
|
/// on integer-only hardware. It is also a prototype example of "command taking
|
||||||
|
/// arguments." It should be removed once actually useful system control
|
||||||
|
/// commands are implemented and done cribbing from it.
|
||||||
|
fn add_command(
|
||||||
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let x_str = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
let x = x_str.parse::<f32>()?;
|
||||||
|
let y_str = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
let y = y_str.parse::<f32>()?;
|
||||||
|
return Ok(writeln!(output, "{}", x + y)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements a command that outputs the ANSI "clear console" sequence.
|
||||||
|
fn clear_command(
|
||||||
|
_args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
Ok(output.write_str("\x1b\x63")?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements an "echo" command which writes its arguments to output.
|
||||||
|
fn echo_command(
|
||||||
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let value = args.collect::<Vec<&str>>().join(" ");
|
||||||
|
Ok(writeln!(output, "{}", &value)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements an "scecho" command that sends arguments to the Security Core's echo service.
|
||||||
|
fn scecho_command(
|
||||||
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let request = args.collect::<Vec<&str>>().join(" ");
|
||||||
|
match kata_security_echo(&request) {
|
||||||
|
Ok(result) => writeln!(output, "{}", result)?,
|
||||||
|
Err(status) => writeln!(output, "ECHO replied {:?}", status)?,
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements a command to receive a blob using ZMODEM.
|
||||||
|
fn rz_command(
|
||||||
|
_args: &mut dyn Iterator<Item = &str>,
|
||||||
|
input: &mut dyn io::BufRead,
|
||||||
|
mut output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let upload = rz::rz(input, &mut output)?;
|
||||||
|
writeln!(
|
||||||
|
output,
|
||||||
|
"size: {}, crc32: {}",
|
||||||
|
upload.len(),
|
||||||
|
hex::encode(upload.crc32().to_be_bytes())
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
use alloc::vec;
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
use cpio::CpioNewcReader;
|
use cpio::CpioNewcReader;
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
use kata_io as io;
|
use kata_io as io;
|
||||||
use kata_line_reader::LineReader;
|
use kata_line_reader::LineReader;
|
||||||
@ -18,31 +18,37 @@ use kata_proc_interface::kata_pkg_mgmt_uninstall;
|
|||||||
use kata_proc_interface::kata_proc_ctrl_get_running_bundles;
|
use kata_proc_interface::kata_proc_ctrl_get_running_bundles;
|
||||||
use kata_proc_interface::kata_proc_ctrl_start;
|
use kata_proc_interface::kata_proc_ctrl_start;
|
||||||
use kata_proc_interface::kata_proc_ctrl_stop;
|
use kata_proc_interface::kata_proc_ctrl_stop;
|
||||||
use kata_security_interface::kata_security_echo;
|
|
||||||
use kata_storage_interface::kata_storage_delete;
|
use kata_storage_interface::kata_storage_delete;
|
||||||
use kata_storage_interface::kata_storage_read;
|
use kata_storage_interface::kata_storage_read;
|
||||||
use kata_storage_interface::kata_storage_write;
|
use kata_storage_interface::kata_storage_write;
|
||||||
use kata_timer_interface::timer_service_completed_timers;
|
|
||||||
use kata_timer_interface::TimerServiceError;
|
|
||||||
use kata_timer_interface::timer_service_oneshot;
|
|
||||||
use kata_timer_interface::timer_service_wait;
|
|
||||||
|
|
||||||
use sel4_sys::seL4_CNode_Delete;
|
use sel4_sys::seL4_CNode_Delete;
|
||||||
use sel4_sys::seL4_CPtr;
|
use sel4_sys::seL4_CPtr;
|
||||||
use sel4_sys::seL4_MinSchedContextBits;
|
|
||||||
use sel4_sys::seL4_ObjectType::*;
|
|
||||||
use sel4_sys::seL4_WordBits;
|
use sel4_sys::seL4_WordBits;
|
||||||
|
|
||||||
use slot_allocator::KATA_CSPACE_SLOTS;
|
use slot_allocator::KATA_CSPACE_SLOTS;
|
||||||
|
|
||||||
mod rz;
|
mod rz;
|
||||||
|
|
||||||
|
#[cfg(feature = "FRINGE_CMDS")]
|
||||||
|
mod fringe_cmds;
|
||||||
|
#[cfg(feature = "TEST_GLOBAL_ALLOCATOR")]
|
||||||
|
mod test_global_allocator;
|
||||||
|
#[cfg(feature = "TEST_MEMORY_MANAGER")]
|
||||||
|
mod test_memory_manager;
|
||||||
|
#[cfg(feature = "TEST_ML_COORDINATOR")]
|
||||||
|
mod test_ml_coordinator;
|
||||||
|
#[cfg(feature = "TEST_PANIC")]
|
||||||
|
mod test_panic;
|
||||||
|
#[cfg(feature = "TEST_TIMER_SERVICE")]
|
||||||
|
mod test_timer_service;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
static SELF_CNODE: seL4_CPtr;
|
static SELF_CNODE: seL4_CPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error type indicating why a command line is not runnable.
|
/// Error type indicating why a command line is not runnable.
|
||||||
enum CommandError {
|
pub enum CommandError {
|
||||||
UnknownCommand,
|
UnknownCommand,
|
||||||
BadArgs,
|
BadArgs,
|
||||||
IO,
|
IO,
|
||||||
@ -92,95 +98,86 @@ impl From<io::Error> for CommandError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CmdFn = fn(
|
||||||
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
builtin_cpio: &[u8]
|
||||||
|
) -> Result<(), CommandError>;
|
||||||
|
|
||||||
/// Read-eval-print loop for the DebugConsole command line interface.
|
/// Read-eval-print loop for the DebugConsole command line interface.
|
||||||
pub fn repl<T: io::BufRead>(
|
pub fn repl<T: io::BufRead>(
|
||||||
output: &mut dyn io::Write,
|
output: &mut dyn io::Write,
|
||||||
input: &mut T,
|
input: &mut T,
|
||||||
builtin_cpio: &[u8],
|
builtin_cpio: &[u8],
|
||||||
) -> ! {
|
) -> ! {
|
||||||
|
let mut cmds = HashMap::<&str, CmdFn>::new();
|
||||||
|
cmds.extend([
|
||||||
|
("builtins", builtins_command as CmdFn),
|
||||||
|
("bundles", bundles_command as CmdFn),
|
||||||
|
("kvdelete", kvdelete_command as CmdFn),
|
||||||
|
("kvread", kvread_command as CmdFn),
|
||||||
|
("kvwrite", kvwrite_command as CmdFn),
|
||||||
|
("install", install_command as CmdFn),
|
||||||
|
("loglevel", loglevel_command as CmdFn),
|
||||||
|
("mstats", mstats_command as CmdFn),
|
||||||
|
("ps", ps_command as CmdFn),
|
||||||
|
("start", start_command as CmdFn),
|
||||||
|
("stop", stop_command as CmdFn),
|
||||||
|
("uninstall", uninstall_command as CmdFn),
|
||||||
|
|
||||||
|
("state_mlcoord", state_mlcoord_command as CmdFn),
|
||||||
|
]);
|
||||||
|
#[cfg(feature = "FRINGE_CMDS")]
|
||||||
|
fringe_cmds::add_cmds(&mut cmds);
|
||||||
|
#[cfg(feature = "TEST_GLOBAL_ALLOCATOR")]
|
||||||
|
test_global_allocator::add_cmds(&mut cmds);
|
||||||
|
#[cfg(feature = "TEST_MEMORY_MANAGER")]
|
||||||
|
test_memory_manager::add_cmds(&mut cmds);
|
||||||
|
#[cfg(feature = "TEST_ML_COORDINATOR")]
|
||||||
|
test_ml_coordinator::add_cmds(&mut cmds);
|
||||||
|
#[cfg(feature = "TEST_PANIC")]
|
||||||
|
test_panic::add_cmds(&mut cmds);
|
||||||
|
#[cfg(feature = "TEST_TIMER_SERVICE")]
|
||||||
|
test_timer_service::add_cmds(&mut cmds);
|
||||||
|
|
||||||
let mut line_reader = LineReader::new();
|
let mut line_reader = LineReader::new();
|
||||||
loop {
|
loop {
|
||||||
const PROMPT: &str = "KATA> ";
|
const PROMPT: &str = "KATA> ";
|
||||||
let _ = output.write_str(PROMPT);
|
let _ = output.write_str(PROMPT);
|
||||||
match line_reader.read_line(output, input) {
|
match line_reader.read_line(output, input) {
|
||||||
Ok(cmdline) => dispatch_command(cmdline, input, output, builtin_cpio),
|
Ok(cmdline) => {
|
||||||
Err(e) => {
|
|
||||||
let _ = writeln!(output, "\n{}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs a command line.
|
|
||||||
///
|
|
||||||
/// The line is split on whitespace. The first token is the command; the
|
|
||||||
/// remaining tokens are the arguments.
|
|
||||||
fn dispatch_command(
|
|
||||||
cmdline: &str,
|
|
||||||
input: &mut dyn io::BufRead,
|
|
||||||
output: &mut dyn io::Write,
|
|
||||||
builtin_cpio: &[u8],
|
|
||||||
) {
|
|
||||||
let mut args = cmdline.split_ascii_whitespace();
|
let mut args = cmdline.split_ascii_whitespace();
|
||||||
match args.next() {
|
match args.next() {
|
||||||
Some(command) => {
|
Some("?") | Some("help") => {
|
||||||
// Statically binds command names to implementations fns, which are
|
let mut keys: Vec<&str> = cmds.keys().copied().collect();
|
||||||
// defined below.
|
keys.sort();
|
||||||
//
|
for k in keys {
|
||||||
// Since even the binding is static, it is fine for each command
|
let _ = writeln!(output, "{}", k);
|
||||||
// implementation to use its own preferred signature.
|
}
|
||||||
let result = match command {
|
}
|
||||||
"add" => add_command(&mut args, output),
|
Some(cmd) => {
|
||||||
"builtins" => builtins_command(&mut args, builtin_cpio, output),
|
let result = cmds.get(cmd).map_or_else(
|
||||||
"echo" => echo_command(cmdline, output),
|
|| Err(CommandError::UnknownCommand),
|
||||||
"clear" => clear_command(output),
|
|func| func(&mut args, input, output, builtin_cpio));
|
||||||
"bundles" => bundles_command(output),
|
|
||||||
"kvdelete" => kvdelete_command(&mut args, output),
|
|
||||||
"kvread" => kvread_command(&mut args, output),
|
|
||||||
"kvwrite" => kvwrite_command(&mut args, output),
|
|
||||||
"install" => install_command(&mut args, builtin_cpio, input, output),
|
|
||||||
"loglevel" => loglevel_command(&mut args, output),
|
|
||||||
"malloc" => malloc_command(&mut args, output),
|
|
||||||
"mfree" => mfree_command(&mut args, output),
|
|
||||||
"mstats" => mstats_command(&mut args, output),
|
|
||||||
"rz" => rz_command(input, output),
|
|
||||||
"ps" => ps_command(output),
|
|
||||||
"scecho" => scecho_command(cmdline, output),
|
|
||||||
"start" => start_command(&mut args, output),
|
|
||||||
"stop" => stop_command(&mut args, output),
|
|
||||||
"uninstall" => uninstall_command(&mut args, output),
|
|
||||||
|
|
||||||
"test_alloc" => test_alloc_command(output),
|
|
||||||
"test_alloc_error" => test_alloc_error_command(output),
|
|
||||||
"test_bootinfo" => test_bootinfo_command(output),
|
|
||||||
"test_mlcancel" => test_mlcancel_command(&mut args, output),
|
|
||||||
"test_mlexecute" => test_mlexecute_command(&mut args, output),
|
|
||||||
"test_mlperiodic" => test_mlperiodic_command(&mut args, output),
|
|
||||||
"test_obj_alloc" => test_obj_alloc_command(output),
|
|
||||||
"test_panic" => test_panic_command(),
|
|
||||||
"test_timer_async" => test_timer_async_command(&mut args, output),
|
|
||||||
"test_timer_blocking" => test_timer_blocking_command(&mut args, output),
|
|
||||||
"test_timer_completed" => test_timer_completed_command(output),
|
|
||||||
|
|
||||||
"state_mlcoord" => state_mlcoord_command(),
|
|
||||||
|
|
||||||
_ => Err(CommandError::UnknownCommand),
|
|
||||||
};
|
|
||||||
if let Err(e) = result {
|
if let Err(e) = result {
|
||||||
let _ = writeln!(output, "{}", e);
|
let _ = writeln!(output, "{}", e);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
None => {
|
None => { let _ = output.write_str("\n"); },
|
||||||
let _ = output.write_str("\n");
|
}
|
||||||
|
}
|
||||||
|
Err(e) => { let _ = writeln!(output, "\n{}", e); },
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements a "builtins" command that lists the contents of the built-in cpio archive.
|
/// Implements a "builtins" command that lists the contents of the built-in cpio archive.
|
||||||
fn builtins_command(
|
fn builtins_command(
|
||||||
_args: &mut dyn Iterator<Item = &str>,
|
_args: &mut dyn Iterator<Item = &str>,
|
||||||
builtin_cpio: &[u8],
|
_input: &mut dyn io::BufRead,
|
||||||
output: &mut dyn io::Write,
|
output: &mut dyn io::Write,
|
||||||
|
builtin_cpio: &[u8],
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
for e in CpioNewcReader::new(builtin_cpio) {
|
for e in CpioNewcReader::new(builtin_cpio) {
|
||||||
if e.is_err() {
|
if e.is_err() {
|
||||||
@ -193,34 +190,12 @@ fn builtins_command(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements an "echo" command which writes its arguments to output.
|
|
||||||
fn echo_command(cmdline: &str, output: &mut dyn io::Write) -> Result<(), CommandError> {
|
|
||||||
const COMMAND_LENGTH: usize = 5; // "echo "
|
|
||||||
if cmdline.len() < COMMAND_LENGTH {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Ok(writeln!(
|
|
||||||
output,
|
|
||||||
"{}",
|
|
||||||
&cmdline[COMMAND_LENGTH..cmdline.len()]
|
|
||||||
)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements an "scecho" command that sends arguments to the Security Core's echo service.
|
|
||||||
fn scecho_command(cmdline: &str, output: &mut dyn io::Write) -> Result<(), CommandError> {
|
|
||||||
let (_, request) = cmdline.split_at(7); // 'scecho'
|
|
||||||
match kata_security_echo(request) {
|
|
||||||
Ok(result) => writeln!(output, "{}", result)?,
|
|
||||||
Err(status) => writeln!(output, "ECHO replied {:?}", status)?,
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements a command to configure the max log level for the DebugConsole.
|
/// Implements a command to configure the max log level for the DebugConsole.
|
||||||
fn loglevel_command(
|
fn loglevel_command(
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
output: &mut dyn io::Write,
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
if let Some(level) = args.next() {
|
if let Some(level) = args.next() {
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
@ -237,59 +212,30 @@ fn loglevel_command(
|
|||||||
Ok(writeln!(output, "{}", log::max_level())?)
|
Ok(writeln!(output, "{}", log::max_level())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements a command to receive a blob using ZMODEM.
|
|
||||||
fn rz_command(
|
|
||||||
input: &mut dyn io::BufRead,
|
|
||||||
mut output: &mut dyn io::Write,
|
|
||||||
) -> Result<(), CommandError> {
|
|
||||||
let upload = rz::rz(input, &mut output)?;
|
|
||||||
writeln!(
|
|
||||||
output,
|
|
||||||
"size: {}, crc32: {}",
|
|
||||||
upload.len(),
|
|
||||||
hex::encode(upload.crc32().to_be_bytes())
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements a "ps" command that dumps seL4 scheduler state to the console.
|
/// Implements a "ps" command that dumps seL4 scheduler state to the console.
|
||||||
#[cfg(feature = "CONFIG_DEBUG_BUILD")]
|
#[allow(unused_variables)]
|
||||||
fn ps_command(_output: &mut dyn io::Write) -> Result<(), CommandError> {
|
fn ps_command(
|
||||||
|
_args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
#[cfg(feature = "CONFIG_DEBUG_BUILD")]
|
||||||
unsafe {
|
unsafe {
|
||||||
kata_os_common::sel4_sys::seL4_DebugDumpScheduler();
|
kata_os_common::sel4_sys::seL4_DebugDumpScheduler();
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "CONFIG_DEBUG_BUILD"))]
|
#[cfg(not(feature = "CONFIG_DEBUG_BUILD"))]
|
||||||
fn ps_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
|
|
||||||
Ok(writeln!(output, "Kernel support not configured!")?)
|
Ok(writeln!(output, "Kernel support not configured!")?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements a binary float addition command.
|
fn bundles_command(
|
||||||
///
|
_args: &mut dyn Iterator<Item = &str>,
|
||||||
/// This is a toy to demonstrate that the CLI can operate on some very basic
|
_input: &mut dyn io::BufRead,
|
||||||
/// dynamic input and that the Rust runtime provides floating point arithmetic
|
|
||||||
/// on integer-only hardware. It is also a prototype example of "command taking
|
|
||||||
/// arguments." It should be removed once actually useful system control
|
|
||||||
/// commands are implemented and done cribbing from it.
|
|
||||||
fn add_command(
|
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
|
||||||
output: &mut dyn io::Write,
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
let x_str = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
let x = x_str.parse::<f32>()?;
|
|
||||||
let y_str = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
let y = y_str.parse::<f32>()?;
|
|
||||||
return Ok(writeln!(output, "{}", x + y)?);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements a command that outputs the ANSI "clear console" sequence.
|
|
||||||
fn clear_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
|
|
||||||
Ok(output.write_str("\x1b\x63")?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bundles_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
|
|
||||||
match kata_proc_ctrl_get_running_bundles() {
|
match kata_proc_ctrl_get_running_bundles() {
|
||||||
Ok(bundle_ids) => {
|
Ok(bundle_ids) => {
|
||||||
writeln!(output, "{}", bundle_ids.join("\n"))?;
|
writeln!(output, "{}", bundle_ids.join("\n"))?;
|
||||||
@ -343,9 +289,9 @@ fn collect_from_zmodem(
|
|||||||
|
|
||||||
fn install_command(
|
fn install_command(
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
builtin_cpio: &[u8],
|
|
||||||
input: &mut dyn io::BufRead,
|
input: &mut dyn io::BufRead,
|
||||||
mut output: &mut dyn io::Write,
|
mut output: &mut dyn io::Write,
|
||||||
|
builtin_cpio: &[u8],
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
fn clear_slot(slot: seL4_CPtr) {
|
fn clear_slot(slot: seL4_CPtr) {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -399,7 +345,9 @@ fn install_command(
|
|||||||
|
|
||||||
fn uninstall_command(
|
fn uninstall_command(
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
output: &mut dyn io::Write,
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
let bundle_id = args.next().ok_or(CommandError::BadArgs)?;
|
let bundle_id = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
match kata_pkg_mgmt_uninstall(bundle_id) {
|
match kata_pkg_mgmt_uninstall(bundle_id) {
|
||||||
@ -415,7 +363,9 @@ fn uninstall_command(
|
|||||||
|
|
||||||
fn start_command(
|
fn start_command(
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
output: &mut dyn io::Write,
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
let bundle_id = args.next().ok_or(CommandError::BadArgs)?;
|
let bundle_id = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
match kata_proc_ctrl_start(bundle_id) {
|
match kata_proc_ctrl_start(bundle_id) {
|
||||||
@ -431,7 +381,9 @@ fn start_command(
|
|||||||
|
|
||||||
fn stop_command(
|
fn stop_command(
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
output: &mut dyn io::Write,
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
let bundle_id = args.next().ok_or(CommandError::BadArgs)?;
|
let bundle_id = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
match kata_proc_ctrl_stop(bundle_id) {
|
match kata_proc_ctrl_stop(bundle_id) {
|
||||||
@ -447,7 +399,9 @@ fn stop_command(
|
|||||||
|
|
||||||
fn kvdelete_command(
|
fn kvdelete_command(
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
output: &mut dyn io::Write,
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
let key = args.next().ok_or(CommandError::BadArgs)?;
|
let key = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
match kata_storage_delete(key) {
|
match kata_storage_delete(key) {
|
||||||
@ -463,7 +417,9 @@ fn kvdelete_command(
|
|||||||
|
|
||||||
fn kvread_command(
|
fn kvread_command(
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
output: &mut dyn io::Write,
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
let key = args.next().ok_or(CommandError::BadArgs)?;
|
let key = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
match kata_storage_read(key) {
|
match kata_storage_read(key) {
|
||||||
@ -479,7 +435,9 @@ fn kvread_command(
|
|||||||
|
|
||||||
fn kvwrite_command(
|
fn kvwrite_command(
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
output: &mut dyn io::Write,
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
let key = args.next().ok_or(CommandError::BadArgs)?;
|
let key = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
let value = args.collect::<Vec<&str>>().join(" ");
|
let value = args.collect::<Vec<&str>>().join(" ");
|
||||||
@ -494,52 +452,6 @@ fn kvwrite_command(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn malloc_command(
|
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
|
||||||
output: &mut dyn io::Write,
|
|
||||||
) -> Result<(), CommandError> {
|
|
||||||
let space_str = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
let space_bytes = space_str.parse::<usize>()?;
|
|
||||||
match kata_frame_alloc(space_bytes) {
|
|
||||||
Ok(frames) => {
|
|
||||||
writeln!(output, "Allocated {:?}", frames)?;
|
|
||||||
}
|
|
||||||
Err(status) => {
|
|
||||||
writeln!(output, "malloc failed: {:?}", status)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mfree_command(
|
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
|
||||||
output: &mut dyn io::Write,
|
|
||||||
) -> Result<(), CommandError> {
|
|
||||||
extern "C" { static SELF_CNODE: seL4_CPtr; }
|
|
||||||
let cptr_str = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
let count_str = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
let frames = ObjDescBundle::new(
|
|
||||||
unsafe { SELF_CNODE },
|
|
||||||
seL4_WordBits as u8,
|
|
||||||
vec![
|
|
||||||
ObjDesc::new(
|
|
||||||
sel4_sys::seL4_RISCV_4K_Page,
|
|
||||||
count_str.parse::<usize>()?,
|
|
||||||
cptr_str.parse::<usize>()? as seL4_CPtr,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
match kata_object_free_toplevel(&frames) {
|
|
||||||
Ok(_) => {
|
|
||||||
writeln!(output, "Free'd {:?}", frames)?;
|
|
||||||
}
|
|
||||||
Err(status) => {
|
|
||||||
writeln!(output, "mfree failed: {:?}", status)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mstats(output: &mut dyn io::Write, stats: &MemoryManagerStats)
|
fn mstats(output: &mut dyn io::Write, stats: &MemoryManagerStats)
|
||||||
-> Result<(), CommandError>
|
-> Result<(), CommandError>
|
||||||
{
|
{
|
||||||
@ -556,7 +468,9 @@ fn mstats(output: &mut dyn io::Write, stats: &MemoryManagerStats)
|
|||||||
|
|
||||||
fn mstats_command(
|
fn mstats_command(
|
||||||
_args: &mut dyn Iterator<Item = &str>,
|
_args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
output: &mut dyn io::Write,
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
match kata_memory_stats() {
|
match kata_memory_stats() {
|
||||||
Ok(stats) => { mstats(output, &stats)?; }
|
Ok(stats) => { mstats(output, &stats)?; }
|
||||||
@ -565,275 +479,11 @@ fn mstats_command(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements a command that tests facilities that use the global allocator.
|
fn state_mlcoord_command(
|
||||||
/// Shamelessly cribbed from https://os.phil-opp.com/heap-allocation/
|
_args: &mut dyn Iterator<Item = &str>,
|
||||||
fn test_alloc_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
|
_input: &mut dyn io::BufRead,
|
||||||
extern crate alloc;
|
_output: &mut dyn io::Write,
|
||||||
use alloc::{boxed::Box, rc::Rc};
|
_builtin_cpio: &[u8],
|
||||||
|
|
||||||
// allocate a number on the heap
|
|
||||||
let heap_value = Box::new(41);
|
|
||||||
writeln!(output, "heap_value at {:p}", heap_value).expect("Box failed");
|
|
||||||
|
|
||||||
// create a dynamically sized vector
|
|
||||||
let mut vec = Vec::new();
|
|
||||||
for i in 0..500 {
|
|
||||||
vec.push(i);
|
|
||||||
}
|
|
||||||
writeln!(output, "vec at {:p}", vec.as_slice()).expect("Vec failed");
|
|
||||||
|
|
||||||
// create a reference counted vector -> will be freed when count reaches 0
|
|
||||||
let reference_counted = Rc::new(vec![1, 2, 3]);
|
|
||||||
let cloned_reference = reference_counted.clone();
|
|
||||||
writeln!(
|
|
||||||
output,
|
|
||||||
"current reference count is {}",
|
|
||||||
Rc::strong_count(&cloned_reference)
|
|
||||||
)
|
|
||||||
.expect("Rc 1 failed");
|
|
||||||
core::mem::drop(reference_counted);
|
|
||||||
writeln!(
|
|
||||||
output,
|
|
||||||
"reference count is {} now",
|
|
||||||
Rc::strong_count(&cloned_reference)
|
|
||||||
)
|
|
||||||
.expect("Rc 2 failed");
|
|
||||||
|
|
||||||
Ok(writeln!(output, "All tests passed!")?)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements a command that tests the global allocator error handling.
|
|
||||||
fn test_alloc_error_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
|
|
||||||
// Default heap holds 16KB.
|
|
||||||
let mut vec = Vec::with_capacity(16384);
|
|
||||||
for i in 0..16348 {
|
|
||||||
vec.push(i);
|
|
||||||
}
|
|
||||||
Ok(writeln!(output, "vec at {:p}", vec.as_slice())?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_bootinfo_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
|
|
||||||
use kata_os_common::sel4_sys::seL4_BootInfo;
|
|
||||||
extern "C" {
|
|
||||||
fn sel4runtime_bootinfo() -> *const seL4_BootInfo;
|
|
||||||
}
|
|
||||||
let bootinfo_ref = unsafe { &*sel4runtime_bootinfo() };
|
|
||||||
writeln!(output, "{}:{} empty slots {}:{} untyped",
|
|
||||||
bootinfo_ref.empty.start, bootinfo_ref.empty.end,
|
|
||||||
bootinfo_ref.untyped.start, bootinfo_ref.untyped.end)?;
|
|
||||||
|
|
||||||
// NB: seL4_DebugCapIdentify is only available in debug builds
|
|
||||||
#[cfg(feature = "CONFIG_DEBUG_BUILD")]
|
|
||||||
for ut in bootinfo_ref.untyped.start..bootinfo_ref.untyped.end {
|
|
||||||
let cap_tag = unsafe { kata_os_common::sel4_sys::seL4_DebugCapIdentify(ut) };
|
|
||||||
assert_eq!(cap_tag, 2,
|
|
||||||
"expected untyped (2), got {} for cap at {}", cap_tag, ut);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements a command that tests panic handling.
|
|
||||||
fn test_panic_command() -> Result<(), CommandError> {
|
|
||||||
panic!("testing");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements a command that cancels an ML execution.
|
|
||||||
fn test_mlcancel_command(
|
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
|
||||||
output: &mut dyn io::Write,
|
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
let bundle_id = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
let model_id = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
|
|
||||||
if let Err(e) = kata_mlcoord_cancel(bundle_id, model_id) {
|
|
||||||
writeln!(output, "Cancel {:?} {:?} err: {:?}", bundle_id, model_id, e)?;
|
|
||||||
} else {
|
|
||||||
writeln!(output, "Cancelled {:?} {:?}", bundle_id, model_id)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements a command that runs a oneshot ML execution.
|
|
||||||
fn test_mlexecute_command(
|
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
|
||||||
output: &mut dyn io::Write,
|
|
||||||
) -> Result<(), CommandError> {
|
|
||||||
let bundle_id = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
let model_id = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
|
|
||||||
if let Err(e) = kata_mlcoord_oneshot(bundle_id, model_id) {
|
|
||||||
writeln!(output, "Execute {:?} {:?} err: {:?}", bundle_id, model_id, e)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements a command that runs a periodic ML execution.
|
|
||||||
fn test_mlperiodic_command(
|
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
|
||||||
output: &mut dyn io::Write,
|
|
||||||
) -> Result<(), CommandError> {
|
|
||||||
let bundle_id = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
let model_id = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
let rate_str = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
let rate_in_ms = rate_str.parse::<u32>()?;
|
|
||||||
|
|
||||||
if let Err(e) = kata_mlcoord_periodic(bundle_id, model_id, rate_in_ms) {
|
|
||||||
writeln!(output, "Periodic {:?} {:?} err: {:?}", bundle_id, model_id, e)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_obj_alloc_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
|
|
||||||
let before_stats = kata_memory_stats().expect("before stats");
|
|
||||||
mstats(output, &before_stats)?;
|
|
||||||
|
|
||||||
fn check_alloc(output: &mut dyn io::Write,
|
|
||||||
name: &str,
|
|
||||||
res: Result<ObjDescBundle, MemoryManagerError>) {
|
|
||||||
match res {
|
|
||||||
Ok(obj) => {
|
|
||||||
if let Err(e) = kata_object_free_toplevel(&obj) {
|
|
||||||
let _ = writeln!(output, "free {} {:?} failed: {:?}", name, obj, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
let _ = writeln!(output, "alloc {} failed: {:?}", name, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NB: alloc+free immediately so we don't run out of top-level CNode slots
|
|
||||||
check_alloc(output, "untyped", kata_untyped_alloc(12)); // NB: 4KB
|
|
||||||
check_alloc(output, "tcb", kata_tcb_alloc());
|
|
||||||
check_alloc(output, "endpoint", kata_endpoint_alloc());
|
|
||||||
check_alloc(output, "notification", kata_notification_alloc());
|
|
||||||
check_alloc(output, "cnode", kata_cnode_alloc(5)); // NB: 32 slots
|
|
||||||
check_alloc(output, "frame", kata_frame_alloc(4096));
|
|
||||||
// check_alloc(output, "large frame", kata_frame_alloc(1024*1024));
|
|
||||||
check_alloc(output, "page table", kata_page_table_alloc());
|
|
||||||
|
|
||||||
#[cfg(feature = "CONFIG_KERNEL_MCS")]
|
|
||||||
check_alloc(output, "sched context",
|
|
||||||
kata_sched_context_alloc(seL4_MinSchedContextBits));
|
|
||||||
|
|
||||||
#[cfg(feature = "CONFIG_KERNEL_MCS")]
|
|
||||||
check_alloc(output, "reply", kata_reply_alloc());
|
|
||||||
|
|
||||||
let after_stats = kata_memory_stats().expect("after stats");
|
|
||||||
mstats(output, &after_stats)?;
|
|
||||||
assert_eq!(before_stats.allocated_bytes, after_stats.allocated_bytes);
|
|
||||||
assert_eq!(before_stats.free_bytes, after_stats.free_bytes);
|
|
||||||
|
|
||||||
// Batch allocate into a private CNode as we might to build a process.
|
|
||||||
const CNODE_DEPTH: usize = 7; // 128 slots
|
|
||||||
let cnode = kata_cnode_alloc(CNODE_DEPTH).unwrap(); // XXX handle error
|
|
||||||
let objs = ObjDescBundle::new(
|
|
||||||
cnode.objs[0].cptr,
|
|
||||||
CNODE_DEPTH as u8,
|
|
||||||
vec![
|
|
||||||
ObjDesc::new(seL4_TCBObject, 1, 0), // 1 tcb
|
|
||||||
ObjDesc::new(seL4_EndpointObject, 2, 1), // 2 endpoiints
|
|
||||||
ObjDesc::new(seL4_ReplyObject, 2, 3), // 2 replys
|
|
||||||
ObjDesc::new(seL4_SchedContextObject, // 1 sched context
|
|
||||||
seL4_MinSchedContextBits, 5),
|
|
||||||
ObjDesc::new(seL4_RISCV_4K_Page, 10, 6), // 10 4K pages
|
|
||||||
],
|
|
||||||
);
|
|
||||||
match kata_object_alloc(&objs) {
|
|
||||||
Ok(_) => {
|
|
||||||
writeln!(output, "Batch alloc ok: {:?}", objs)?;
|
|
||||||
if let Err(e) = kata_object_free(&objs) {
|
|
||||||
writeln!(output, "Batch free err: {:?}", e)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
writeln!(output, "Batch alloc err: {:?} {:?}", objs, e)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Err(e) = kata_object_free_toplevel(&cnode) {
|
|
||||||
writeln!(output, "Cnode free err: {:?} {:?}", cnode, e)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Batch allocate using the newer api that constructs a CNode based
|
|
||||||
// on the batch of objects specified.
|
|
||||||
match kata_object_alloc_in_cnode(
|
|
||||||
vec![
|
|
||||||
ObjDesc::new(seL4_TCBObject, 1, 0), // 1 tcb
|
|
||||||
ObjDesc::new(seL4_EndpointObject, 1, 1), // 1 endpoiints
|
|
||||||
ObjDesc::new(seL4_ReplyObject, 1, 2), // 1 replys
|
|
||||||
ObjDesc::new(seL4_SchedContextObject, // 1 sched context
|
|
||||||
seL4_MinSchedContextBits, 3),
|
|
||||||
ObjDesc::new(seL4_RISCV_4K_Page, 2, 4), // 2 4K pages
|
|
||||||
],
|
|
||||||
) {
|
|
||||||
Ok(objs) => {
|
|
||||||
writeln!(output, "kata_object_alloc_in_cnode ok: {:?}", objs)?;
|
|
||||||
if let Err(e) = kata_object_free_in_cnode(&objs) {
|
|
||||||
writeln!(output, "kata_object_free_in_cnode failed: {:?}", e)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
writeln!(output, "kata_object_alloc_in_cnode failed: {:?}", e)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(writeln!(output, "All tests passed!")?)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements a command that starts a timer, but does not wait on the
|
|
||||||
/// notification.
|
|
||||||
fn test_timer_async_command(
|
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
|
||||||
output: &mut dyn io::Write,
|
|
||||||
) -> Result<(), CommandError> {
|
|
||||||
let id_str = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
let id = id_str.parse::<u32>()?;
|
|
||||||
let time_str = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
let time_ms = time_str.parse::<u32>()?;
|
|
||||||
|
|
||||||
writeln!(output, "Starting timer {} for {} ms.", id, time_ms)?;
|
|
||||||
|
|
||||||
match timer_service_oneshot(id, time_ms) {
|
|
||||||
TimerServiceError::TimerOk => (),
|
|
||||||
_ => return Err(CommandError::BadArgs),
|
|
||||||
}
|
|
||||||
|
|
||||||
timer_service_oneshot(id, time_ms);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements a command that starts a timer, blocking until the timer has
|
|
||||||
/// completed.
|
|
||||||
fn test_timer_blocking_command(
|
|
||||||
args: &mut dyn Iterator<Item = &str>,
|
|
||||||
output: &mut dyn io::Write,
|
|
||||||
) -> Result<(), CommandError> {
|
|
||||||
let time_str = args.next().ok_or(CommandError::BadArgs)?;
|
|
||||||
let time_ms = time_str.parse::<u32>()?;
|
|
||||||
|
|
||||||
writeln!(output, "Blocking {} ms waiting for timer.", time_ms)?;
|
|
||||||
|
|
||||||
// Set timer_id to 0, we don't need to use multiple timers here.
|
|
||||||
match timer_service_oneshot(0, time_ms) {
|
|
||||||
TimerServiceError::TimerOk => (),
|
|
||||||
_ => return Err(CommandError::BadArgs),
|
|
||||||
}
|
|
||||||
|
|
||||||
timer_service_wait();
|
|
||||||
|
|
||||||
return Ok(writeln!(output, "Timer completed.")?);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements a command that checks the completed timers.
|
|
||||||
fn test_timer_completed_command(
|
|
||||||
output: &mut dyn io::Write,
|
|
||||||
) -> Result<(), CommandError> {
|
|
||||||
return Ok(writeln!(output, "Timers completed: {:#032b}", timer_service_completed_timers())?);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn state_mlcoord_command() -> Result<(), CommandError> {
|
|
||||||
return Ok(kata_mlcoord_debug_state());
|
return Ok(kata_mlcoord_debug_state());
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
// Global allocator shell test commands
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::fmt::Write;
|
||||||
|
use crate::CmdFn;
|
||||||
|
use crate::CommandError;
|
||||||
|
use crate::HashMap;
|
||||||
|
|
||||||
|
use kata_io as io;
|
||||||
|
|
||||||
|
pub fn add_cmds(cmds: &mut HashMap::<&str, CmdFn>) {
|
||||||
|
cmds.extend([
|
||||||
|
("test_alloc", alloc_command as CmdFn),
|
||||||
|
("test_alloc_error", alloc_error_command as CmdFn),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements a command that tests facilities that use the global allocator.
|
||||||
|
/// Shamelessly cribbed from https://os.phil-opp.com/heap-allocation/
|
||||||
|
fn alloc_command(
|
||||||
|
_args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
extern crate alloc;
|
||||||
|
use alloc::{boxed::Box, rc::Rc};
|
||||||
|
|
||||||
|
// allocate a number on the heap
|
||||||
|
let heap_value = Box::new(41);
|
||||||
|
writeln!(output, "heap_value at {:p}", heap_value).expect("Box failed");
|
||||||
|
|
||||||
|
// create a dynamically sized vector
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for i in 0..500 {
|
||||||
|
vec.push(i);
|
||||||
|
}
|
||||||
|
writeln!(output, "vec at {:p}", vec.as_slice()).expect("Vec failed");
|
||||||
|
|
||||||
|
// create a reference counted vector -> will be freed when count reaches 0
|
||||||
|
let reference_counted = Rc::new(vec![1, 2, 3]);
|
||||||
|
let cloned_reference = reference_counted.clone();
|
||||||
|
writeln!(
|
||||||
|
output,
|
||||||
|
"current reference count is {}",
|
||||||
|
Rc::strong_count(&cloned_reference)
|
||||||
|
)
|
||||||
|
.expect("Rc 1 failed");
|
||||||
|
core::mem::drop(reference_counted);
|
||||||
|
writeln!(
|
||||||
|
output,
|
||||||
|
"reference count is {} now",
|
||||||
|
Rc::strong_count(&cloned_reference)
|
||||||
|
)
|
||||||
|
.expect("Rc 2 failed");
|
||||||
|
|
||||||
|
Ok(writeln!(output, "All tests passed!")?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements a command that tests the global allocator error handling.
|
||||||
|
fn alloc_error_command(
|
||||||
|
_args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
// Default heap holds 16KB.
|
||||||
|
let mut vec = Vec::with_capacity(16384);
|
||||||
|
for i in 0..16384 {
|
||||||
|
vec.push(i);
|
||||||
|
}
|
||||||
|
Ok(writeln!(output, "vec at {:p}", vec.as_slice())?)
|
||||||
|
}
|
@ -0,0 +1,204 @@
|
|||||||
|
// MemoryManager service shell test commands
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
use alloc::vec;
|
||||||
|
use core::fmt::Write;
|
||||||
|
use crate::CmdFn;
|
||||||
|
use crate::CommandError;
|
||||||
|
use crate::HashMap;
|
||||||
|
use crate::mstats;
|
||||||
|
|
||||||
|
use kata_io as io;
|
||||||
|
use kata_memory_interface::*;
|
||||||
|
use kata_os_common::sel4_sys;
|
||||||
|
|
||||||
|
use sel4_sys::seL4_CPtr;
|
||||||
|
use sel4_sys::seL4_MinSchedContextBits;
|
||||||
|
use sel4_sys::seL4_ObjectType::*;
|
||||||
|
use sel4_sys::seL4_WordBits;
|
||||||
|
|
||||||
|
pub fn add_cmds(cmds: &mut HashMap::<&str, CmdFn>) {
|
||||||
|
cmds.extend([
|
||||||
|
("test_bootinfo", bootinfo_command as CmdFn),
|
||||||
|
("test_malloc", malloc_command as CmdFn),
|
||||||
|
("test_mfree", mfree_command as CmdFn),
|
||||||
|
("test_obj_alloc", obj_alloc_command as CmdFn),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bootinfo_command(
|
||||||
|
_args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
use kata_os_common::sel4_sys::seL4_BootInfo;
|
||||||
|
extern "C" {
|
||||||
|
fn sel4runtime_bootinfo() -> *const seL4_BootInfo;
|
||||||
|
}
|
||||||
|
let bootinfo_ref = unsafe { &*sel4runtime_bootinfo() };
|
||||||
|
writeln!(output, "{}:{} empty slots {}:{} untyped",
|
||||||
|
bootinfo_ref.empty.start, bootinfo_ref.empty.end,
|
||||||
|
bootinfo_ref.untyped.start, bootinfo_ref.untyped.end)?;
|
||||||
|
|
||||||
|
// NB: seL4_DebugCapIdentify is only available in debug builds
|
||||||
|
#[cfg(feature = "CONFIG_DEBUG_BUILD")]
|
||||||
|
for ut in bootinfo_ref.untyped.start..bootinfo_ref.untyped.end {
|
||||||
|
let cap_tag = unsafe { kata_os_common::sel4_sys::seL4_DebugCapIdentify(ut) };
|
||||||
|
assert_eq!(cap_tag, 2,
|
||||||
|
"expected untyped (2), got {} for cap at {}", cap_tag, ut);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn malloc_command(
|
||||||
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let space_str = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
let space_bytes = space_str.parse::<usize>()?;
|
||||||
|
match kata_frame_alloc(space_bytes) {
|
||||||
|
Ok(frames) => {
|
||||||
|
writeln!(output, "Allocated {:?}", frames)?;
|
||||||
|
}
|
||||||
|
Err(status) => {
|
||||||
|
writeln!(output, "malloc failed: {:?}", status)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mfree_command(
|
||||||
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
extern "C" { static SELF_CNODE: seL4_CPtr; }
|
||||||
|
let cptr_str = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
let count_str = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
let frames = ObjDescBundle::new(
|
||||||
|
unsafe { SELF_CNODE },
|
||||||
|
seL4_WordBits as u8,
|
||||||
|
vec![
|
||||||
|
ObjDesc::new(
|
||||||
|
sel4_sys::seL4_RISCV_4K_Page,
|
||||||
|
count_str.parse::<usize>()?,
|
||||||
|
cptr_str.parse::<usize>()? as seL4_CPtr,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
match kata_object_free_toplevel(&frames) {
|
||||||
|
Ok(_) => {
|
||||||
|
writeln!(output, "Free'd {:?}", frames)?;
|
||||||
|
}
|
||||||
|
Err(status) => {
|
||||||
|
writeln!(output, "mfree failed: {:?}", status)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn obj_alloc_command(
|
||||||
|
_args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let before_stats = kata_memory_stats().expect("before stats");
|
||||||
|
mstats(output, &before_stats)?;
|
||||||
|
|
||||||
|
fn check_alloc(output: &mut dyn io::Write,
|
||||||
|
name: &str,
|
||||||
|
res: Result<ObjDescBundle, MemoryManagerError>) {
|
||||||
|
match res {
|
||||||
|
Ok(obj) => {
|
||||||
|
if let Err(e) = kata_object_free_toplevel(&obj) {
|
||||||
|
let _ = writeln!(output, "free {} {:?} failed: {:?}", name, obj, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
let _ = writeln!(output, "alloc {} failed: {:?}", name, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NB: alloc+free immediately so we don't run out of top-level CNode slots
|
||||||
|
check_alloc(output, "untyped", kata_untyped_alloc(12)); // NB: 4KB
|
||||||
|
check_alloc(output, "tcb", kata_tcb_alloc());
|
||||||
|
check_alloc(output, "endpoint", kata_endpoint_alloc());
|
||||||
|
check_alloc(output, "notification", kata_notification_alloc());
|
||||||
|
check_alloc(output, "cnode", kata_cnode_alloc(5)); // NB: 32 slots
|
||||||
|
check_alloc(output, "frame", kata_frame_alloc(4096));
|
||||||
|
// check_alloc(output, "large frame", kata_frame_alloc(1024*1024));
|
||||||
|
check_alloc(output, "page table", kata_page_table_alloc());
|
||||||
|
|
||||||
|
#[cfg(feature = "CONFIG_KERNEL_MCS")]
|
||||||
|
check_alloc(output, "sched context",
|
||||||
|
kata_sched_context_alloc(seL4_MinSchedContextBits));
|
||||||
|
|
||||||
|
#[cfg(feature = "CONFIG_KERNEL_MCS")]
|
||||||
|
check_alloc(output, "reply", kata_reply_alloc());
|
||||||
|
|
||||||
|
let after_stats = kata_memory_stats().expect("after stats");
|
||||||
|
mstats(output, &after_stats)?;
|
||||||
|
assert_eq!(before_stats.allocated_bytes, after_stats.allocated_bytes);
|
||||||
|
assert_eq!(before_stats.free_bytes, after_stats.free_bytes);
|
||||||
|
|
||||||
|
// Batch allocate into a private CNode as we might to build a process.
|
||||||
|
const CNODE_DEPTH: usize = 7; // 128 slots
|
||||||
|
let cnode = kata_cnode_alloc(CNODE_DEPTH).unwrap(); // XXX handle error
|
||||||
|
let objs = ObjDescBundle::new(
|
||||||
|
cnode.objs[0].cptr,
|
||||||
|
CNODE_DEPTH as u8,
|
||||||
|
vec![
|
||||||
|
ObjDesc::new(seL4_TCBObject, 1, 0), // 1 tcb
|
||||||
|
ObjDesc::new(seL4_EndpointObject, 2, 1), // 2 endpoiints
|
||||||
|
ObjDesc::new(seL4_ReplyObject, 2, 3), // 2 replys
|
||||||
|
ObjDesc::new(seL4_SchedContextObject, // 1 sched context
|
||||||
|
seL4_MinSchedContextBits, 5),
|
||||||
|
ObjDesc::new(seL4_RISCV_4K_Page, 10, 6), // 10 4K pages
|
||||||
|
],
|
||||||
|
);
|
||||||
|
match kata_object_alloc(&objs) {
|
||||||
|
Ok(_) => {
|
||||||
|
writeln!(output, "Batch alloc ok: {:?}", objs)?;
|
||||||
|
if let Err(e) = kata_object_free(&objs) {
|
||||||
|
writeln!(output, "Batch free err: {:?}", e)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
writeln!(output, "Batch alloc err: {:?} {:?}", objs, e)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Err(e) = kata_object_free_toplevel(&cnode) {
|
||||||
|
writeln!(output, "Cnode free err: {:?} {:?}", cnode, e)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Batch allocate using the newer api that constructs a CNode based
|
||||||
|
// on the batch of objects specified.
|
||||||
|
match kata_object_alloc_in_cnode(
|
||||||
|
vec![
|
||||||
|
ObjDesc::new(seL4_TCBObject, 1, 0), // 1 tcb
|
||||||
|
ObjDesc::new(seL4_EndpointObject, 1, 1), // 1 endpoiints
|
||||||
|
ObjDesc::new(seL4_ReplyObject, 1, 2), // 1 replys
|
||||||
|
ObjDesc::new(seL4_SchedContextObject, // 1 sched context
|
||||||
|
seL4_MinSchedContextBits, 3),
|
||||||
|
ObjDesc::new(seL4_RISCV_4K_Page, 2, 4), // 2 4K pages
|
||||||
|
],
|
||||||
|
) {
|
||||||
|
Ok(objs) => {
|
||||||
|
writeln!(output, "kata_object_alloc_in_cnode ok: {:?}", objs)?;
|
||||||
|
if let Err(e) = kata_object_free_in_cnode(&objs) {
|
||||||
|
writeln!(output, "kata_object_free_in_cnode failed: {:?}", e)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
writeln!(output, "kata_object_alloc_in_cnode failed: {:?}", e)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(writeln!(output, "All tests passed!")?)
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
// MlCoordinator service shell test commands
|
||||||
|
|
||||||
|
use core::fmt::Write;
|
||||||
|
use crate::CmdFn;
|
||||||
|
use crate::CommandError;
|
||||||
|
use crate::HashMap;
|
||||||
|
|
||||||
|
use kata_io as io;
|
||||||
|
use kata_ml_interface::*;
|
||||||
|
|
||||||
|
pub fn add_cmds(cmds: &mut HashMap::<&str, CmdFn>) {
|
||||||
|
cmds.extend([
|
||||||
|
("test_mlcancel", mlcancel_command as CmdFn),
|
||||||
|
("test_mlexecute", mlexecute_command as CmdFn),
|
||||||
|
("test_mlperiodic", mlperiodic_command as CmdFn),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements a command that cancels an ML execution.
|
||||||
|
fn mlcancel_command(
|
||||||
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let bundle_id = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
let model_id = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
|
||||||
|
if let Err(e) = kata_mlcoord_cancel(bundle_id, model_id) {
|
||||||
|
writeln!(output, "Cancel {:?} {:?} err: {:?}", bundle_id, model_id, e)?;
|
||||||
|
} else {
|
||||||
|
writeln!(output, "Cancelled {:?} {:?}", bundle_id, model_id)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements a command that runs a oneshot ML execution.
|
||||||
|
fn mlexecute_command(
|
||||||
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let bundle_id = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
let model_id = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
|
||||||
|
if let Err(e) = kata_mlcoord_oneshot(bundle_id, model_id) {
|
||||||
|
writeln!(output, "Execute {:?} {:?} err: {:?}", bundle_id, model_id, e)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements a command that runs a periodic ML execution.
|
||||||
|
fn mlperiodic_command(
|
||||||
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let bundle_id = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
let model_id = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
let rate_str = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
let rate_in_ms = rate_str.parse::<u32>()?;
|
||||||
|
|
||||||
|
if let Err(e) = kata_mlcoord_periodic(bundle_id, model_id, rate_in_ms) {
|
||||||
|
writeln!(output, "Periodic {:?} {:?} err: {:?}", bundle_id, model_id, e)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
// Panic-related shell test commands
|
||||||
|
|
||||||
|
use crate::CmdFn;
|
||||||
|
use crate::CommandError;
|
||||||
|
use crate::HashMap;
|
||||||
|
|
||||||
|
use kata_io as io;
|
||||||
|
|
||||||
|
pub fn add_cmds(cmds: &mut HashMap::<&str, CmdFn>) {
|
||||||
|
cmds.extend([
|
||||||
|
("test_panic", panic_command as CmdFn),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements a command that tests panic handling.
|
||||||
|
fn panic_command(
|
||||||
|
_args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
_output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
panic!("testing");
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
// TimerService shell test commands
|
||||||
|
|
||||||
|
use core::fmt::Write;
|
||||||
|
use crate::CmdFn;
|
||||||
|
use crate::CommandError;
|
||||||
|
use crate::HashMap;
|
||||||
|
|
||||||
|
use kata_io as io;
|
||||||
|
|
||||||
|
use kata_timer_interface::timer_service_completed_timers;
|
||||||
|
use kata_timer_interface::TimerServiceError;
|
||||||
|
use kata_timer_interface::timer_service_oneshot;
|
||||||
|
use kata_timer_interface::timer_service_wait;
|
||||||
|
|
||||||
|
pub fn add_cmds(cmds: &mut HashMap::<&str, CmdFn>) {
|
||||||
|
cmds.extend([
|
||||||
|
("test_timer_async", timer_async_command as CmdFn),
|
||||||
|
("test_timer_blocking", timer_blocking_command as CmdFn),
|
||||||
|
("test_timer_completed",timer_completed_command as CmdFn),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements a command that starts a timer, but does not wait on the
|
||||||
|
/// notification.
|
||||||
|
fn timer_async_command(
|
||||||
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let id_str = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
let id = id_str.parse::<u32>()?;
|
||||||
|
let time_str = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
let time_ms = time_str.parse::<u32>()?;
|
||||||
|
|
||||||
|
writeln!(output, "Starting timer {} for {} ms.", id, time_ms)?;
|
||||||
|
|
||||||
|
match timer_service_oneshot(id, time_ms) {
|
||||||
|
TimerServiceError::TimerOk => (),
|
||||||
|
_ => return Err(CommandError::BadArgs),
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_service_oneshot(id, time_ms);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements a command that starts a timer, blocking until the timer has
|
||||||
|
/// completed.
|
||||||
|
fn timer_blocking_command(
|
||||||
|
args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let time_str = args.next().ok_or(CommandError::BadArgs)?;
|
||||||
|
let time_ms = time_str.parse::<u32>()?;
|
||||||
|
|
||||||
|
writeln!(output, "Blocking {} ms waiting for timer.", time_ms)?;
|
||||||
|
|
||||||
|
// Set timer_id to 0, we don't need to use multiple timers here.
|
||||||
|
match timer_service_oneshot(0, time_ms) {
|
||||||
|
TimerServiceError::TimerOk => (),
|
||||||
|
_ => return Err(CommandError::BadArgs),
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_service_wait();
|
||||||
|
|
||||||
|
return Ok(writeln!(output, "Timer completed.")?);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements a command that checks the completed timers.
|
||||||
|
fn timer_completed_command(
|
||||||
|
_args: &mut dyn Iterator<Item = &str>,
|
||||||
|
_input: &mut dyn io::BufRead,
|
||||||
|
output: &mut dyn io::Write,
|
||||||
|
_builtin_cpio: &[u8],
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
return Ok(writeln!(output, "Timers completed: {:#032b}", timer_service_completed_timers())?);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user