From fd2bebb81f17bfce9621db906ef166433bfccdad Mon Sep 17 00:00:00 2001 From: Matt Harvey <mattharvey@google.com> Date: Tue, 2 Feb 2021 14:12:08 -0800 Subject: [PATCH] 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 --- CMakeLists.txt | 27 +--- README.md | 11 ++ apps/system/CMakeLists.txt | 37 +++++ apps/system/README | 17 +++ .../system/components/DebugConsole/Cargo.lock | 49 +++++++ .../system/components/DebugConsole/Cargo.toml | 9 ++ .../DebugConsole/DebugConsole.camkes | 6 + .../kata-debug-console/Cargo.toml | 16 +++ .../kata-debug-console/src/run.rs | 27 ++++ .../DebugConsole/kata-io/Cargo.toml | 5 + .../DebugConsole/kata-io/src/lib.rs | 35 +++++ .../DebugConsole/kata-line-reader/Cargo.toml | 8 ++ .../DebugConsole/kata-line-reader/src/lib.rs | 78 +++++++++++ .../DebugConsole/kata-shell/Cargo.toml | 9 ++ .../DebugConsole/kata-shell/src/lib.rs | 127 ++++++++++++++++++ .../DebugConsole/kata-uart-client/Cargo.toml | 9 ++ .../DebugConsole/kata-uart-client/src/lib.rs | 37 +++++ .../components/UartDriver/UartDriver.camkes | 21 +++ .../system/components/UartDriver/src/driver.c | 94 +++++++++++++ apps/system/interfaces/uart.idl4 | 16 +++ apps/system/rust.cmake | 53 ++++++++ apps/system/system.camkes | 54 ++++++++ easy-settings.cmake | 5 + rust.cmake | 60 +++++++++ settings.cmake | 1 + 25 files changed, 785 insertions(+), 26 deletions(-) mode change 100644 => 120000 CMakeLists.txt create mode 100644 README.md create mode 100644 apps/system/CMakeLists.txt create mode 100644 apps/system/README create mode 100644 apps/system/components/DebugConsole/Cargo.lock create mode 100644 apps/system/components/DebugConsole/Cargo.toml create mode 100644 apps/system/components/DebugConsole/DebugConsole.camkes create mode 100644 apps/system/components/DebugConsole/kata-debug-console/Cargo.toml create mode 100644 apps/system/components/DebugConsole/kata-debug-console/src/run.rs create mode 100644 apps/system/components/DebugConsole/kata-io/Cargo.toml create mode 100644 apps/system/components/DebugConsole/kata-io/src/lib.rs create mode 100644 apps/system/components/DebugConsole/kata-line-reader/Cargo.toml create mode 100644 apps/system/components/DebugConsole/kata-line-reader/src/lib.rs create mode 100644 apps/system/components/DebugConsole/kata-shell/Cargo.toml create mode 100644 apps/system/components/DebugConsole/kata-shell/src/lib.rs create mode 100644 apps/system/components/DebugConsole/kata-uart-client/Cargo.toml create mode 100644 apps/system/components/DebugConsole/kata-uart-client/src/lib.rs create mode 100644 apps/system/components/UartDriver/UartDriver.camkes create mode 100644 apps/system/components/UartDriver/src/driver.c create mode 100644 apps/system/interfaces/uart.idl4 create mode 100644 apps/system/rust.cmake create mode 100644 apps/system/system.camkes create mode 100644 easy-settings.cmake create mode 100644 rust.cmake create mode 120000 settings.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index c58cc51..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required(VERSION 3.7.2) -project(ProcessManager C ASM) - -set(project_dir "${CMAKE_CURRENT_LIST_DIR}/../../") -file(GLOB project_modules ${project_dir}/projects/*) -list( - APPEND - CMAKE_MODULE_PATH - ${project_dir}/kernel - ${project_dir}/tools/seL4/cmake-tool/helpers/ - ${project_dir}/tools/seL4/elfloader-tool/ - ${project_modules} -) -set(POLLY_DIR ${project_dir}/tools/polly CACHE INTERNAL "") - -add_executable(ProcessManager src/main.c) - -target_link_libraries(ProcessManager - sel4runtime sel4 - muslc utils sel4muslcsys sel4platsupport sel4utils sel4debug) - -include(rootserver) -DeclareRootserver(ProcessManager) - -include(simulation) -GenerateSimulateScript() diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 120000 index 0000000..fba0c5b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1 @@ +../camkes/CMakeLists.txt \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5729571 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Kata OS + +This is a CAmkES project that assembles the entire Kata OS. It exists outside +the seL4 source trees, since it contains code not intended to go to upstream +seL4. + +This uses the [standard CAmkES build system](https://docs.sel4.systems/projects/camkes/manual.html#running-a-simple-example) +by symlinking CMakeLists.txt. It also symlinks settings.cmake, and so retains +the notion of "apps," which enables the build system to switch which assembly +it builds using the CAMKES\_APP CMake cache value. Kata OS just has one app, +*system*. diff --git a/apps/system/CMakeLists.txt b/apps/system/CMakeLists.txt new file mode 100644 index 0000000..423db69 --- /dev/null +++ b/apps/system/CMakeLists.txt @@ -0,0 +1,37 @@ +# +# Copyright 2018, Data61 +# Commonwealth Scientific and Industrial Research Organisation (CSIRO) +# ABN 41 687 119 230. +# +# This software may be distributed and modified according to the terms of +# the BSD 2-Clause license. Note that NO WARRANTY is provided. +# See "LICENSE_BSD2.txt" for details. +# +# @TAG(DATA61_BSD) +# + +cmake_minimum_required(VERSION 3.7.2) + +project(system) + +include(${CMAKE_CURRENT_LIST_DIR}/rust.cmake) + +RustAddLibrary( + kata_debug_console + SOURCE_DIR + ${CMAKE_CURRENT_LIST_DIR}/components/DebugConsole + TARGET + "riscv32imc-unknown-none-elf" + LIB_FILENAME + libkata_debug_console.a +) + +DeclareCAmkESComponent(DebugConsole + LIBS kata_debug_console +) + +DeclareCAmkESComponent(UartDriver + SOURCES components/UartDriver/src/driver.c +) + +DeclareCAmkESRootserver(system.camkes) diff --git a/apps/system/README b/apps/system/README new file mode 100644 index 0000000..d832c7a --- /dev/null +++ b/apps/system/README @@ -0,0 +1,17 @@ +<!-- + Copyright 2017, Data61 + Commonwealth Scientific and Industrial Research Organisation (CSIRO) + ABN 41 687 119 230. + + This software may be distributed and modified according to the terms of + the BSD 2-Clause license. Note that NO WARRANTY is provided. + See "LICENSE_BSD2.txt" for details. + + @TAG(DATA61_BSD) +--> +# + +UART driver for KZM. + +This is an example of accessing hardware device memory. The device memory +address may vary. diff --git a/apps/system/components/DebugConsole/Cargo.lock b/apps/system/components/DebugConsole/Cargo.lock new file mode 100644 index 0000000..a631062 --- /dev/null +++ b/apps/system/components/DebugConsole/Cargo.lock @@ -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" diff --git a/apps/system/components/DebugConsole/Cargo.toml b/apps/system/components/DebugConsole/Cargo.toml new file mode 100644 index 0000000..525f272 --- /dev/null +++ b/apps/system/components/DebugConsole/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] + +members = [ + "kata-debug-console", + "kata-io", + "kata-line-reader", + "kata-shell", + "kata-uart-client", +] diff --git a/apps/system/components/DebugConsole/DebugConsole.camkes b/apps/system/components/DebugConsole/DebugConsole.camkes new file mode 100644 index 0000000..81aa874 --- /dev/null +++ b/apps/system/components/DebugConsole/DebugConsole.camkes @@ -0,0 +1,6 @@ +component DebugConsole { + control; + uses uart_inf uart; + dataport Buf tx_dataport; + dataport Buf rx_dataport; +} diff --git a/apps/system/components/DebugConsole/kata-debug-console/Cargo.toml b/apps/system/components/DebugConsole/kata-debug-console/Cargo.toml new file mode 100644 index 0000000..bfd510a --- /dev/null +++ b/apps/system/components/DebugConsole/kata-debug-console/Cargo.toml @@ -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"] diff --git a/apps/system/components/DebugConsole/kata-debug-console/src/run.rs b/apps/system/components/DebugConsole/kata-debug-console/src/run.rs new file mode 100644 index 0000000..4892039 --- /dev/null +++ b/apps/system/components/DebugConsole/kata-debug-console/src/run.rs @@ -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); +} diff --git a/apps/system/components/DebugConsole/kata-io/Cargo.toml b/apps/system/components/DebugConsole/kata-io/Cargo.toml new file mode 100644 index 0000000..eaccbe5 --- /dev/null +++ b/apps/system/components/DebugConsole/kata-io/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "kata-io" +version = "0.1.0" +authors = ["Matt Harvey <mattharvey@google.com>"] +edition = "2018" diff --git a/apps/system/components/DebugConsole/kata-io/src/lib.rs b/apps/system/components/DebugConsole/kata-io/src/lib.rs new file mode 100644 index 0000000..5eb7877 --- /dev/null +++ b/apps/system/components/DebugConsole/kata-io/src/lib.rs @@ -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), + } + } +} diff --git a/apps/system/components/DebugConsole/kata-line-reader/Cargo.toml b/apps/system/components/DebugConsole/kata-line-reader/Cargo.toml new file mode 100644 index 0000000..feb53f4 --- /dev/null +++ b/apps/system/components/DebugConsole/kata-line-reader/Cargo.toml @@ -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" } diff --git a/apps/system/components/DebugConsole/kata-line-reader/src/lib.rs b/apps/system/components/DebugConsole/kata-line-reader/src/lib.rs new file mode 100644 index 0000000..ccecae5 --- /dev/null +++ b/apps/system/components/DebugConsole/kata-line-reader/src/lib.rs @@ -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) + } +} diff --git a/apps/system/components/DebugConsole/kata-shell/Cargo.toml b/apps/system/components/DebugConsole/kata-shell/Cargo.toml new file mode 100644 index 0000000..ff7cbb4 --- /dev/null +++ b/apps/system/components/DebugConsole/kata-shell/Cargo.toml @@ -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" } diff --git a/apps/system/components/DebugConsole/kata-shell/src/lib.rs b/apps/system/components/DebugConsole/kata-shell/src/lib.rs new file mode 100644 index 0000000..1f694a4 --- /dev/null +++ b/apps/system/components/DebugConsole/kata-shell/src/lib.rs @@ -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")?) +} diff --git a/apps/system/components/DebugConsole/kata-uart-client/Cargo.toml b/apps/system/components/DebugConsole/kata-uart-client/Cargo.toml new file mode 100644 index 0000000..63d7ca1 --- /dev/null +++ b/apps/system/components/DebugConsole/kata-uart-client/Cargo.toml @@ -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" } diff --git a/apps/system/components/DebugConsole/kata-uart-client/src/lib.rs b/apps/system/components/DebugConsole/kata-uart-client/src/lib.rs new file mode 100644 index 0000000..dcf8cd0 --- /dev/null +++ b/apps/system/components/DebugConsole/kata-uart-client/src/lib.rs @@ -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()) + } +} diff --git a/apps/system/components/UartDriver/UartDriver.camkes b/apps/system/components/UartDriver/UartDriver.camkes new file mode 100644 index 0000000..29b7d6a --- /dev/null +++ b/apps/system/components/UartDriver/UartDriver.camkes @@ -0,0 +1,21 @@ +/* + * Copyright 2017, Data61 + * Commonwealth Scientific and Industrial Research Organisation (CSIRO) + * ABN 41 687 119 230. + * + * This software may be distributed and modified according to the terms of + * the BSD 2-Clause license. Note that NO WARRANTY is provided. + * See "LICENSE_BSD2.txt" for details. + * + * @TAG(DATA61_BSD) + */ + +component UartDriver { + dataport Buf mem; + dataport Buf tx_dataport; + dataport Buf rx_dataport; + + // consumes Interrupt interrupt; + + provides uart_inf uart; +} diff --git a/apps/system/components/UartDriver/src/driver.c b/apps/system/components/UartDriver/src/driver.c new file mode 100644 index 0000000..046360a --- /dev/null +++ b/apps/system/components/UartDriver/src/driver.c @@ -0,0 +1,94 @@ +// 16550a UART driver +// +// Pared down from the xv6 RISC-V source (MIT license). +// https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/uart.c + +#include <camkes.h> + +#define UART0 (unsigned int)mem + +// the UART control registers are memory-mapped +// at address UART0. this macro returns the +// address of one of the registers. +#define Reg(reg) ((volatile unsigned char *)(UART0 + reg)) + +// the UART control registers. +// some have different meanings for +// read vs write. +// see http://byterunner.com/16550.html +#define RHR 0 // receive holding register (for input bytes) +#define THR 0 // transmit holding register (for output bytes) +#define IER 1 // interrupt enable register +#define IER_RX_ENABLE (1<<0) +#define IER_TX_ENABLE (1<<1) +#define FCR 2 // FIFO control register +#define FCR_FIFO_ENABLE (1<<0) +#define FCR_FIFO_CLEAR (3<<1) // clear the content of the two FIFOs +#define ISR 2 // interrupt status register +#define LCR 3 // line control register +#define LCR_EIGHT_BITS (3<<0) +#define LCR_BAUD_LATCH (1<<7) // special mode to set baud rate +#define LSR 5 // line status register +#define LSR_RX_READY (1<<0) // input is waiting to be read from RHR +#define LSR_TX_IDLE (1<<5) // THR can accept another character to send + +#define ReadReg(reg) (*(Reg(reg))) +#define WriteReg(reg, v) (*(Reg(reg)) = (v)) + +void uart__init() +{ + // disable interrupts (UART from generating, not hart from dispatching) + WriteReg(IER, 0x00); + + // special mode to set baud rate. + WriteReg(LCR, LCR_BAUD_LATCH); + + // LSB for baud rate of 38.4K. + WriteReg(0, 0x03); + + // MSB for baud rate of 38.4K. + WriteReg(1, 0x00); + + // leave set-baud mode, + // and set word length to 8 bits, no parity. + WriteReg(LCR, LCR_EIGHT_BITS); + + // reset and enable FIFOs. + WriteReg(FCR, FCR_FIFO_ENABLE | FCR_FIFO_CLEAR); + + // TODO (mattharvey): seL4 is not configured to dispatch UART interrupts to + // this driver yet. Until that time, this driver spins to wait. The proper + // thing will be to make a Rust embedded_hal implementation for Sparrow. + // + // enable transmit and receive interrupts. + // WriteReg(IER, IER_TX_ENABLE | IER_RX_ENABLE); +} + +static int uart_received() +{ + return ReadReg(LSR) & LSR_RX_READY; +} + +static int is_transmit_empty() { + return ReadReg(LSR) & LSR_TX_IDLE; +} + +void uart_rx(size_t n) { + char *c = (char*)rx_dataport; + // TODO(mattharvey): Error return value for n > PAGE_SIZE + for (size_t i = 0; i < n && i < PAGE_SIZE; ++i) { + while (!uart_received()); + *c = ReadReg(RHR); + ++c; + } +} + +void uart_tx(size_t n) { + char *c = (char*)tx_dataport; + // TODO(mattharvey): Error return value for n > PAGE_SIZE + for (size_t i = 0; i < n && i < PAGE_SIZE; ++i) { + while(!is_transmit_empty()); + WriteReg(THR, *c); + ++c; + } +} diff --git a/apps/system/interfaces/uart.idl4 b/apps/system/interfaces/uart.idl4 new file mode 100644 index 0000000..acfa770 --- /dev/null +++ b/apps/system/interfaces/uart.idl4 @@ -0,0 +1,16 @@ +/* + * Copyright 2017, Data61 + * Commonwealth Scientific and Industrial Research Organisation (CSIRO) + * ABN 41 687 119 230. + * + * This software may be distributed and modified according to the terms of + * the BSD 2-Clause license. Note that NO WARRANTY is provided. + * See "LICENSE_BSD2.txt" for details. + * + * @TAG(DATA61_BSD) + */ + +procedure uart_inf { + void rx(in size_t n); + void tx(in size_t n); +}; diff --git a/apps/system/rust.cmake b/apps/system/rust.cmake new file mode 100644 index 0000000..26f218b --- /dev/null +++ b/apps/system/rust.cmake @@ -0,0 +1,53 @@ +# +# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) +# +# SPDX-License-Identifier: BSD-2-Clause +# + +cmake_minimum_required(VERSION 3.8.2) +include_guard(GLOBAL) + +# add_library but for rust libraries. Invokes cargo in the SOURCE_DIR that is provided, +# all build output is placed in BUILD_DIR or CMAKE_CURRENT_BINARY_DIR if BUILD_DIR isn't provided. +# lib_name: Name of library that is created +# SOURCE_DIR: source directory of cargo project +# BUILD_DIR: directory for cargo build output +# TARGET: custom target to use. See in ../rust_targets/ for list of available targets. +# LIB_FILENAME: filename of library created by cargo +# DEPENDS: And target or file dependencies that need to be run before cargo +function(RustAddLibrary lib_name) + cmake_parse_arguments(PARSE_ARGV 1 RUST "" "SOURCE_DIR;BUILD_DIR;TARGET;LIB_FILENAME" "DEPENDS") + if(NOT "${RUST_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "Unknown arguments to RustAddLibrary ${RUST_UNPARSED_ARGUMENTS}") + endif() + if("${RUST_SOURCE_DIR}" STREQUAL "") + message(FATAL_ERROR "SOURCE_DIR must be set for RustAddLibrary") + endif() + if("${RUST_LIB_FILENAME}" STREQUAL "") + message(FATAL_ERROR "LIB_FILENAME must be set for RustAddLibrary") + endif() + if("${RUST_BUILD_DIR}" STREQUAL "") + set(RUST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) + endif() + + add_custom_target( + ${libmain}_custom + BYPRODUCTS + ${RUST_BUILD_DIR}/${RUST_LIB_FILENAME} + ${USES_TERMINAL_DEBUG} + DEPENDS ${RUST_DEPENDS} + WORKING_DIRECTORY ${RUST_SOURCE_DIR} + COMMAND + ${CMAKE_COMMAND} -E env cargo +nightly build + --target riscv32imc-unknown-none-elf + --target-dir ${RUST_BUILD_DIR} -Z unstable-options + --out-dir ${RUST_BUILD_DIR} + ) + + add_library(${lib_name} STATIC IMPORTED GLOBAL) + set_property( + TARGET ${lib_name} + PROPERTY IMPORTED_LOCATION "${RUST_BUILD_DIR}/${RUST_LIB_FILENAME}" + ) + add_dependencies(${lib_name} ${libmain}_custom) +endfunction() diff --git a/apps/system/system.camkes b/apps/system/system.camkes new file mode 100644 index 0000000..0acce4d --- /dev/null +++ b/apps/system/system.camkes @@ -0,0 +1,54 @@ +/* + * Copyright 2017, Data61 + * Commonwealth Scientific and Industrial Research Organisation (CSIRO) + * ABN 41 687 119 230. + * + * This software may be distributed and modified according to the terms of + * the BSD 2-Clause license. Note that NO WARRANTY is provided. + * See "LICENSE_BSD2.txt" for details. + * + * @TAG(DATA61_BSD) + */ + +import <std_connector.camkes>; + +import "interfaces/uart.idl4"; +import "components/UartDriver/UartDriver.camkes"; +import "components/DebugConsole/DebugConsole.camkes"; + +component UART { + hardware; + dataport Buf mem; + // TODO(mattharvey): Make receives wait on interrupt. + // emits Interrupt interrupt; +} + +assembly { + composition { + component UART uart; + component UartDriver drv; + component DebugConsole debug_console; + + connection seL4HardwareMMIO uart_mem(from drv.mem, to uart.mem); + // TODO(mattharvey): Make receives wait on interrupt. + // connection seL4HardwareInterrupt uart_interrupt( + // from uart.interrupt, to drv.interrupt); + connection seL4RPCCall uart_inf(from debug_console.uart, to drv.uart); + + connection seL4SharedData tx_channel( + from debug_console.tx_dataport, to drv.tx_dataport); + connection seL4SharedData rx_channel( + from debug_console.rx_dataport, to drv.rx_dataport); + } + + configuration { + uart.mem_paddr = 0x10000000; + uart.mem_size = 0x1000; + // seL4 claims 10 is bigger than irqMax if this is uncommented. + // uart.interrupt_irq_number = 10; + + random.ID = 1; + + uart.integrity_label = "drv"; + } +} diff --git a/easy-settings.cmake b/easy-settings.cmake new file mode 100644 index 0000000..a1cb6f3 --- /dev/null +++ b/easy-settings.cmake @@ -0,0 +1,5 @@ +set(CAMKES_APP "system" CACHE STRING "The one and only CAmkES application in this project") +set(SIMULATION ON CACHE BOOL "Whether to build simulate script") +set(RELEASE OFF CACHE BOOL "Performance optimized build") +set(PLATFORM "spike" CACHE STRING "The one and only seL4 platform for Sparrow") +set(KernelSel4Arch "riscv32" CACHE STRING "Specifies 32-bit branch of the seL4 spike platform") diff --git a/rust.cmake b/rust.cmake new file mode 100644 index 0000000..0332c72 --- /dev/null +++ b/rust.cmake @@ -0,0 +1,60 @@ +# Fork of tools/seL4/cmake-tool/helpers/rust.cmake. +# +# The differences are that a) xargo has been replaced with cargo +nightly, since +# xargo was upstreamed into Rust proper after seL4 created rust.cmake, and b) +# the Rust target is hard-coded to riscv32imc-unknown-none-elf to make this +# file easier to read. + +# +# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) +# +# SPDX-License-Identifier: BSD-2-Clause +# + +cmake_minimum_required(VERSION 3.8.2) +include_guard(GLOBAL) + +# add_library but for rust libraries. Invokes cargo in the SOURCE_DIR that is provided, +# all build output is placed in BUILD_DIR or CMAKE_CURRENT_BINARY_DIR if BUILD_DIR isn't provided. +# lib_name: Name of library that is created +# SOURCE_DIR: source directory of cargo project +# BUILD_DIR: directory for cargo build output +# TARGET: custom target to use. See in ../rust_targets/ for list of available targets. +# LIB_FILENAME: filename of library created by cargo +# DEPENDS: And target or file dependencies that need to be run before cargo +function(RustAddLibrary lib_name) + cmake_parse_arguments(PARSE_ARGV 1 RUST "" "SOURCE_DIR;BUILD_DIR;TARGET;LIB_FILENAME" "DEPENDS") + if(NOT "${RUST_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "Unknown arguments to RustAddLibrary ${RUST_UNPARSED_ARGUMENTS}") + endif() + if("${RUST_SOURCE_DIR}" STREQUAL "") + message(FATAL_ERROR "SOURCE_DIR must be set for RustAddLibrary") + endif() + if("${RUST_LIB_FILENAME}" STREQUAL "") + message(FATAL_ERROR "LIB_FILENAME must be set for RustAddLibrary") + endif() + if("${RUST_BUILD_DIR}" STREQUAL "") + set(RUST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) + endif() + + add_custom_target( + ${libmain}_custom + BYPRODUCTS + ${RUST_BUILD_DIR}/${RUST_LIB_FILENAME} + ${USES_TERMINAL_DEBUG} + DEPENDS ${RUST_DEPENDS} + WORKING_DIRECTORY ${RUST_SOURCE_DIR} + COMMAND + ${CMAKE_COMMAND} -E env cargo +nightly build + --target riscv32imc-unknown-none-elf + --target-dir ${RUST_BUILD_DIR} -Z unstable-options + --out-dir ${RUST_BUILD_DIR} + ) + + add_library(${lib_name} STATIC IMPORTED GLOBAL) + set_property( + TARGET ${lib_name} + PROPERTY IMPORTED_LOCATION "${RUST_BUILD_DIR}/${RUST_LIB_FILENAME}" + ) + add_dependencies(${lib_name} ${libmain}_custom) +endfunction() diff --git a/settings.cmake b/settings.cmake new file mode 120000 index 0000000..776b137 --- /dev/null +++ b/settings.cmake @@ -0,0 +1 @@ +../camkes/settings.cmake \ No newline at end of file