mirror of
https://github.com/AmbiML/sparrow-kata-full.git
synced 2025-08-01 21:59:41 +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" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = [
|
||||
"TEST_GLOBAL_ALLOCATOR",
|
||||
"TEST_MEMORY_MANAGER",
|
||||
"TEST_ML_COORDINATOR",
|
||||
"TEST_PANIC",
|
||||
"TEST_TIMER_SERVICE",
|
||||
]
|
||||
CONFIG_DEBUG_BUILD = []
|
||||
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]
|
||||
crc = { version = "1.4.0", default_features = false }
|
||||
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"] }
|
||||
kata-io = { path = "../kata-io" }
|
||||
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]
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt;
|
||||
use core::fmt::Write;
|
||||
use cpio::CpioNewcReader;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use kata_io as io;
|
||||
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_start;
|
||||
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_read;
|
||||
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_CPtr;
|
||||
use sel4_sys::seL4_MinSchedContextBits;
|
||||
use sel4_sys::seL4_ObjectType::*;
|
||||
use sel4_sys::seL4_WordBits;
|
||||
|
||||
use slot_allocator::KATA_CSPACE_SLOTS;
|
||||
|
||||
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" {
|
||||
static SELF_CNODE: seL4_CPtr;
|
||||
}
|
||||
|
||||
/// Error type indicating why a command line is not runnable.
|
||||
enum CommandError {
|
||||
pub enum CommandError {
|
||||
UnknownCommand,
|
||||
BadArgs,
|
||||
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.
|
||||
pub fn repl<T: io::BufRead>(
|
||||
output: &mut dyn io::Write,
|
||||
input: &mut T,
|
||||
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();
|
||||
loop {
|
||||
const PROMPT: &str = "KATA> ";
|
||||
let _ = output.write_str(PROMPT);
|
||||
match line_reader.read_line(output, input) {
|
||||
Ok(cmdline) => dispatch_command(cmdline, input, output, builtin_cpio),
|
||||
Err(e) => {
|
||||
let _ = writeln!(output, "\n{}", e);
|
||||
Ok(cmdline) => {
|
||||
let mut args = cmdline.split_ascii_whitespace();
|
||||
match args.next() {
|
||||
Some("?") | Some("help") => {
|
||||
let mut keys: Vec<&str> = cmds.keys().copied().collect();
|
||||
keys.sort();
|
||||
for k in keys {
|
||||
let _ = writeln!(output, "{}", k);
|
||||
}
|
||||
}
|
||||
Some(cmd) => {
|
||||
let result = cmds.get(cmd).map_or_else(
|
||||
|| Err(CommandError::UnknownCommand),
|
||||
|func| func(&mut args, input, output, builtin_cpio));
|
||||
if let Err(e) = result {
|
||||
let _ = writeln!(output, "{}", e);
|
||||
};
|
||||
}
|
||||
None => { let _ = output.write_str("\n"); },
|
||||
}
|
||||
}
|
||||
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();
|
||||
match args.next() {
|
||||
Some(command) => {
|
||||
// Statically binds command names to implementations fns, which are
|
||||
// defined below.
|
||||
//
|
||||
// Since even the binding is static, it is fine for each command
|
||||
// implementation to use its own preferred signature.
|
||||
let result = match command {
|
||||
"add" => add_command(&mut args, output),
|
||||
"builtins" => builtins_command(&mut args, builtin_cpio, output),
|
||||
"echo" => echo_command(cmdline, output),
|
||||
"clear" => clear_command(output),
|
||||
"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 {
|
||||
let _ = writeln!(output, "{}", e);
|
||||
};
|
||||
}
|
||||
None => {
|
||||
let _ = output.write_str("\n");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements a "builtins" command that lists the contents of the built-in cpio archive.
|
||||
fn builtins_command(
|
||||
_args: &mut dyn Iterator<Item = &str>,
|
||||
builtin_cpio: &[u8],
|
||||
_input: &mut dyn io::BufRead,
|
||||
output: &mut dyn io::Write,
|
||||
builtin_cpio: &[u8],
|
||||
) -> Result<(), CommandError> {
|
||||
for e in CpioNewcReader::new(builtin_cpio) {
|
||||
if e.is_err() {
|
||||
@ -193,34 +190,12 @@ fn builtins_command(
|
||||
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.
|
||||
fn loglevel_command(
|
||||
args: &mut dyn Iterator<Item = &str>,
|
||||
_input: &mut dyn io::BufRead,
|
||||
output: &mut dyn io::Write,
|
||||
_builtin_cpio: &[u8],
|
||||
) -> Result<(), CommandError> {
|
||||
if let Some(level) = args.next() {
|
||||
use log::LevelFilter;
|
||||
@ -237,59 +212,30 @@ fn loglevel_command(
|
||||
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.
|
||||
#[cfg(feature = "CONFIG_DEBUG_BUILD")]
|
||||
fn ps_command(_output: &mut dyn io::Write) -> Result<(), CommandError> {
|
||||
#[allow(unused_variables)]
|
||||
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 {
|
||||
kata_os_common::sel4_sys::seL4_DebugDumpScheduler();
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "CONFIG_DEBUG_BUILD"))]
|
||||
fn ps_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
|
||||
#[cfg(not(feature = "CONFIG_DEBUG_BUILD"))]
|
||||
Ok(writeln!(output, "Kernel support not configured!")?)
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
fn bundles_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(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() {
|
||||
Ok(bundle_ids) => {
|
||||
writeln!(output, "{}", bundle_ids.join("\n"))?;
|
||||
@ -343,9 +289,9 @@ fn collect_from_zmodem(
|
||||
|
||||
fn install_command(
|
||||
args: &mut dyn Iterator<Item = &str>,
|
||||
builtin_cpio: &[u8],
|
||||
input: &mut dyn io::BufRead,
|
||||
mut output: &mut dyn io::Write,
|
||||
builtin_cpio: &[u8],
|
||||
) -> Result<(), CommandError> {
|
||||
fn clear_slot(slot: seL4_CPtr) {
|
||||
unsafe {
|
||||
@ -399,7 +345,9 @@ fn install_command(
|
||||
|
||||
fn uninstall_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)?;
|
||||
match kata_pkg_mgmt_uninstall(bundle_id) {
|
||||
@ -415,7 +363,9 @@ fn uninstall_command(
|
||||
|
||||
fn start_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)?;
|
||||
match kata_proc_ctrl_start(bundle_id) {
|
||||
@ -431,7 +381,9 @@ fn start_command(
|
||||
|
||||
fn stop_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)?;
|
||||
match kata_proc_ctrl_stop(bundle_id) {
|
||||
@ -447,7 +399,9 @@ fn stop_command(
|
||||
|
||||
fn kvdelete_command(
|
||||
args: &mut dyn Iterator<Item = &str>,
|
||||
_input: &mut dyn io::BufRead,
|
||||
output: &mut dyn io::Write,
|
||||
_builtin_cpio: &[u8],
|
||||
) -> Result<(), CommandError> {
|
||||
let key = args.next().ok_or(CommandError::BadArgs)?;
|
||||
match kata_storage_delete(key) {
|
||||
@ -463,7 +417,9 @@ fn kvdelete_command(
|
||||
|
||||
fn kvread_command(
|
||||
args: &mut dyn Iterator<Item = &str>,
|
||||
_input: &mut dyn io::BufRead,
|
||||
output: &mut dyn io::Write,
|
||||
_builtin_cpio: &[u8],
|
||||
) -> Result<(), CommandError> {
|
||||
let key = args.next().ok_or(CommandError::BadArgs)?;
|
||||
match kata_storage_read(key) {
|
||||
@ -479,7 +435,9 @@ fn kvread_command(
|
||||
|
||||
fn kvwrite_command(
|
||||
args: &mut dyn Iterator<Item = &str>,
|
||||
_input: &mut dyn io::BufRead,
|
||||
output: &mut dyn io::Write,
|
||||
_builtin_cpio: &[u8],
|
||||
) -> Result<(), CommandError> {
|
||||
let key = args.next().ok_or(CommandError::BadArgs)?;
|
||||
let value = args.collect::<Vec<&str>>().join(" ");
|
||||
@ -494,52 +452,6 @@ fn kvwrite_command(
|
||||
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)
|
||||
-> Result<(), CommandError>
|
||||
{
|
||||
@ -556,7 +468,9 @@ fn mstats(output: &mut dyn io::Write, stats: &MemoryManagerStats)
|
||||
|
||||
fn mstats_command(
|
||||
_args: &mut dyn Iterator<Item = &str>,
|
||||
_input: &mut dyn io::BufRead,
|
||||
output: &mut dyn io::Write,
|
||||
_builtin_cpio: &[u8],
|
||||
) -> Result<(), CommandError> {
|
||||
match kata_memory_stats() {
|
||||
Ok(stats) => { mstats(output, &stats)?; }
|
||||
@ -565,275 +479,11 @@ fn mstats_command(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Implements a command that tests facilities that use the global allocator.
|
||||
/// Shamelessly cribbed from https://os.phil-opp.com/heap-allocation/
|
||||
fn test_alloc_command(output: &mut dyn io::Write) -> 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 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,
|
||||
fn state_mlcoord_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 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());
|
||||
}
|
||||
|
@ -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