Replaces processmanager with a one-app CAmkES assembly for the entire Kata OS

This also adds a skeleton for the DebugConsole CLI taking IO from a UART
via some Rust wrapper functions, also defined in this change
(kata-uart-client).

Change-Id: I56856c14992010483da58c45f6550c0a4c9987b0
GitOrigin-RevId: e1b2d65ed3a7f627a9f7377caa407151fc943864
This commit is contained in:
Matt Harvey
2021-02-02 14:12:08 -08:00
committed by Sam Leffler
parent 5007f2c48c
commit fd2bebb81f
25 changed files with 785 additions and 26 deletions

View File

@@ -0,0 +1,49 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "cty"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3"
[[package]]
name = "kata-debug-console"
version = "0.1.0"
dependencies = [
"kata-shell",
"kata-uart-client",
"panic-halt",
]
[[package]]
name = "kata-io"
version = "0.1.0"
[[package]]
name = "kata-line-reader"
version = "0.1.0"
dependencies = [
"kata-io",
]
[[package]]
name = "kata-shell"
version = "0.1.0"
dependencies = [
"kata-io",
"kata-line-reader",
]
[[package]]
name = "kata-uart-client"
version = "0.1.0"
dependencies = [
"cty",
"kata-io",
]
[[package]]
name = "panic-halt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"

View File

@@ -0,0 +1,9 @@
[workspace]
members = [
"kata-debug-console",
"kata-io",
"kata-line-reader",
"kata-shell",
"kata-uart-client",
]

View File

@@ -0,0 +1,6 @@
component DebugConsole {
control;
uses uart_inf uart;
dataport Buf tx_dataport;
dataport Buf rx_dataport;
}

View File

@@ -0,0 +1,16 @@
[package]
name = "kata-debug-console"
version = "0.1.0"
authors = ["Matt Harvey <mattharvey@google.com>"]
edition = "2018"
description = "Kata OS DebugConsole"
[dependencies]
panic-halt = "0.2.0"
kata-shell = { path = "../kata-shell" }
kata-uart-client = { path = "../kata-uart-client" }
[lib]
name = "kata_debug_console"
path = "src/run.rs"
crate-type = ["staticlib"]

View File

@@ -0,0 +1,27 @@
//! Kata OS command line interface
// This brief bootstrap of Rust-in-Kata prototypes a minimal modular design
// for the DebugConsole CLI use case.
//
// * kata_io Read/Write interface (or move to std::, but that requires alloc)
// * kata_uart_client implementation of the kata_io interface
// * kata_line_reader
// * kata_shell
// * kata_debug_console main entry point fn run()
// std:: requires at least an allocator, which Kata does not have yet. For now
// the CLI will be implemented with only core::.
#![no_std]
extern crate panic_halt;
use kata_shell;
use kata_uart_client;
/// Entry point for DebugConsole. Runs the shell with UART IO.
#[no_mangle]
pub extern "C" fn run() -> ! {
let mut tx = kata_uart_client::Tx {};
let mut rx = kata_uart_client::Rx {};
kata_shell::repl(&mut tx, &mut rx);
}

View File

@@ -0,0 +1,5 @@
[package]
name = "kata-io"
version = "0.1.0"
authors = ["Matt Harvey <mattharvey@google.com>"]
edition = "2018"

View File

@@ -0,0 +1,35 @@
#![no_std]
pub struct Error;
/// Interface for the CLI to consume bytes.
pub trait Read {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error>;
}
/// Interface for the CLI to emit bytes.
pub trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize, Error>;
}
/// Adapter for writing core::fmt formatted strings.
impl core::fmt::Write for dyn Write + '_ {
/// Writes the bytes of a &str to the underlying writer.
fn write_str(&mut self, s: &str) -> core::fmt::Result {
match self.write(s.as_bytes()) {
Ok(_) => Ok(()),
Err(_) => Err(core::fmt::Error),
}
}
}
impl dyn Read + '_ {
pub fn get_u8(&mut self) -> Result<u8, Error> {
let mut buf: [u8; 1] = [0u8];
let n_read = self.read(&mut buf)?;
match n_read {
1usize => Ok(buf[0]),
_ => Err(Error),
}
}
}

View File

@@ -0,0 +1,8 @@
[package]
name = "kata-line-reader"
version = "0.1.0"
authors = ["Matt Harvey <mattharvey@google.com>"]
edition = "2018"
[dependencies]
kata-io = { path = "../kata-io" }

View File

