diff --git a/apps/system/components/DebugConsole/kata-shell/Cargo.toml b/apps/system/components/DebugConsole/kata-shell/Cargo.toml index 12cf3de..e176637 100644 --- a/apps/system/components/DebugConsole/kata-shell/Cargo.toml +++ b/apps/system/components/DebugConsole/kata-shell/Cargo.toml @@ -5,7 +5,9 @@ authors = ["Matt Harvey "] edition = "2018" [dependencies] +crc = { version = "1.4.0", default_features = false } cstr_core = "0.2" +hex = { version = "0.4.3", default-features = false, features = ["alloc"] } kata-io = { path = "../kata-io" } kata-line-reader = { path = "../kata-line-reader" } kata-proc-common = { path = "../../ProcessManager/kata-proc-common" } @@ -13,3 +15,4 @@ kata-security-interface = { path = "../../SecurityCoordinator/kata-security-inte kata-storage-interface = { path = "../../StorageManager/kata-storage-interface" } log = "0.4" postcard = { version = "0.7", features = ["alloc"], default-features = false } +zmodem = { path = "../zmodem" } diff --git a/apps/system/components/DebugConsole/kata-shell/src/lib.rs b/apps/system/components/DebugConsole/kata-shell/src/lib.rs index 003bd85..babd9f8 100644 --- a/apps/system/components/DebugConsole/kata-shell/src/lib.rs +++ b/apps/system/components/DebugConsole/kata-shell/src/lib.rs @@ -6,6 +6,7 @@ use alloc::vec::Vec; use core::fmt; use core::fmt::Write; use cstr_core::CString; +use hex; use postcard; use kata_io as io; @@ -15,10 +16,13 @@ use kata_storage_interface::kata_storage_delete; use kata_storage_interface::kata_storage_read; use kata_storage_interface::kata_storage_write; +mod rz; + /// Error type indicating why a command line is not runnable. enum CommandError { UnknownCommand, BadArgs, + IO, Formatter(fmt::Error), } @@ -27,6 +31,7 @@ impl fmt::Display for CommandError { match self { CommandError::UnknownCommand => write!(f, "unknown command"), CommandError::BadArgs => write!(f, "invalid arguments"), + CommandError::IO => write!(f, "input / output error"), CommandError::Formatter(e) => write!(f, "{}", e), } } @@ -50,6 +55,12 @@ impl From for CommandError { } } +impl From for CommandError { + fn from(_err: io::Error) -> CommandError { + CommandError::IO + } +} + /// Read-eval-print loop for the DebugConsole command line interface. pub fn repl(output: &mut dyn io::Write, input: &mut dyn io::Read) -> ! { let mut line_reader = LineReader::new(); @@ -57,7 +68,7 @@ pub fn repl(output: &mut dyn io::Write, input: &mut dyn io::Read) -> ! { const PROMPT: &str = "KATA> "; let _ = output.write_str(PROMPT); match line_reader.read_line(output, input) { - Ok(cmdline) => dispatch_command(cmdline, output), + Ok(cmdline) => dispatch_command(cmdline, input, output), Err(e) => { let _ = writeln!(output, "\n{}", e); } @@ -69,7 +80,7 @@ pub fn repl(output: &mut dyn io::Write, input: &mut dyn io::Read) -> ! { /// /// The line is split on whitespace. The first token is the command; the /// remaining tokens are the arguments. -fn dispatch_command(cmdline: &str, output: &mut dyn io::Write) { +fn dispatch_command(cmdline: &str, input: &mut dyn io::Read, output: &mut dyn io::Write) { let mut args = cmdline.split_ascii_whitespace(); match args.nth(0) { Some(command) => { @@ -88,6 +99,7 @@ fn dispatch_command(cmdline: &str, output: &mut dyn io::Write) { "kvwrite" => kvwrite_command(&mut args, output), "install" => install_command(&mut args, output), "loglevel" => loglevel_command(&mut args, output), + "rz" => rz_command(input, output), "ps" => ps_command(), "scecho" => scecho_command(cmdline, output), "start" => start_command(&mut args, output), @@ -155,7 +167,7 @@ fn scecho_command(cmdline: &str, output: &mut dyn io::Write) -> Result<(), Comma Ok(()) } -// Set/display the max log level for the DebugConsole. +/// Implements a command to configure the max log level for the DebugConsole. fn loglevel_command( args: &mut dyn Iterator, output: &mut dyn io::Write, @@ -175,6 +187,21 @@ 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::Read, + mut output: &mut dyn io::Write, +) -> Result<(), CommandError> { + let upload = rz::rz(input, &mut output)?; + writeln!( + output, + "size: {}, crc32: {}", + upload.contents().len(), + hex::encode(upload.crc32().to_be_bytes()) + )?; + Ok(()) +} + /// Implements a "ps" command that dumps seL4 scheduler state to the console. fn ps_command() -> Result<(), CommandError> { extern "C" { diff --git a/apps/system/components/DebugConsole/kata-shell/src/rz.rs b/apps/system/components/DebugConsole/kata-shell/src/rz.rs new file mode 100644 index 0000000..5962054 --- /dev/null +++ b/apps/system/components/DebugConsole/kata-shell/src/rz.rs @@ -0,0 +1,50 @@ +/// Wrapper types for fully-buffered ZMODEM receives. +use alloc::vec::Vec; + +use crc::crc32; +use crc::Hasher32; + +use zmodem; + +use kata_io as io; + +pub struct Upload { + digest: crc32::Digest, + contents: Vec, +} + +impl Upload { + pub fn new() -> Upload { + Upload { + digest: crc32::Digest::new(crc32::IEEE), + contents: Vec::new(), + } + } + + pub fn crc32(&self) -> u32 { + self.digest.sum32() + } + + pub fn contents(&self) -> &[u8] { + self.contents.as_slice() + } +} + +impl io::Write for Upload { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.digest.write(buf); + self.contents.extend_from_slice(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +/// Receives using ZMODEM and wraps the result as an Upload. +pub fn rz(r: R, w: W) -> Result { + let mut upload = Upload::new(); + zmodem::recv::recv(r, w, &mut upload)?; + Ok(upload) +}