DebugConsole: add cpio archive of builtin bundle objects

- replace the memory-mapped elf file by a cpio archive of bundle
  objects (BundleImages until we fill in what a bundle is)
- add a new "builtins" command to list the contents of the cpio
  archive (similar to cpio -t)
- extend the "install" command to load from the builtins archive
- switch the connection to ProcessManager to support the larger
  ObjDescBundle's coming from the cpio archive

Change-Id: I5d7c195b58937df3921f925de3637f325f53fa2f
GitOrigin-RevId: 410813e62ae8f38685a1b32deb2e80de538085a4
This commit is contained in:
Sam Leffler 2022-05-11 00:46:58 +00:00
parent 6b1fff796b
commit 746616b6d6
5 changed files with 94 additions and 17 deletions

View File

@ -10,6 +10,8 @@ import <TimerServiceInterface.camkes>;
component DebugConsole {
control;
dataport Buf(0x1000000) cpio_archive;
dataport Buf tx_dataport;
uses rust_write_inf uart_write;

View File

@ -11,6 +11,7 @@
#![no_std]
use core::slice;
use kata_io;
use kata_os_common::allocator;
use kata_os_common::logger::KataLogger;
@ -27,6 +28,8 @@ use slot_allocator::KATA_CSPACE_SLOTS;
extern "C" {
static SELF_CNODE_FIRST_SLOT: seL4_CPtr;
static SELF_CNODE_LAST_SLOT: seL4_CPtr;
static cpio_archive: *const u8; // CPIO archive of built-in files
}
#[no_mangle]
@ -62,8 +65,11 @@ pub extern "C" fn pre_init() {
/// Entry point for DebugConsole. Runs the shell with UART IO.
#[no_mangle]
pub extern "C" fn run() -> ! {
trace!("run");
let mut tx = kata_uart_client::Tx::new();
let mut rx = kata_io::BufReader::new(kata_uart_client::Rx::new());
kata_shell::repl(&mut tx, &mut rx);
let cpio_archive_ref = unsafe {
// XXX want begin-end or begin+size instead of a fixed-size block
slice::from_raw_parts(cpio_archive, 16777216)
};
kata_shell::repl(&mut tx, &mut rx, cpio_archive_ref);
}

View File

@ -17,6 +17,7 @@ CONFIG_KERNEL_MCS = []
[dependencies]
crc = { version = "1.4.0", default_features = false }
cpio = { git = "https://github.com/rcore-os/cpio" }
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }
kata-io = { path = "../kata-io" }
kata-line-reader = { path = "../kata-line-reader" }

View File

@ -1,11 +1,11 @@
#![no_std]
extern crate alloc;
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
use core::fmt;
use core::fmt::Write;
use cpio::CpioNewcReader;
use hex;
use log;
@ -24,8 +24,8 @@ 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::TimerServiceError;
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;
@ -95,13 +95,17 @@ impl From<io::Error> for 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) -> ! {
pub fn repl<T: io::BufRead>(
output: &mut dyn io::Write,
input: &mut T,
builtin_cpio: &[u8],
) -> ! {
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),
Ok(cmdline) => dispatch_command(cmdline, input, output, builtin_cpio),
Err(e) => {
let _ = writeln!(output, "\n{}", e);
}
@ -113,7 +117,12 @@ pub fn repl<T: io::BufRead>(output: &mut dyn io::Write, input: &mut T) -> ! {
///
/// 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) {
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.nth(0) {
Some(command) => {
@ -124,13 +133,14 @@ fn dispatch_command(cmdline: &str, input: &mut dyn io::BufRead, output: &mut dyn
// 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, input, 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),
@ -165,6 +175,23 @@ fn dispatch_command(cmdline: &str, input: &mut dyn io::BufRead, output: &mut dyn
};
}
/// 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],
output: &mut dyn io::Write,
) -> Result<(), CommandError> {
for e in CpioNewcReader::new(builtin_cpio) {
if e.is_err() {
writeln!(output, "{:?}", e.unwrap_err())?;
break; // NB: iterator does not terminate on error
}
let entry = e.unwrap();
writeln!(output, "{} {}", entry.name, entry.data.len())?;
}
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 "
@ -273,6 +300,33 @@ fn bundles_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
Ok(())
}
fn collect_from_cpio(
filename: &str,
cpio: &[u8],
output: &mut dyn io::Write,
) -> Option<ObjDescBundle> {
for e in CpioNewcReader::new(cpio) {
if e.is_err() {
writeln!(output, "cpio error {:?}", e.unwrap_err()).ok()?;
// NB: iterator does not terminate on error but also won't advance
break;
}
let entry = e.unwrap();
if entry.name == filename {
// Cheat, re-use zmodem data collector.
use kata_io::Write;
let mut upload = rz::Upload::new();
let len = upload.write(entry.data).ok()?;
upload.finish();
writeln!(output, "Collected {} bytes of data, crc32 {}",
len, hex::encode(upload.crc32().to_be_bytes())).ok()?;
return Some(upload.frames().clone());
}
}
writeln!(output, "Built-in file \"{}\" not found", filename).ok()?;
None
}
fn collect_from_zmodem(
input: &mut dyn io::BufRead,
mut output: &mut dyn io::Write,
@ -288,6 +342,7 @@ 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,
) -> Result<(), CommandError> {
@ -305,7 +360,11 @@ fn install_command(
Some("-z") => {
collect_from_zmodem(input, &mut output).ok_or(CommandError::IO)?
}
_ => {
Some(filename) => {
collect_from_cpio(filename, builtin_cpio, output)
.ok_or(CommandError::IO)?
}
None => {
// TODO: pattern-fill pages
kata_frame_alloc(8192).map_err(|_| CommandError::IO)?
}

View File

@ -50,15 +50,15 @@ component VectorCoreHw {
emits Interrupt data_fault;
}
component VectorPayload {
component BuiltinCpioArchive {
hardware;
dataport Buf(0x1000000) elf_file;
dataport Buf(0x1000000) cpio;
}
assembly {
composition {
component VectorCoreHw vctop;
component VectorPayload vc_payload;
component BuiltinCpioArchive cpio;
component OpenTitanUART uart;
component OpenTitanUARTDriver uart_driver;
@ -72,6 +72,10 @@ assembly {
component StorageManager storage_manager;
component TimerService timer_service;
// Built-in CPIO archive is visible only to DebugConsole.
connection seL4HardwareMMIO cpio_archive(from debug_console.cpio_archive,
to cpio.cpio);
// OpenTitanUARTDriver
connection seL4HardwareMMIO uart_mem(from uart_driver.mmio_region,
to uart.mmio_region);
@ -97,6 +101,7 @@ assembly {
connection seL4HardwareMMIO vc_dtcm(from ml_coordinator.dtcm,
to vctop.dtcm);
// TimerService
connection seL4HardwareMMIO timer_csr(from timer_service.csr,
to timer.csr);
@ -108,13 +113,17 @@ assembly {
// Hookup ProcessManager to DebugConsole for shell commands.
connection seL4RPCCall shell_process(from debug_console.proc_ctrl,
to process_manager.proc_ctrl);
connection seL4RPCCall shell_package(from debug_console.pkg_mgmt,
to process_manager.pkg_mgmt);
connection seL4RPCCall shell_ml(from debug_console.mlcoord,
to ml_coordinator.mlcoord);
connection seL4RPCCall shell_storage(from debug_console.storage,
to storage_manager.storage);
// Note this allocates a 4KB shared memory region for pkg install
// to pass an ObjDescArray
connection seL4RPCOverMultiSharedData shell_package(
from debug_console.pkg_mgmt,
to process_manager.pkg_mgmt);
// Connect the MemoryInterface to each component that needs to allocate
// global memory. Note this allocates a 4KB shared memory region to each
// component and copies data between components.
@ -159,6 +168,9 @@ assembly {
}
configuration {
cpio.cpio_paddr = 0x46000000;
cpio.cpio_size = 0x1000000;
uart.mmio_region_paddr = 0x50000000;
uart.mmio_region_size = 0x1000;
uart.tx_watermark_irq_number = 1;
@ -176,9 +188,6 @@ assembly {
vctop.instruction_fault_irq_number = 15; // kTopMatchaPlicIrqIdVcTopInstructionFault @ top_matcha.h
vctop.data_fault_irq_number = 16; // kTopMatchaPlicIrqIdVcTopDataFault @ top_matcha.h
vc_payload.elf_file_paddr = 0x46000000;
vc_payload.elf_file_size = 0x1000000;
timer.csr_paddr = 0x50030000;
timer.csr_size = 0x1000;