@@ -0,0 +1,78 @@
#![no_std]
use core::fmt;
use kata_io as io;
const LINE_MAX: usize = 128;
pub enum LineReadError {
IO(io::Error),
Overflow,
Encoding(core::str::Utf8Error),
}
impl From<io::Error> for LineReadError {
fn from(err: io::Error) -> LineReadError {
LineReadError::IO(err)
}
}
impl From<core::str::Utf8Error> for LineReadError {
fn from(err: core::str::Utf8Error) -> LineReadError {
LineReadError::Encoding(err)
}
}
impl fmt::Display for LineReadError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LineReadError::IO(_) => write!(f, "IO error"),
LineReadError::Overflow => write!(f, "line too long"),
LineReadError::Encoding(_) => write!(f, "bad character encoding"),
}
}
}
pub struct LineReader {
// Owned by LineReader to facilitate static allocation.
buf: [u8; LINE_MAX],
}
impl LineReader {
pub fn new() -> LineReader {
LineReader {
buf: [0u8; LINE_MAX],
}
}
pub fn read_line(
&mut self,
output: &mut dyn io::Write,
input: &mut dyn io::Read,
) -> Result<&str, LineReadError> {
const DEL: u8 = 127u8;
const BACKSPACE: u8 = 8u8;
let mut len = 0;
while len < self.buf.len() {
let mut c = input.get_u8()?;
while c == DEL || c == BACKSPACE {
if len > 0 {
output.write(&[BACKSPACE, b' ', BACKSPACE])?;
len -= 1;
}
c = input.get_u8()?;
}
if c == b'\r' || c == b'\n' {
if len > 0 {
output.write(&[b'\n'])?;
}
return Ok(core::str::from_utf8(&self.buf[0..len])?);
}
self.buf[len] = c;
len += 1;
output.write(&[c])?;
}
Err(LineReadError::Overflow)
}
}

View File

@@ -0,0 +1,9 @@
[package]
name = "kata-shell"
version = "0.1.0"
authors = ["Matt Harvey <mattharvey@google.com>"]
edition = "2018"
[dependencies]
kata-io = { path = "../kata-io" }
kata-line-reader = { path = "../kata-line-reader" }

View File

@@ -0,0 +1,127 @@
#![no_std]
use core::fmt;
use core::fmt::Write;
use kata_io as io;
use kata_line_reader::LineReader;
/// Error type indicating why a command line is not runnable.
enum CommandError {
UnknownCommand,
BadArgs,
Formatter(fmt::Error),
}
impl fmt::Display for CommandError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CommandError::UnknownCommand => write!(f, "unknown command"),
CommandError::BadArgs => write!(f, "invalid arguments"),
CommandError::Formatter(e) => write!(f, "{}", e),
}
}
}
impl From<core::num::ParseIntError> for CommandError {
fn from(_err: core::num::ParseIntError) -> CommandError {
CommandError::BadArgs
}
}
impl From<core::num::ParseFloatError> for CommandError {
fn from(_err: core::num::ParseFloatError) -> CommandError {
CommandError::BadArgs
}
}
impl From<fmt::Error> for CommandError {
fn from(err: fmt::Error) -> CommandError {
CommandError::Formatter(err)
}
}
/// 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();
loop {
// The PROMPT is the Hiragana representation of the word "kata."
const PROMPT: &str = "かた ";
let _ = output.write_str(PROMPT);
match line_reader.read_line(output, input) {
Ok(cmdline) => dispatch_command(cmdline, output),
Err(e) => {
let _ = write!(output, "\n{}\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, output: &mut dyn io::Write) {
let mut args = cmdline.split_ascii_whitespace();
match args.nth(0) {
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 {
"echo" => echo_command(cmdline, output),
"add" => add_command(&mut args, output),
"clear" => clear_command(output),
_ => Err(CommandError::UnknownCommand),
};
if let Err(e) = result {
let _ = write!(output, "{}\n", e);
};
}
None => {
let _ = output.write_str("\n");
}
};
}
/// 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(write!(
output,
"{}\n",
&cmdline[COMMAND_LENGTH..cmdline.len()]
)?)
}
}
/// 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>,
output: &mut dyn io::Write,
) -> Result<(), CommandError> {
if let Some(x_str) = args.nth(0) {
if let Some(y_str) = args.nth(0) {
let x = x_str.parse::<f32>()?;
let y = y_str.parse::<f32>()?;
return Ok(write!(output, "{}\n", x + y)?);
}
}
Err(CommandError::BadArgs)
}
/// 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")?)
}

View File

@@ -0,0 +1,9 @@
[package]
name = "kata-uart-client"
version = "0.1.0"
authors = ["Matt Harvey <mattharvey@google.com>"]
edition = "2018"
[dependencies]
cty = "0.2.1"
kata-io = { path = "../kata-io" }

View File

@@ -0,0 +1,37 @@
#![no_std]
use kata_io as io;
// C interface to external UART driver.
extern "C" {
static rx_dataport: *mut cty::c_char;
static tx_dataport: *mut cty::c_char;
fn uart_rx(n: cty::size_t);
fn uart_tx(n: cty::size_t);
}
pub struct Rx {}
impl io::Read for Rx {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
unsafe {
uart_rx(buf.len());
let port = core::slice::from_raw_parts(rx_dataport, buf.len());
buf.copy_from_slice(&port);
}
Ok(buf.len())
}
}
pub struct Tx {}
impl io::Write for Tx {
fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
unsafe {
let port = core::slice::from_raw_parts_mut(tx_dataport, buf.len());
port.copy_from_slice(buf);
uart_tx(buf.len());
}
Ok(buf.len())
}
}