Rework basically the whole sw/matcha tree. Change-Id: I2f72d4799a5aa14f6eef1a534b91e4cc13e3ccae
diff --git a/app/Cargo.toml b/app/Cargo.toml index f1952ac..7876a41 100644 --- a/app/Cargo.toml +++ b/app/Cargo.toml
@@ -1,11 +1,10 @@ [package] -name = "matcha" +name = "matcha_app" version = "0.1.0" edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] +bare-io = "0.2" libtock = { path = "../../libtock-rs" } libtock_core = { path = "../../libtock-rs/core" } -libtock_codegen = { path = "../../libtock-rs/codegen" } +matcha_config = { path = "../config" }
diff --git a/app/src/dprintf.rs b/app/src/dprintf.rs new file mode 100644 index 0000000..179cfdf --- /dev/null +++ b/app/src/dprintf.rs
@@ -0,0 +1,28 @@ +//! App-side dprintf macro that calls through to the debug_uart capsule. + +use bare_io::{Cursor, Write}; +use core::fmt; +use libtock::syscalls; +use matcha_config::*; + +#[macro_export] +macro_rules! dprintf { + ($msg:expr) => ({ + $crate::dprintf::vdprintf(format_args!($msg)) + }); + ($fmt:expr, $($arg:tt)+) => ({ + $crate::dprintf::vdprintf(format_args!($fmt, $($arg)+)) + }); +} + +pub fn vdprintf(args: fmt::Arguments) { + let mut uart_buf = [0u8; 256]; + let mut cur = Cursor::new(&mut uart_buf[..]); + if cur.write_fmt(args).is_ok() { + let pos = cur.position(); + drop(cur); + let allow = syscalls::allow(DRIVER_NUM_DEBUG_UART, 0, &mut uart_buf); + let _result = syscalls::command(DRIVER_NUM_DEBUG_UART, 0, pos as usize, 0); + drop(allow); + } +}
diff --git a/app/src/main.rs b/app/src/main.rs index 75c75d9..dd4d4cb 100644 --- a/app/src/main.rs +++ b/app/src/main.rs
@@ -1,14 +1,22 @@ #![no_std] -use libtock::println; use libtock::result::TockResult; +use libtock::syscalls; +use matcha_config::*; + +mod dprintf; libtock_core::stack_size! {0x1000} +//------------------------------------------------------------------------------ + #[libtock::main] async fn main() -> TockResult<()> { - let drivers = libtock::retrieve_drivers()?; - drivers.console.create_console(); - println!("Hello Tock World from shodan/sw/matcha/src/main.rs!"); + dprintf!("sw/matcha/app/src/main.rs::main()\n"); + + dprintf!("Booting sel4 from TockOS app!\n"); + let _result = syscalls::command(DRIVER_NUM_ELF_LOADER, CMD_ELF_LOADER_BOOT_SEL4, 0, 0); + dprintf!("Booting sel4 from TockOS app done!\n"); + Ok(()) -} \ No newline at end of file +}
diff --git a/blob_fs/.gitignore b/blob_fs/.gitignore deleted file mode 100644 index a9d37c5..0000000 --- a/blob_fs/.gitignore +++ /dev/null
@@ -1,2 +0,0 @@ -target -Cargo.lock
diff --git a/blob_fs/src/blob_device.rs b/blob_fs/src/blob_device.rs index 0a6c48f..206fe8f 100644 --- a/blob_fs/src/blob_device.rs +++ b/blob_fs/src/blob_device.rs
@@ -125,12 +125,14 @@ } pub fn read_blockmap(&self, bitmap: &mut BitVector) -> Result<(), BFSErr> { - self.bd.read_range(self.blockmap_base(), slice_as_unsafe_blob_mut(bitmap.bits))?; + self.bd + .read_range(self.blockmap_base(), slice_as_unsafe_blob_mut(bitmap.bits))?; return Ok(()); } pub fn write_blockmap(&mut self, bitmap: &mut BitVector) -> Result<(), BFSErr> { - self.bd.write_range(self.blockmap_base(), slice_as_unsafe_blob(bitmap.bits))?; + self.bd + .write_range(self.blockmap_base(), slice_as_unsafe_blob(bitmap.bits))?; return Ok(()); } @@ -151,7 +153,10 @@ } pub fn write_inode(&mut self, index: usize, inode: &Inode) -> Result<(), BFSErr> { - dcheck!((inode.header.flags & NodeHeader::FLAG_INODE) != 0, BFSErr::InvalidArg); + dcheck!( + (inode.header.flags & NodeHeader::FLAG_INODE) != 0, + BFSErr::InvalidArg + ); let base = self.nodemap_base(); let offset = index * mem::size_of::<Inode>(); let blob = as_unsafe_blob(inode);
diff --git a/blob_fs/src/blob_fs.rs b/blob_fs/src/blob_fs.rs index 72e72d5..18ea80d 100644 --- a/blob_fs/src/blob_fs.rs +++ b/blob_fs/src/blob_fs.rs
@@ -54,7 +54,10 @@ pub fn get_blob(&self, hash: u64, blob_out: &mut [u8]) -> Result<(), BFSErr> { let result = self.find_inode(hash)?; let inode = result.1; - dcheck!(inode.blob_size as usize <= blob_out.len(), BFSErr::OutOfBounds); + dcheck!( + inode.blob_size as usize <= blob_out.len(), + BFSErr::OutOfBounds + ); let dst = &mut blob_out[..inode.blob_size as usize]; self.bd.read_blob(inode.inline_extent, dst)?; @@ -76,7 +79,8 @@ self.bd.write_blob(extent, blob_in)?; // Set the corresponding bits in our local bitmap - self.blockmap.clear_range(extent.offset(), extent.offset() + extent.size as usize)?; + self.blockmap + .clear_range(extent.offset(), extent.offset() + extent.size as usize)?; // FIXME flush bitmap to disk? // Create the inode for the new blob @@ -110,7 +114,8 @@ let extent = result.1.inline_extent; self.bd.invalidate_inode(inode_idx)?; - self.blockmap.set_range(extent.offset(), extent.offset() + extent.size as usize)?; + self.blockmap + .set_range(extent.offset(), extent.offset() + extent.size as usize)?; self.bd.delete_blob(extent)?; self.bd.delete_blob(extent)?; return Ok(()); @@ -160,7 +165,9 @@ fn find_extent(&self, blob_block_count: u16) -> Result<Extent, BFSErr> { let block_count = self.bd.bd.geom().block_count; - let offset = self.blockmap.find_span(0, block_count, blob_block_count as usize)?; + let offset = self + .blockmap + .find_span(0, block_count, blob_block_count as usize)?; return Ok(Extent { size: blob_block_count as u16, @@ -179,7 +186,10 @@ const BLOCK_SIZE: usize = 8192; const BLOCK_COUNT: usize = 32; - let geom = BlockDeviceGeometry { block_size: BLOCK_SIZE, block_count: BLOCK_COUNT }; + let geom = BlockDeviceGeometry { + block_size: BLOCK_SIZE, + block_count: BLOCK_COUNT, + }; let mut buf: [u8; BLOCK_SIZE * BLOCK_COUNT] = [0; BLOCK_SIZE * BLOCK_COUNT]; let mut dirty_bits = [0; BLOCK_SIZE * BLOCK_COUNT / 32]; let bd: &mut dyn BlockDevice = &mut TestDevice::new(geom, buf.as_mut_ptr(), &mut dirty_bits); @@ -193,7 +203,10 @@ assert_ok!(fs.sanity_check()); // Block map should start with 4 reserved blocks for metadata - assert_eq!(fs.blockmap.count_range(0, BLOCK_COUNT).unwrap(), BLOCK_COUNT - 4); + assert_eq!( + fs.blockmap.count_range(0, BLOCK_COUNT).unwrap(), + BLOCK_COUNT - 4 + ); // Store a small blob in the filesystem let blob_hash: u64 = 0xDEADBEEFF00DCAFE; @@ -202,7 +215,10 @@ assert_ok!(fs.put_blob(blob_hash, blob_contents)); // Block map should have lost one free block - assert_eq!(fs.blockmap.count_range(0, BLOCK_COUNT).unwrap(), BLOCK_COUNT - 5); + assert_eq!( + fs.blockmap.count_range(0, BLOCK_COUNT).unwrap(), + BLOCK_COUNT - 5 + ); // Storing it a second time should fail. assert_err!(fs.put_blob(blob_hash, blob_contents)); @@ -224,7 +240,10 @@ assert_err!(fs.delete_blob(blob_hash)); // Block map should have gained one free block - assert_eq!(fs.blockmap.count_range(0, BLOCK_COUNT).unwrap(), BLOCK_COUNT - 4); + assert_eq!( + fs.blockmap.count_range(0, BLOCK_COUNT).unwrap(), + BLOCK_COUNT - 4 + ); // Reading a non-existent blob should cause an error let bad_hash: u64 = 0xAAAAAAAAAAAAAAAA;
diff --git a/blob_fs/src/memmap_device.rs b/blob_fs/src/memmap_device.rs index 3e570d5..033eab7 100644 --- a/blob_fs/src/memmap_device.rs +++ b/blob_fs/src/memmap_device.rs
@@ -9,7 +9,10 @@ impl MemmapDevice { pub fn new(geom: BlockDeviceGeometry, flash_base: *mut u8) -> Self { - let result = MemmapDevice { geom: geom, flash_base: flash_base }; + let result = MemmapDevice { + geom: geom, + flash_base: flash_base, + }; return result; } } @@ -96,7 +99,9 @@ let bs = self.geom.block_size; unsafe { - self.flash_base.add(iblock * bs).copy_to(block.as_mut_ptr(), block.len()); + self.flash_base + .add(iblock * bs) + .copy_to(block.as_mut_ptr(), block.len()); } return Ok(()); @@ -108,7 +113,9 @@ let bs = self.geom.block_size; unsafe { - self.flash_base.add(iblock * bs).copy_from(block.as_ptr(), bs); + self.flash_base + .add(iblock * bs) + .copy_from(block.as_ptr(), bs); } return Ok(()); @@ -132,7 +139,9 @@ self.check_read_range(addr, data)?; unsafe { - self.flash_base.add(addr).copy_to(data.as_mut_ptr(), data.len()); + self.flash_base + .add(addr) + .copy_to(data.as_mut_ptr(), data.len()); } return Ok(()); @@ -144,7 +153,9 @@ self.check_write_range(addr, data)?; unsafe { - self.flash_base.add(addr).copy_from(data.as_ptr(), data.len()); + self.flash_base + .add(addr) + .copy_from(data.as_ptr(), data.len()); } return Ok(()); @@ -172,7 +183,10 @@ #[test] fn test_overwrite() { - let geom = BlockDeviceGeometry { block_size: 16, block_count: 4 }; + let geom = BlockDeviceGeometry { + block_size: 16, + block_count: 4, + }; let mut buf: Vec<u8> = vec![0; geom.block_count * geom.block_size]; let bd: &mut dyn BlockDevice = &mut MemmapDevice::new(geom, buf.as_mut_ptr()); @@ -193,7 +207,10 @@ #[test] #[should_panic] fn test_bad_overwrite() { - let geom = BlockDeviceGeometry { block_size: 16, block_count: 4 }; + let geom = BlockDeviceGeometry { + block_size: 16, + block_count: 4, + }; let mut buf: Vec<u8> = vec![0; geom.block_count * geom.block_size]; let bd: &mut dyn BlockDevice = &mut MemmapDevice::new(geom, buf.as_mut_ptr()); @@ -210,7 +227,10 @@ #[test] #[should_panic] fn test_read_unwritten_block() { - let geom = BlockDeviceGeometry { block_size: 16, block_count: 4 }; + let geom = BlockDeviceGeometry { + block_size: 16, + block_count: 4, + }; let mut buf: Vec<u8> = vec![0; geom.block_count * geom.block_size]; let bd: &mut dyn BlockDevice = &mut MemmapDevice::new(geom, buf.as_mut_ptr()); @@ -224,7 +244,10 @@ #[test] #[should_panic] fn test_read_erased_block() { - let geom = BlockDeviceGeometry { block_size: 16, block_count: 4 }; + let geom = BlockDeviceGeometry { + block_size: 16, + block_count: 4, + }; let mut buf: Vec<u8> = vec![0; geom.block_count * geom.block_size]; let bd: &mut dyn BlockDevice = &mut MemmapDevice::new(geom, buf.as_mut_ptr()); @@ -244,7 +267,10 @@ #[test] fn test_read_write() { - let geom = BlockDeviceGeometry { block_size: 16, block_count: 4 }; + let geom = BlockDeviceGeometry { + block_size: 16, + block_count: 4, + }; let mut buf: Vec<u8> = vec![0; geom.block_count * geom.block_size]; let bd: &mut dyn BlockDevice = &mut MemmapDevice::new(geom, buf.as_mut_ptr());
diff --git a/blob_fs/src/test_device.rs b/blob_fs/src/test_device.rs index 69fbf2e..74b0380 100644 --- a/blob_fs/src/test_device.rs +++ b/blob_fs/src/test_device.rs
@@ -12,8 +12,11 @@ impl<'a> TestDevice<'a> { pub fn new(geom: BlockDeviceGeometry, flash_base: *mut u8, dirty_bits: &'a mut [u32]) -> Self { assert_eq!(geom.block_size * geom.block_count, dirty_bits.len() * 32); - let result = - TestDevice { geom: geom, flash_base: flash_base, dirty: BitVector::new(dirty_bits) }; + let result = TestDevice { + geom: geom, + flash_base: flash_base, + dirty: BitVector::new(dirty_bits), + }; return result; } @@ -142,7 +145,9 @@ let bs = self.geom.block_size; unsafe { - self.flash_base.add(iblock * bs).copy_to(block.as_mut_ptr(), block.len()); + self.flash_base + .add(iblock * bs) + .copy_to(block.as_mut_ptr(), block.len()); } return Ok(()); @@ -154,7 +159,9 @@ let bs = self.geom.block_size; unsafe { - self.flash_base.add(iblock * bs).copy_from(block.as_ptr(), bs); + self.flash_base + .add(iblock * bs) + .copy_from(block.as_ptr(), bs); } self.mark_dirty(iblock * bs, bs)?; @@ -180,7 +187,9 @@ self.check_read_range(addr, data)?; unsafe { - self.flash_base.add(addr).copy_to(data.as_mut_ptr(), data.len()); + self.flash_base + .add(addr) + .copy_to(data.as_mut_ptr(), data.len()); } return Ok(()); @@ -192,7 +201,9 @@ self.check_write_range(addr, data)?; unsafe { - self.flash_base.add(addr).copy_from(data.as_ptr(), data.len()); + self.flash_base + .add(addr) + .copy_from(data.as_ptr(), data.len()); } self.mark_dirty(addr, data.len())?; @@ -224,7 +235,10 @@ fn test_overwrite() { const BLOCK_SIZE: usize = 16; const BLOCK_COUNT: usize = 4; - let geom = BlockDeviceGeometry { block_size: BLOCK_SIZE, block_count: BLOCK_COUNT }; + let geom = BlockDeviceGeometry { + block_size: BLOCK_SIZE, + block_count: BLOCK_COUNT, + }; let mut buf: [u8; BLOCK_SIZE * BLOCK_COUNT] = [0; BLOCK_SIZE * BLOCK_COUNT]; let mut dirty_bits = [0; BLOCK_SIZE * BLOCK_COUNT / 32]; let bd: &mut dyn BlockDevice = &mut TestDevice::new(geom, buf.as_mut_ptr(), &mut dirty_bits); @@ -248,7 +262,10 @@ fn test_bad_overwrite() { const BLOCK_SIZE: usize = 16; const BLOCK_COUNT: usize = 4; - let geom = BlockDeviceGeometry { block_size: BLOCK_SIZE, block_count: BLOCK_COUNT }; + let geom = BlockDeviceGeometry { + block_size: BLOCK_SIZE, + block_count: BLOCK_COUNT, + }; let mut buf: [u8; BLOCK_SIZE * BLOCK_COUNT] = [0; BLOCK_SIZE * BLOCK_COUNT]; let mut dirty_bits = [0; BLOCK_SIZE * BLOCK_COUNT / 32]; let bd: &mut dyn BlockDevice = &mut TestDevice::new(geom, buf.as_mut_ptr(), &mut dirty_bits); @@ -268,7 +285,10 @@ fn test_read_unwritten_block() { const BLOCK_SIZE: usize = 16; const BLOCK_COUNT: usize = 4; - let geom = BlockDeviceGeometry { block_size: BLOCK_SIZE, block_count: BLOCK_COUNT }; + let geom = BlockDeviceGeometry { + block_size: BLOCK_SIZE, + block_count: BLOCK_COUNT, + }; let mut buf: [u8; BLOCK_SIZE * BLOCK_COUNT] = [0; BLOCK_SIZE * BLOCK_COUNT]; let mut dirty_bits = [0; BLOCK_SIZE * BLOCK_COUNT / 32]; let bd: &mut dyn BlockDevice = &mut TestDevice::new(geom, buf.as_mut_ptr(), &mut dirty_bits); @@ -285,7 +305,10 @@ fn test_read_erased_block() { const BLOCK_SIZE: usize = 16; const BLOCK_COUNT: usize = 4; - let geom = BlockDeviceGeometry { block_size: BLOCK_SIZE, block_count: BLOCK_COUNT }; + let geom = BlockDeviceGeometry { + block_size: BLOCK_SIZE, + block_count: BLOCK_COUNT, + }; let mut buf: [u8; BLOCK_SIZE * BLOCK_COUNT] = [0; BLOCK_SIZE * BLOCK_COUNT]; let mut dirty_bits = [0; BLOCK_SIZE * BLOCK_COUNT / 32]; let bd: &mut dyn BlockDevice = &mut TestDevice::new(geom, buf.as_mut_ptr(), &mut dirty_bits); @@ -308,7 +331,10 @@ fn test_read_write() { const BLOCK_SIZE: usize = 16; const BLOCK_COUNT: usize = 4; - let geom = BlockDeviceGeometry { block_size: BLOCK_SIZE, block_count: BLOCK_COUNT }; + let geom = BlockDeviceGeometry { + block_size: BLOCK_SIZE, + block_count: BLOCK_COUNT, + }; let mut buf: [u8; BLOCK_SIZE * BLOCK_COUNT] = [0; BLOCK_SIZE * BLOCK_COUNT]; let mut dirty_bits = [0; BLOCK_SIZE * BLOCK_COUNT / 32]; let bd: &mut dyn BlockDevice = &mut TestDevice::new(geom, buf.as_mut_ptr(), &mut dirty_bits);
diff --git a/board/Cargo.toml b/board/Cargo.toml deleted file mode 100644 index 2d4ec52..0000000 --- a/board/Cargo.toml +++ /dev/null
@@ -1,29 +0,0 @@ -[package] -name = "opentitan-matcha" -version = "0.1.0" -authors = ["Tock Project Developers <tock-dev@googlegroups.com>"] -build = "build.rs" -edition = "2018" - -[dependencies] -components = { path = "../../tock/boards/components" } -rv32i = { path = "../../tock/arch/rv32i" } -capsules = { path = "../../tock/capsules" } -kernel = { path = "../../tock/kernel" } -lowrisc = { path = "../../tock/chips/lowrisc" } - -matcha = { path = "../chip" } -blob_fs = { path = "../blob_fs" } -matcha-capsules = { path = "../capsules" } - -[features] -# OpenTitan Matcha SoC design can be synthesized or compiled for different targets. A -# target can be a specific FPGA board, an ASIC technology, or a simulation tool. -# Please see: https://docs.opentitan.org/doc/ug/getting_started/ for further -# information. -# -# OpenTitan Matcha CPU and possibly other components must be configured appropriately -# for a specific target: -# - sim_verilator: -# OpenTitan Matcha SoC design simulated in Verilator. -sim_verilator = ["matcha/config_sim_verilator"]
diff --git a/board/Makefile b/board/Makefile deleted file mode 100644 index 41bc04d..0000000 --- a/board/Makefile +++ /dev/null
@@ -1,34 +0,0 @@ -# Makefile for building the tock kernel for the OpenTitan Matcha platform - -DEFAULT_BOARD_CONFIGURATION=fpga_nexysvideo -TARGET=riscv32imc-unknown-none-elf -PLATFORM=opentitan-matcha -FLASHID=--dev-id="0403:6010" -RISC_PREFIX = riscv64-elf - - -include Makefile.common - -# Pass OpenTitan board configuration option in `BOARD_CONFIGURATION` through -# Cargo `--features`. Please see `Cargo.toml` for available options. -ifneq ($(BOARD_CONFIGURATION),) - CARGO_FLAGS += --features=$(BOARD_CONFIGURATION) -else - CARGO_FLAGS += --features=$(DEFAULT_BOARD_CONFIGURATION) -endif - -qemu: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).elf - $(call check_defined, OPENTITAN_BOOT_ROM) - qemu-system-riscv32 -M opentitan -kernel $^ -bios $(OPENTITAN_BOOT_ROM) -nographic -serial mon:stdio - -qemu-app: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).elf - $(call check_defined, OPENTITAN_BOOT_ROM) - qemu-system-riscv32 -M opentitan -kernel $^ -bios $(OPENTITAN_BOOT_ROM) -device loader,file=$(APP),addr=0x20030000 -nographic -serial mon:stdio - -flash: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin - $(OPENTITAN_TREE)/build-out/sw/host/spiflash/spiflash $(FLASHID) --input=$(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin - -flash-app: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).elf - $(RISC_PREFIX)-objcopy --update-section .apps=$(APP) $^ $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM)-app.elf - $(RISC_PREFIX)-objcopy --output-target=binary $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM)-app.elf $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM)-app.bin - $(OPENTITAN_TREE)/build-out/sw/host/spiflash/spiflash $(FLASHID) --input=$(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM)-app.bin
diff --git a/board/Makefile.common b/board/Makefile.common deleted file mode 100644 index 6ace79a..0000000 --- a/board/Makefile.common +++ /dev/null
@@ -1,296 +0,0 @@ -# Force the Shell to be bash as some systems have strange default shells -SHELL := bash - -# Remove built-in rules and variables -# n.b. no-op for make --version < 4.0 -MAKEFLAGS += -r -MAKEFLAGS += -R - -# The absolute path of the directory containing this `Makefile.common` file. -MAKEFILE_COMMON_PATH := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) - -# The absolute path of Tock's root directory. -# This is currently the parent directory of MAKEFILE_COMMON_PATH. -#TOCK_ROOT_DIRECTORY := $(dir $(abspath $(MAKEFILE_COMMON_PATH))) -TOCK_ROOT_DIRECTORY := /usr/local/google/home/aappleby/shodan/sw/tock/ - - -# Common defaults that specific boards can override, but likely do not need to. -TOOLCHAIN ?= llvm -CARGO ?= cargo -RUSTUP ?= rustup - -# Default location of target directory (relative to board makefile) -# passed to cargo --target_dir -TARGET_DIRECTORY ?= $(TOCK_ROOT_DIRECTORY)target/ - -# RUSTC_FLAGS allows boards to define board-specific options. -# This will hopefully move into Cargo.toml (or Cargo.toml.local) eventually. -# lld uses the page size to align program sections. It defaults to 4096 and this -# puts a gap between before the .relocate section. `zmax-page-size=512` tells -# lld the actual page size so it doesn't have to be conservative. -RUSTC_FLAGS ?= \ - -C link-arg=-Tlayout.ld \ - -C linker=rust-lld \ - -C linker-flavor=ld.lld \ - -C relocation-model=dynamic-no-pic \ - -C link-arg=-zmax-page-size=512 \ - -C link-arg=-icf=all \ - -# RISC-V-specific flags. -ifneq ($(findstring riscv32i, $(TARGET)),) - # NOTE: This flag causes kernel panics on some ARM cores. Since the - # size benefit is almost exclusively for RISC-V, we only apply it for - # those targets. - RUSTC_FLAGS += -C force-frame-pointers=no -endif - -# RUSTC_FLAGS_TOCK by default extends RUSTC_FLAGS with options -# that are global to all Tock boards. -# -# We use `remap-path-prefix` to remove user-specific filepath strings for error -# reporting from appearing in the generated binary. -RUSTC_FLAGS_TOCK ?= \ - $(RUSTC_FLAGS) \ - --remap-path-prefix=$(TOCK_ROOT_DIRECTORY)= \ - -# Disallow warnings for continuous integration builds. Disallowing them here -# ensures that warnings during testing won't prevent compilation from succeeding. -ifeq ($(CI),true) - RUSTC_FLAGS_TOCK += -D warnings -endif - -# The following flags should only be passed to the board's binary crate, but -# not to any of its dependencies (the kernel, capsules, chips, etc.). The -# dependencies wouldn't use it, but because the link path is different for each -# board, Cargo wouldn't be able to cache builds of the dependencies. -# -# Indeed, as far as Cargo is concerned, building the kernel with -# `-C link-arg=-L/tock/boards/imix` is different than building the kernel with -# `-C link-arg=-L/tock/boards/hail`, so Cargo would have to rebuild the kernel -# for each board instead of caching it per board (even if in reality the same -# kernel is built because the link-arg isn't used by the kernel). -# -# Ultimately, this should move to the Cargo.toml, for example when -# https://github.com/rust-lang/cargo/pull/7811 is merged into Cargo. -# -# The difference between `RUSTC_FLAGS_TOCK` and `RUSTC_FLAGS_FOR_BIN` is that -# the former is forwarded to all the dependencies (being passed to cargo via -# the `RUSTFLAGS` environment variable), whereas the latter is only applied to -# the final binary crate (being passed as parameter to `cargo rustc`). -RUSTC_FLAGS_FOR_BIN ?= \ - -C link-arg=-L$(abspath .) \ - -# http://stackoverflow.com/questions/10858261/abort-makefile-if-variable-not-set -# Check that given variables are set and all have non-empty values, print an -# error otherwise. -check_defined = $(strip $(foreach 1,$1,$(if $(value $1),,$(error Undefined variable "$1")))) - -# Check that we know the basics of what we are compiling for. -# `PLATFORM`: The name of the board that the kernel is being compiled for. -# `TARGET` : The Rust target architecture the kernel is being compiled for. -$(call check_defined, PLATFORM) -$(call check_defined, TARGET) - -# Location of target-specific build -TARGET_PATH := $(TARGET_DIRECTORY)$(TARGET) - -# If environment variable V is non-empty, be verbose. -ifneq ($(V),) - Q = - VERBOSE = --verbose -else - Q = @ - VERBOSE = -endif - -# Ask git what version of the Tock kernel we are compiling, so we can include -# this within the binary. If Tock is not within a git repo then we fallback to -# a set string which should be updated with every release. -export TOCK_KERNEL_VERSION := $(shell git describe --tags --always 2> /dev/null || echo "1.4+") - -# Validate that rustup is new enough. -MINIMUM_RUSTUP_VERSION := 1.11.0 -RUSTUP_VERSION := $(strip $(word 2, $(shell $(RUSTUP) --version))) -ifeq ($(shell $(TOCK_ROOT_DIRECTORY)tools/semver.sh $(RUSTUP_VERSION) \< $(MINIMUM_RUSTUP_VERSION)), true) - $(warning Required tool `$(RUSTUP)` is out-of-date.) - $(warning Running `$(RUSTUP) update` in 3 seconds (ctrl-c to cancel)) - $(shell sleep 3s) - DUMMY := $(shell $(RUSTUP) update) -endif - -# Verify that various required Rust components are installed. All of these steps -# only have to be done once per Rust version, but will take some time when -# compiling for the first time. -LLVM_TOOLS_INSTALLED := $(shell $(RUSTUP) component list | grep 'llvm-tools-preview.*(installed)' > /dev/null; echo $$?) -ifeq ($(LLVM_TOOLS_INSTALLED),1) - $(shell $(RUSTUP) component add llvm-tools-preview) -endif -ifneq ($(shell $(RUSTUP) component list | grep rust-src),rust-src (installed)) - $(shell $(RUSTUP) component add rust-src) -endif -ifneq ($(shell $(RUSTUP) target list | grep "$(TARGET) (installed)"),$(TARGET) (installed)) - $(shell $(RUSTUP) target add $(TARGET)) -endif - -# If the user is using the standard toolchain we need to get the full path. -# rustup should take care of this for us by putting in a proxy in .cargo/bin, -# but until that is setup we workaround it. -ifeq ($(TOOLCHAIN),llvm) - TOOLCHAIN = "$(shell dirname $(shell find `rustc --print sysroot` -name llvm-size))/llvm" -endif - -# Set variables of the key tools we need to compile a Tock kernel. -SIZE ?= $(TOOLCHAIN)-size -OBJCOPY ?= $(TOOLCHAIN)-objcopy -OBJDUMP ?= $(TOOLCHAIN)-objdump - -# Set additional flags to produce binary from .elf. -# * --strip-sections prevents enormous binaries when SRAM is below flash. -# * --remove-section .apps prevents the .apps section from being included in the -# kernel binary file. This section is a placeholder for optionally including -# application binaries, and only needs to exist in the .elf. By removing it, -# we prevent the kernel binary from overwriting applications. -OBJCOPY_FLAGS ?= --strip-sections -S --remove-section .apps -# This make variable allows board-specific Makefiles to pass down options to -# the Cargo build command. For example, in boards/<custom_board>/Makefile: -# `CARGO_FLAGS += --features=foo` would pass feature `foo` to the top level -# Cargo.toml. -CARGO_FLAGS ?= -# Add default flags to cargo. Boards can add additional options in CARGO_FLAGS -CARGO_FLAGS_TOCK ?= $(VERBOSE) --target=$(TARGET) --package $(PLATFORM) --target-dir=$(TARGET_DIRECTORY) $(CARGO_FLAGS) -# Set the default flags we need for objdump to get a .lst file. -OBJDUMP_FLAGS ?= --disassemble-all --source --section-headers --demangle -# Set default flags for size -SIZE_FLAGS ?= - -# Need an extra flag for OBJDUMP if we are on a thumb platform. -ifneq (,$(findstring thumb,$(TARGET))) - OBJDUMP_FLAGS += --arch-name=thumb -endif - -# Check whether the system already has a sha256sum application -# present, if not use the custom shipped one -ifeq (, $(shell sha256sum --version 2>/dev/null)) - # No system sha256sum available - SHA256SUM := $(CARGO) run --manifest-path $(TOCK_ROOT_DIRECTORY)tools/sha256sum/Cargo.toml -- 2>/dev/null -else - # Use system sha256sum - SHA256SUM := sha256sum -endif - -# Dump configuration for verbose builds -ifneq ($(V),) - $(info ) - $(info *******************************************************) - $(info TOCK KERNEL BUILD SYSTEM -- VERBOSE BUILD CONFIGURATION) - $(info *******************************************************) - $(info MAKEFILE_COMMON_PATH = $(MAKEFILE_COMMON_PATH)) - $(info TOCK_ROOT_DIRECTORY = $(TOCK_ROOT_DIRECTORY)) - $(info TARGET_DIRECTORY = $(TARGET_DIRECTORY)) - $(info ) - $(info PLATFORM = $(PLATFORM)) - $(info TARGET = $(TARGET)) - $(info TOCK_KERNEL_VERSION = $(TOCK_KERNEL_VERSION)) - $(info RUSTC_FLAGS = $(RUSTC_FLAGS)) - $(info RUSTC_FLAGS_TOCK = $(RUSTC_FLAGS_TOCK)) - $(info MAKEFLAGS = $(MAKEFLAGS)) - $(info OBJDUMP_FLAGS = $(OBJDUMP_FLAGS)) - $(info OBJCOPY_FLAGS = $(OBJCOPY_FLAGS)) - $(info CARGO_FLAGS = $(CARGO_FLAGS)) - $(info CARGO_FLAGS_TOCK = $(CARGO_FLAGS_TOCK)) - $(info SIZE_FLAGS = $(SIZE_FLAGS)) - $(info ) - $(info TOOLCHAIN = $(TOOLCHAIN)) - $(info SIZE = $(SIZE)) - $(info OBJCOPY = $(OBJCOPY)) - $(info OBJDUMP = $(OBJDUMP)) - $(info CARGO = $(CARGO)) - $(info RUSTUP = $(RUSTUP)) - $(info SHA256SUM = $(SHA256SUM)) - $(info ) - $(info cargo --version = $(shell $(CARGO) --version)) - $(info rustc --version = $(shell rustc --version)) - $(info rustup --version = $(shell $(RUSTUP) --version)) - $(info *******************************************************) - $(info ) -endif - -.PRECIOUS: %.elf -# Support rules - -# User-facing targets -.PHONY: all -all: release - -# `make check` runs the Rust compiler but does not actually output the final -# binary. This makes checking for Rust errors much faster. -.PHONY: check -check: - $(Q)$(CARGO) check $(VERBOSE) $(CARGO_FLAGS_TOCK) - - -.PHONY: clean -clean:: - $(Q)$(CARGO) clean $(VERBOSE) --target-dir=$(TARGET_DIRECTORY) - -.PHONY: release -release: $(TARGET_PATH)/release/$(PLATFORM).bin - -.PHONY: debug -debug: $(TARGET_PATH)/debug/$(PLATFORM).bin - -.PHONY: debug-lst -debug-lst: $(TARGET_PATH)/debug/$(PLATFORM).lst - -.PHONY: doc -doc: | target - @# This mess is all to work around rustdoc giving no way to return an - @# error if there are warnings. This effectively simulates that. - $(Q)RUSTDOCFLAGS='-Z unstable-options --document-hidden-items -D warnings' $(CARGO) --color=always doc $(VERBOSE) --release --package $(PLATFORM) --target-dir=$(TARGET_DIRECTORY) 2>&1 | tee /dev/tty | grep -q warning && (echo "Warnings detected during doc build" && if [[ $$CI == "true" ]]; then echo "Erroring due to CI context" && exit 33; fi) || if [ $$? -eq 33 ]; then exit 1; fi - - -.PHONY: lst -lst: $(TARGET_PATH)/release/$(PLATFORM).lst - -# Helper rule for showing the TARGET used by this board. Useful when building -# the documentation for all boards. -.PHONY: show-target -show-target: - $(info $(TARGET)) - -# Support rules - -target: - @mkdir -p $(TARGET_PATH) - -# Cargo outputs an elf file (just without a file extension) -%.elf: % - $(Q)cp $< $@ - - -%.bin: %.elf - $(Q)$(OBJCOPY) --output-target=binary $(OBJCOPY_FLAGS) $< $@ - $(Q)$(SHA256SUM) $@ - -%.lst: %.elf - $(Q)$(OBJDUMP) $(OBJDUMP_FLAGS) $< > $@ - - -$(TOCK_ROOT_DIRECTORY)tools/sha256sum/target/debug/sha256sum: - $(Q)$(CARGO) build $(VERBOSE) --manifest-path $(TOCK_ROOT_DIRECTORY)tools/sha256sum/Cargo.toml - - -# Cargo-drivers -# We want to always invoke cargo (yay nested build systems), so these need to -# be phony, which means they can't be pattern rules. - -.PHONY: $(TARGET_PATH)/release/$(PLATFORM) -$(TARGET_PATH)/release/$(PLATFORM): - $(Q)RUSTFLAGS="$(RUSTC_FLAGS_TOCK)" $(CARGO) rustc $(CARGO_FLAGS_TOCK) --bin $(PLATFORM) --release -- $(RUSTC_FLAGS_FOR_BIN) - $(Q)$(SIZE) $(SIZE_FLAGS) $@ - -.PHONY: $(TARGET_PATH)/debug/$(PLATFORM) -$(TARGET_PATH)/debug/$(PLATFORM): - $(Q)RUSTFLAGS="$(RUSTC_FLAGS_TOCK)" $(CARGO) rustc $(CARGO_FLAGS_TOCK) --bin $(PLATFORM) -- $(RUSTC_FLAGS_FOR_BIN) - $(Q)$(SIZE) $(SIZE_FLAGS) $@
diff --git a/board/README.md b/board/README.md deleted file mode 100644 index 551991f..0000000 --- a/board/README.md +++ /dev/null
@@ -1,4 +0,0 @@ -OpenTitan Matcha RISC-V Board -================= - -This is provides board support for the Matcha config of OpenTitan. \ No newline at end of file
diff --git a/board/build.rs b/board/build.rs deleted file mode 100644 index ab031c3..0000000 --- a/board/build.rs +++ /dev/null
@@ -1,4 +0,0 @@ -fn main() { - println!("cargo:rerun-if-changed=layout.ld"); - println!("cargo:rerun-if-changed=../../../tock/boards/kernel_layout.ld"); -}
diff --git a/board/src/io.rs b/board/src/io.rs deleted file mode 100644 index 2439aec..0000000 --- a/board/src/io.rs +++ /dev/null
@@ -1,50 +0,0 @@ -use core::fmt::Write; -use core::panic::PanicInfo; -use core::str; -use kernel::debug; -use kernel::debug::IoWrite; -use kernel::hil::gpio; -use kernel::hil::led; - -use crate::CHIP; -use crate::PROCESSES; - -struct Writer {} - -static mut WRITER: Writer = Writer {}; - -impl Write for Writer { - fn write_str(&mut self, s: &str) -> ::core::fmt::Result { - self.write(s.as_bytes()); - Ok(()) - } -} - -impl IoWrite for Writer { - fn write(&mut self, buf: &[u8]) { - unsafe { - matcha::uart::UART0.transmit_sync(buf); - } - } -} - -/// Panic handler. -#[cfg(not(test))] -#[no_mangle] -#[panic_handler] -pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! { - // turn off the non panic leds, just in case - let first_led = &mut led::LedLow::new(&mut matcha::gpio::PORT[7]); - gpio::Pin::make_output(&matcha::gpio::PORT[7]); - - let writer = &mut WRITER; - - debug::panic( - &mut [first_led], - writer, - pi, - &rv32i::support::nop, - &PROCESSES, - &CHIP, - ) -}
diff --git a/board/src/main.rs b/board/src/main.rs deleted file mode 100644 index 9025306..0000000 --- a/board/src/main.rs +++ /dev/null
@@ -1,351 +0,0 @@ -//! Board file for LowRISC OpenTitan Matcha RISC-V development platform. -//! -//! - <https://opentitan.org/> - -#![no_std] -// Disable this attribute when documenting, as a workaround for -// https://github.com/rust-lang/rust/issues/62184. -#![cfg_attr(not(doc), no_main)] -#![feature(const_in_array_repeat_expressions)] - -use matcha_capsules::debug_uart::DebugUart; -use capsules::virtual_alarm::{MuxAlarm, VirtualMuxAlarm}; -use capsules::virtual_hmac::VirtualMuxHmac; -use kernel::capabilities; -use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState}; -use kernel::component::Component; -use kernel::hil; -use kernel::hil::i2c::I2CMaster; -use kernel::hil::time::Alarm; -use kernel::Chip; -use kernel::Platform; -use kernel::{create_capability, debug, static_init}; -use rv32i::csr; - -pub mod io; - -// -// Actual memory for holding the active process structures. Need an empty list -// at least. -static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; 4] = - [None, None, None, None]; - -static mut CHIP: Option< - &'static matcha::chip::Matcha<VirtualMuxAlarm<'static, matcha::timer::RvTimer>>, -> = None; - -// How should the kernel respond when a process faults. -const FAULT_RESPONSE: kernel::procs::FaultResponse = kernel::procs::FaultResponse::Panic; - -/// Dummy buffer that causes the linker to reserve enough space for the stack. -/// Must be at least 16k in debug builds (@aappleby - not sure why, what's so large?) -#[no_mangle] -#[link_section = ".stack_buffer"] -pub static mut STACK_MEMORY: [u8; 0x4000] = [0; 0x4000]; - -/// A structure representing this platform that holds references to all -/// capsules for this platform. We've included an alarm and console. -struct OpenTitan { - led: &'static capsules::led::LED<'static, matcha::gpio::GpioPin<'static>>, - gpio: &'static capsules::gpio::GPIO<'static, matcha::gpio::GpioPin<'static>>, - console: &'static capsules::console::Console<'static>, - alarm: &'static capsules::alarm::AlarmDriver< - 'static, - VirtualMuxAlarm<'static, matcha::timer::RvTimer<'static>>, - >, - hmac: &'static capsules::hmac::HmacDriver< - 'static, - VirtualMuxHmac<'static, lowrisc::hmac::Hmac<'static>, [u8; 32]>, - [u8; 32], - >, - lldb: &'static capsules::low_level_debug::LowLevelDebug< - 'static, - capsules::virtual_uart::UartDevice<'static>, - >, - i2c_master: &'static capsules::i2c_master::I2CMasterDriver<lowrisc::i2c::I2c<'static>>, - debug_uart: &'static DebugUart, - storage_manager: &'static capsules::storage_manager::StorageManager, -} - -/// Mapping of integer syscalls to objects that implement syscalls. -impl Platform for OpenTitan { - fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R - where - F: FnOnce(Option<&dyn kernel::Driver>) -> R, - { - match driver_num { - capsules::led::DRIVER_NUM => f(Some(self.led)), - capsules::hmac::DRIVER_NUM => f(Some(self.hmac)), - capsules::gpio::DRIVER_NUM => f(Some(self.gpio)), - capsules::console::DRIVER_NUM => f(Some(self.console)), - capsules::alarm::DRIVER_NUM => f(Some(self.alarm)), - capsules::low_level_debug::DRIVER_NUM => f(Some(self.lldb)), - capsules::i2c_master::DRIVER_NUM => f(Some(self.i2c_master)), - matcha_capsules::debug_uart::DRIVER_NUM => f(Some(self.debug_uart)), - capsules::storage_manager::DRIVER_NUM => f(Some(self.storage_manager)), - _ => f(None), - } - } -} - - -pub struct MatchaHAL { -} - -impl matcha_capsules::debug_uart::DebugUartHAL for MatchaHAL { - fn send_sync(&self, buf: &[u8], len: usize) { - unsafe { - let tx_busy = 0x4000_0010 as *const u32; - let tx_port = 0x4000_0018 as *mut u32; - for i in 0..len{ - while (tx_busy.read_volatile() & 1) != 0 {} - tx_port.write_volatile(buf[i] as u32); - } - } - } -} - -/// Reset Handler. -/// -/// This function is called from the arch crate after some very basic RISC-V -/// setup. -#[no_mangle] -pub unsafe fn reset_handler() { - // Basic setup of the platform. - rv32i::init_memory(); - // Ibex-specific handler - matcha::chip::configure_trap_handler(); - - // initialize capabilities - let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability); - let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability); - - let main_loop_cap = create_capability!(capabilities::MainLoopCapability); - - let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES)); - - let dynamic_deferred_call_clients = - static_init!([DynamicDeferredCallClientState; 1], Default::default()); - let dynamic_deferred_caller = static_init!( - DynamicDeferredCall, - DynamicDeferredCall::new(dynamic_deferred_call_clients) - ); - DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); - - // Configure kernel debug gpios as early as possible - kernel::debug::assign_gpios( - Some(&matcha::gpio::PORT[7]), // First LED - None, - None, - ); - - // Create a shared UART channel for the console and for kernel debug. - let uart_mux = components::console::UartMuxComponent::new( - &matcha::uart::UART0, - matcha::uart::UART0_BAUDRATE, - dynamic_deferred_caller, - ) - .finalize(()); - - // LEDs - // Start with half on and half off - let led = components::led::LedsComponent::new(components::led_component_helper!( - matcha::gpio::GpioPin, - ( - &matcha::gpio::PORT[8], - kernel::hil::gpio::ActivationMode::ActiveHigh - ), - ( - &matcha::gpio::PORT[9], - kernel::hil::gpio::ActivationMode::ActiveHigh - ), - ( - &matcha::gpio::PORT[10], - kernel::hil::gpio::ActivationMode::ActiveHigh - ), - ( - &matcha::gpio::PORT[11], - kernel::hil::gpio::ActivationMode::ActiveHigh - ), - ( - &matcha::gpio::PORT[12], - kernel::hil::gpio::ActivationMode::ActiveHigh - ), - ( - &matcha::gpio::PORT[13], - kernel::hil::gpio::ActivationMode::ActiveHigh - ), - ( - &matcha::gpio::PORT[14], - kernel::hil::gpio::ActivationMode::ActiveHigh - ), - ( - &matcha::gpio::PORT[15], - kernel::hil::gpio::ActivationMode::ActiveHigh - ) - )) - .finalize(components::led_component_buf!(matcha::gpio::GpioPin)); - - let gpio = components::gpio::GpioComponent::new( - board_kernel, - components::gpio_component_helper!( - matcha::gpio::GpioPin, - 0 => &matcha::gpio::PORT[0], - 1 => &matcha::gpio::PORT[1], - 2 => &matcha::gpio::PORT[2], - 3 => &matcha::gpio::PORT[3], - 4 => &matcha::gpio::PORT[4], - 5 => &matcha::gpio::PORT[5], - 6 => &matcha::gpio::PORT[6], - 7 => &matcha::gpio::PORT[15] - ), - ) - .finalize(components::gpio_component_buf!(matcha::gpio::GpioPin)); - - let alarm = &matcha::timer::TIMER; - alarm.setup(); - - // Create a shared virtualization mux layer on top of a single hardware - // alarm. - let mux_alarm = static_init!( - MuxAlarm<'static, matcha::timer::RvTimer>, - MuxAlarm::new(alarm) - ); - hil::time::Alarm::set_alarm_client(&matcha::timer::TIMER, mux_alarm); - - // Alarm - let virtual_alarm_user = static_init!( - VirtualMuxAlarm<'static, matcha::timer::RvTimer>, - VirtualMuxAlarm::new(mux_alarm) - ); - let scheduler_timer_virtual_alarm = static_init!( - VirtualMuxAlarm<'static, matcha::timer::RvTimer>, - VirtualMuxAlarm::new(mux_alarm) - ); - let alarm = static_init!( - capsules::alarm::AlarmDriver<'static, VirtualMuxAlarm<'static, matcha::timer::RvTimer>>, - capsules::alarm::AlarmDriver::new( - virtual_alarm_user, - board_kernel.create_grant(&memory_allocation_cap) - ) - ); - hil::time::Alarm::set_alarm_client(virtual_alarm_user, alarm); - - let chip = static_init!( - matcha::chip::Matcha<VirtualMuxAlarm<'static, matcha::timer::RvTimer>>, - matcha::chip::Matcha::new(scheduler_timer_virtual_alarm) - ); - scheduler_timer_virtual_alarm.set_alarm_client(chip.scheduler_timer()); - CHIP = Some(chip); - - // Need to enable all interrupts for Tock Kernel - chip.enable_plic_interrupts(); - // enable interrupts globally - csr::CSR - .mie - .modify(csr::mie::mie::msoft::SET + csr::mie::mie::mtimer::SET + csr::mie::mie::mext::SET); - csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET); - - // Setup the console. - let console = components::console::ConsoleComponent::new(board_kernel, uart_mux).finalize(()); - // Create the debugger object that handles calls to `debug!()`. - components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(()); - - let lldb = components::lldb::LowLevelDebugComponent::new(board_kernel, uart_mux).finalize(()); - - let hmac_data_buffer = static_init!([u8; 64], [0; 64]); - let hmac_dest_buffer = static_init!([u8; 32], [0; 32]); - - let mux_hmac = components::hmac::HmacMuxComponent::new(&matcha::hmac::HMAC).finalize( - components::hmac_mux_component_helper!(lowrisc::hmac::Hmac, [u8; 32]), - ); - - let hmac = components::hmac::HmacComponent::new( - board_kernel, - &mux_hmac, - hmac_data_buffer, - hmac_dest_buffer, - ) - .finalize(components::hmac_component_helper!( - lowrisc::hmac::Hmac, - [u8; 32] - )); - - let i2c_master = static_init!( - capsules::i2c_master::I2CMasterDriver<lowrisc::i2c::I2c<'static>>, - capsules::i2c_master::I2CMasterDriver::new( - &matcha::i2c::I2C, - &mut capsules::i2c_master::BUF, - board_kernel.create_grant(&memory_allocation_cap) - ) - ); - - matcha::i2c::I2C.set_master_client(i2c_master); - - let matcha_hal = static_init!( - MatchaHAL, - MatchaHAL{} - ); - - let debug_uart = static_init!( - DebugUart, - DebugUart { - hal: matcha_hal, - app_data_grant: board_kernel.create_grant(&memory_allocation_cap) - } - ); - - /// These symbols are defined in the linker script. - extern "C" { - /// Beginning of the ROM region containing app images. - static _sapps: u8; - /// End of the ROM region containing app images. - static _eapps: u8; - /// Beginning of the RAM region for app memory. - static mut _sappmem: u8; - /// End of the RAM region for app memory. - static _eappmem: u8; - } - - let storage_manager = static_init!( - capsules::storage_manager::StorageManager, - capsules::storage_manager::StorageManager::new(board_kernel.create_grant(&memory_allocation_cap)) - ); - - let opentitan = OpenTitan { - gpio: gpio, - led: led, - console: console, - alarm: alarm, - hmac, - lldb: lldb, - i2c_master, - debug_uart: debug_uart, - storage_manager: storage_manager, - }; - - kernel::procs::load_processes( - board_kernel, - chip, - core::slice::from_raw_parts( - &_sapps as *const u8, - &_eapps as *const u8 as usize - &_sapps as *const u8 as usize, - ), - core::slice::from_raw_parts_mut( - &mut _sappmem as *mut u8, - &_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize, - ), - &mut PROCESSES, - FAULT_RESPONSE, - &process_mgmt_cap, - ) - .unwrap_or_else(|err| { - debug!("Error loading processes!"); - debug!("{:?}", err); - }); - debug!("OpenTitan initialisation complete. Entering main loop"); - debug!("Woo Tock!"); - - let scheduler = components::sched::priority::PriorityComponent::new(board_kernel).finalize(()); - board_kernel.kernel_loop(&opentitan, chip, None, scheduler, &main_loop_cap); -}
diff --git a/capsules/Cargo.toml b/capsules/Cargo.toml index 39159ad..65f7cf5 100644 --- a/capsules/Cargo.toml +++ b/capsules/Cargo.toml
@@ -1,10 +1,10 @@ [package] -name = "matcha-capsules" +name = "matcha_capsules" version = "0.1.0" edition = "2018" [dependencies] -kernel = { path = "../../tock/kernel" } -enum_primitive = { path = "../../tock/libraries/enum_primitive" } -blob_fs = { path = "../blob_fs" } - +kernel = { path = "../../tock/kernel" } +matcha_hal = { path = "../hal" } +matcha_utils = { path = "../utils" } +matcha_config = { path = "../config" } \ No newline at end of file
diff --git a/capsules/rust-toolchain b/capsules/rust-toolchain deleted file mode 100644 index b18a3f3..0000000 --- a/capsules/rust-toolchain +++ /dev/null
@@ -1 +0,0 @@ -nightly-2020-06-03
diff --git a/capsules/src/debug_uart.rs b/capsules/src/debug_uart.rs index 1d6fe4c..f1e18f3 100644 --- a/capsules/src/debug_uart.rs +++ b/capsules/src/debug_uart.rs
@@ -6,19 +6,6 @@ //! which dumps data from an allow'ed buffer directly to a memory-mapped UART //! peripheral. //! -//! Instantiation: -//! let debug_uart = static_init!( -//! DebugUart, -//! DebugUart { -//! tx_busy: StaticRef::new(TX_BUSY_ADDR as *const ReadOnly<u32>), -//! tx_port: StaticRef::new(TX_PORT_ADDR as *const WriteOnly<u32>), -//! app_data_grant: board_kernel.create_grant(&memory_allocation_cap) -//! } -//! ); -//! -//! where TX_BUSY_ADDR is a register whose low bit is 1 if the UART's fifo is -//! full and TX_PORT_ADDR is the register we write bytes to. -//! //! Usage - send buffer directly to UART: //! let driver_num = capsules::debug_uart::DRIVER_NUM; //! let allow = syscalls::allow(driver_num, 0, &mut buffer); @@ -27,24 +14,16 @@ use kernel::{AppId, AppSlice, Callback, Driver, Grant, ReturnCode, Shared}; -pub const DRIVER_NUM: usize = 0x00009 as usize; - -pub trait DebugUartHAL { - fn send_sync(&self, buf: &[u8], len: usize); -} - #[derive(Default)] pub struct AppData { pub buffer: Option<AppSlice<Shared, u8>>, } -pub struct DebugUart { - pub hal: &'static dyn DebugUartHAL, +pub struct DebugUartCapsule { pub app_data_grant: Grant<AppData>, } -impl Driver for DebugUart { - +impl Driver for DebugUartCapsule { fn subscribe(&self, _: usize, _: Option<Callback>, _: AppId) -> ReturnCode { ReturnCode::EINVAL } @@ -56,7 +35,7 @@ let _ = self.app_data_grant.enter(app_id, |app_data, _| { if let Some(buf) = &app_data.buffer { - self.hal.send_sync(buf.as_ref(), r2); + matcha_hal::debug_uart::send_sync(buf.as_ref(), r2); } }); return ReturnCode::SUCCESS;
diff --git a/capsules/src/elf_loader.rs b/capsules/src/elf_loader.rs new file mode 100644 index 0000000..84d9fc3 --- /dev/null +++ b/capsules/src/elf_loader.rs
@@ -0,0 +1,27 @@ +//! Trivial Shodan elf loader capsule + +use kernel::{AppId, AppSlice, Callback, Driver, ReturnCode, Shared}; +use matcha_hal::dprintf; + +pub struct ElfLoaderCapsule {} + +impl Driver for ElfLoaderCapsule { + fn subscribe(&self, _: usize, _: Option<Callback>, _: AppId) -> ReturnCode { + return ReturnCode::EINVAL; + } + + fn command(&self, minor_num: usize, _r2: usize, _r3: usize, _app_id: AppId) -> ReturnCode { + dprintf!("ElfLoaderCapsule::command()\n"); + + if minor_num == matcha_config::CMD_ELF_LOADER_BOOT_SEL4 { + matcha_utils::load_sel4(); + return ReturnCode::SUCCESS; + } + + return ReturnCode::EINVAL; + } + + fn allow(&self, _: AppId, _: usize, _: Option<AppSlice<Shared, u8>>) -> ReturnCode { + return ReturnCode::EINVAL; + } +}
diff --git a/capsules/src/lib.rs b/capsules/src/lib.rs index 78117c5..bd4ff3f 100644 --- a/capsules/src/lib.rs +++ b/capsules/src/lib.rs
@@ -1,5 +1,7 @@ -#![feature(const_fn)] #![forbid(unsafe_code)] #![no_std] pub mod debug_uart; +pub mod elf_loader; +pub mod mailbox; +pub mod storage_manager;
diff --git a/capsules/src/mailbox.rs b/capsules/src/mailbox.rs new file mode 100644 index 0000000..4f9676f --- /dev/null +++ b/capsules/src/mailbox.rs
@@ -0,0 +1,29 @@ +//! Stub Shodan mailbox driver capsule. + +use kernel::{AppId, AppSlice, Callback, Driver, Grant, ReturnCode, Shared}; + +#[derive(Default)] +pub struct AppData { + pub buffer: Option<AppSlice<Shared, u8>>, +} + +pub struct Mailbox { + pub app_data_grant: Grant<AppData>, +} + +impl Driver for Mailbox { + fn subscribe(&self, _: usize, _: Option<Callback>, _: AppId) -> ReturnCode { + ReturnCode::EINVAL + } + + fn command(&self, _minor_num: usize, _r2: usize, _r3: usize, _app_id: AppId) -> ReturnCode { + return ReturnCode::EINVAL; + } + + fn allow(&self, app_id: AppId, _: usize, slice: Option<AppSlice<Shared, u8>>) -> ReturnCode { + let _ = self.app_data_grant.enter(app_id, |app_data, _| { + app_data.buffer = slice; + }); + return ReturnCode::SUCCESS; + } +}
diff --git a/capsules/src/storage_manager.rs b/capsules/src/storage_manager.rs new file mode 100644 index 0000000..ab26383 --- /dev/null +++ b/capsules/src/storage_manager.rs
@@ -0,0 +1,123 @@ +//! Stub StorageManager capsule that doesn't do anything yet. + +use kernel::{AppId, AppSlice, Callback, Driver, Grant, ReturnCode, Shared}; +use matcha_hal::dprintf; + +#[derive(Default)] +pub struct AppData { + pub callback: Option<Callback>, + pub buffer: Option<AppSlice<Shared, u8>>, + pub minor_num: usize, + pub arg2: usize, + pub arg3: usize, +} + +pub struct StorageManagerCapsule { + app_data_grant: Grant<AppData>, +} + +impl StorageManagerCapsule { + pub fn new(app_data_grant: Grant<AppData>) -> Self { + dprintf!("StorageManager::new()"); + return StorageManagerCapsule { + app_data_grant: app_data_grant, + }; + } + + pub fn handle_command( + &self, + app_data: &mut AppData, + minor_num: usize, + arg2: usize, + arg3: usize, + ) -> ReturnCode { + dprintf!( + "StorageManagerCapsule::handle_command({}, {}, {})", + minor_num, + arg2, + arg3 + ); + app_data.minor_num = minor_num; + app_data.arg2 = arg2; + app_data.arg3 = arg3; + match minor_num { + 0 => ReturnCode::SUCCESS, + 1 => { + if let Some(mut callback) = app_data.callback { + dprintf!("StorageManagerCapsule::handle_command : Calling callback!"); + callback.schedule(1, 2, 3); + app_data.callback = Some(callback); + ReturnCode::SUCCESS + } else { + dprintf!("StorageManagerCapsule::handle_command : No callback!"); + ReturnCode::EINVAL + } + } + _ => ReturnCode::EINVAL, + } + } + + pub fn handle_subscribe( + &self, + app_data: &mut AppData, + minor_num: usize, + callback: Option<Callback>, + ) -> ReturnCode { + dprintf!("StorageManagerCapsule::handle_subscribe({})", minor_num); + if callback.is_some() { + dprintf!("StorageManagerCapsule::handle_subscribe got Some callback"); + } else { + dprintf!("StorageManagerCapsule::handle_subscribe got None callback"); + } + app_data.callback = callback; + return ReturnCode::SUCCESS; + } + + pub fn handle_allow( + &self, + app_data: &mut AppData, + _minor_num: usize, + slice: Option<AppSlice<Shared, u8>>, + ) -> ReturnCode { + if let Some(slice) = slice { + dprintf!("StorageManagerCapsule::handle_allow({})", slice.len()); + app_data.buffer = Some(slice); + } else { + dprintf!("StorageManagerCapsule::handle_allow(None)"); + } + return ReturnCode::SUCCESS; + } +} + +/// Driver impl just enters the app_data grant and delegates to StorageManagerCapsule. + +impl Driver for StorageManagerCapsule { + fn subscribe(&self, minor_num: usize, callback: Option<Callback>, app_id: AppId) -> ReturnCode { + self.app_data_grant + .enter(app_id, |app_data, _| { + self.handle_subscribe(app_data, minor_num, callback) + }) + .unwrap_or_else(|err| err.into()) + } + + fn command(&self, minor_num: usize, r2: usize, r3: usize, app_id: AppId) -> ReturnCode { + self.app_data_grant + .enter(app_id, |app_data, _| { + self.handle_command(app_data, minor_num, r2, r3) + }) + .unwrap_or_else(|err| err.into()) + } + + fn allow( + &self, + app_id: AppId, + minor_num: usize, + slice: Option<AppSlice<Shared, u8>>, + ) -> ReturnCode { + self.app_data_grant + .enter(app_id, |app_data, _| { + self.handle_allow(app_data, minor_num, slice) + }) + .unwrap_or_else(|err| err.into()) + } +}
diff --git a/chip/Cargo.toml b/chip/Cargo.toml deleted file mode 100644 index b55a931..0000000 --- a/chip/Cargo.toml +++ /dev/null
@@ -1,18 +0,0 @@ -[package] -name = "matcha" -version = "0.1.0" -authors = ["Tock Project Developers <tock-dev@googlegroups.com>"] -edition = "2018" - -[features] -# Compiling this crate requires enabling one of these features, otherwise -# the default will be chosen. -config_fpga_nexysvideo = ["config_disable_default"] -config_sim_verilator = ["config_disable_default"] -config_disable_default = [] - -[dependencies] -lowrisc = { path = "../../tock/chips/lowrisc" } -rv32i = { path = "../../tock/arch/rv32i" } -kernel = { path = "../../tock/kernel" } -
diff --git a/chip/README.md b/chip/README.md deleted file mode 100644 index b5b6a4c..0000000 --- a/chip/README.md +++ /dev/null
@@ -1,4 +0,0 @@ -OpenTitan Matcha SoC -======================= -Matcha is the dual-hart OpenTitan system. At the center of the Matcha are two -Ibex RISC-V compliant processors. \ No newline at end of file
diff --git a/chip/src/aes.rs b/chip/src/aes.rs deleted file mode 100644 index 7ab4bf9..0000000 --- a/chip/src/aes.rs +++ /dev/null
@@ -1,350 +0,0 @@ -//! Support for the AES hardware block on OpenTitan -//! -//! https://docs.opentitan.org/hw/ip/aes/doc/ - -use kernel::common::cells::{OptionalCell, TakeCell}; -use kernel::common::registers::{ - register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly, -}; -use kernel::common::StaticRef; -use kernel::debug; -use kernel::hil; -use kernel::hil::symmetric_encryption; -use kernel::hil::symmetric_encryption::{AES128_BLOCK_SIZE, AES128_KEY_SIZE}; -use kernel::ReturnCode; - -const MAX_LENGTH: usize = 128; - -register_structs! { - pub AesRegisters { - (0x00 => key0: WriteOnly<u32>), - (0x04 => key1: WriteOnly<u32>), - (0x08 => key2: WriteOnly<u32>), - (0x0c => key3: WriteOnly<u32>), - (0x10 => key4: WriteOnly<u32>), - (0x14 => key5: WriteOnly<u32>), - (0x18 => key6: WriteOnly<u32>), - (0x1c => key7: WriteOnly<u32>), - (0x20 => data_in0: WriteOnly<u32>), - (0x24 => data_in1: WriteOnly<u32>), - (0x28 => data_in2: WriteOnly<u32>), - (0x2c => data_in3: WriteOnly<u32>), - (0x30 => data_out0: ReadOnly<u32>), - (0x34 => data_out1: ReadOnly<u32>), - (0x38 => data_out2: ReadOnly<u32>), - (0x3c => data_out3: ReadOnly<u32>), - (0x40 => ctrl: ReadWrite<u32, CTRL::Register>), - (0x44 => trigger: WriteOnly<u32, TRIGGER::Register>), - (0x48 => status: ReadOnly<u32, STATUS::Register>), - (0x4c => @END), - } -} - -register_bitfields![u32, - CTRL [ - OPERATION OFFSET(0) NUMBITS(1) [ - Encrypting = 0, - Decrypting = 1 - ], - KEY_LEN OFFSET(1) NUMBITS(3) [ - Key128 = 1, - Key192 = 2, - Key256 = 4 - ], - MANUAL_OPERATION OFFSET(4) NUMBITS(1) [] - ], - TRIGGER [ - START OFFSET(0) NUMBITS(1) [], - KEY_CLEAR OFFSET(1) NUMBITS(1) [], - DATA_IN_CLEAR OFFSET(2) NUMBITS(1) [], - DATA_OUT_CLEAR OFFSET(3) NUMBITS(1) [] - ], - STATUS [ - IDLE 0, - STALL 1, - OUTPUT_VALID 2, - INPUT_READY 3 - ] -]; - -// https://docs.opentitan.org/hw/top_earlgrey/doc/ -const AES_BASE: StaticRef<AesRegisters> = - unsafe { StaticRef::new(0x41100000 as *const AesRegisters) }; - -pub struct Aes<'a> { - registers: StaticRef<AesRegisters>, - - client: OptionalCell<&'a dyn hil::symmetric_encryption::Client<'a>>, - source: TakeCell<'a, [u8]>, - dest: TakeCell<'a, [u8]>, -} - -impl<'a> Aes<'a> { - const fn new() -> Aes<'a> { - Aes { - registers: AES_BASE, - client: OptionalCell::empty(), - source: TakeCell::empty(), - dest: TakeCell::empty(), - } - } - - fn clear(&self) { - let regs = self.registers; - regs.trigger.write( - TRIGGER::KEY_CLEAR::SET + TRIGGER::DATA_IN_CLEAR::SET + TRIGGER::DATA_OUT_CLEAR::SET, - ); - } - - fn configure(&self, encrypting: bool) { - let regs = self.registers; - let e = if encrypting { - CTRL::OPERATION::Encrypting - } else { - CTRL::OPERATION::Decrypting - }; - // Set this in manual mode for the moment since automatic block mode - // does not appear to be working - - regs.ctrl - .write(e + CTRL::KEY_LEN::Key128 + CTRL::MANUAL_OPERATION::SET); - } - - fn idle(&self) -> bool { - let regs = self.registers; - regs.status.is_set(STATUS::IDLE) - } - - fn input_ready(&self) -> bool { - let regs = self.registers; - regs.status.is_set(STATUS::INPUT_READY) - } - - fn output_valid(&self) -> bool { - let regs = self.registers; - regs.status.is_set(STATUS::OUTPUT_VALID) - } - - fn trigger(&self) { - let regs = self.registers; - regs.trigger.write(TRIGGER::START::SET); - } - - fn read_block(&self, blocknum: usize) { - let regs = self.registers; - let blocknum = blocknum * AES128_BLOCK_SIZE; - - loop { - if self.output_valid() { - break; - } - } - - self.dest.map_or_else( - || { - debug!("Called read_block() with no data"); - }, - |dest| { - for i in 0..4 { - // we work off an array of u8 so we need to assemble those - // back into a u32 - let mut v = 0; - match i { - 0 => v = regs.data_out0.get(), - 1 => v = regs.data_out1.get(), - 2 => v = regs.data_out2.get(), - 3 => v = regs.data_out3.get(), - _ => {} - } - dest[blocknum + (i * 4) + 0] = (v >> 0) as u8; - dest[blocknum + (i * 4) + 1] = (v >> 8) as u8; - dest[blocknum + (i * 4) + 2] = (v >> 16) as u8; - dest[blocknum + (i * 4) + 3] = (v >> 24) as u8; - } - }, - ); - } - - fn write_block(&self, blocknum: usize) { - let regs = self.registers; - let blocknum = blocknum * AES128_BLOCK_SIZE; - - loop { - if self.input_ready() { - break; - } - } - - self.source.map_or_else( - || { - // This is the case that dest = source - self.dest.map_or_else( - || { - debug!("Called write_block() with no data"); - }, - |dest| { - for i in 0..4 { - // we work off an array of u8 so we need to - // assemble those back into a u32 - let mut v = dest[blocknum + (i * 4) + 0] as usize; - v |= (dest[blocknum + (i * 4) + 1] as usize) << 8; - v |= (dest[blocknum + (i * 4) + 2] as usize) << 16; - v |= (dest[blocknum + (i * 4) + 3] as usize) << 24; - match i { - 0 => regs.data_in0.set(v as u32), - 1 => regs.data_in1.set(v as u32), - 2 => regs.data_in2.set(v as u32), - 3 => regs.data_in3.set(v as u32), - _ => {} - } - } - }, - ) - }, - |source| { - for i in 0..4 { - // we work off an array of u8 so we need to assemble - // those back into a u32 - let mut v = source[blocknum + (i * 4) + 0] as usize; - v |= (source[blocknum + (i * 4) + 1] as usize) << 8; - v |= (source[blocknum + (i * 4) + 2] as usize) << 16; - v |= (source[blocknum + (i * 4) + 3] as usize) << 24; - match i { - 0 => regs.data_in0.set(v as u32), - 1 => regs.data_in1.set(v as u32), - 2 => regs.data_in2.set(v as u32), - 3 => regs.data_in3.set(v as u32), - _ => {} - } - } - }, - ); - } - - fn set_key(&self, key: &[u8]) -> ReturnCode { - let regs = self.registers; - - loop { - if self.idle() { - break; - } - } - - if key.len() != AES128_KEY_SIZE { - return ReturnCode::EINVAL; - } - - for i in 0..4 { - let mut k = key[i * 4 + 0] as usize; - k |= (key[i * 4 + 1] as usize) << 8; - k |= (key[i * 4 + 2] as usize) << 16; - k |= (key[i * 4 + 3] as usize) << 24; - match i { - 0 => regs.key0.set(k as u32), - 1 => regs.key1.set(k as u32), - 2 => regs.key2.set(k as u32), - 3 => regs.key3.set(k as u32), - _ => {} - } - } - - // We must write the rest of the registers as well - regs.key4.set(0); - regs.key5.set(0); - regs.key6.set(0); - regs.key7.set(0); - ReturnCode::SUCCESS - } - - fn do_crypt(&self, start_index: usize, stop_index: usize, wr_start_index: usize) { - // convert our indicies into the array into block numbers - // start and end are pointer for reading - // write is the pointer for writing - // Note that depending on whether or not we have separate source - // and dest buffers the write and read pointers may index into - // different arrays. - let start_block = start_index / AES128_BLOCK_SIZE; - let end_block = stop_index / AES128_BLOCK_SIZE; - let mut write_block = wr_start_index / AES128_BLOCK_SIZE; - for i in start_block..end_block { - self.write_block(write_block); - self.trigger(); - self.read_block(i); - write_block = write_block + 1; - } - } -} - -impl<'a> hil::symmetric_encryption::AES128<'a> for Aes<'a> { - fn enable(&self) { - self.configure(true); - } - - fn disable(&self) { - self.clear(); - } - - fn set_client(&'a self, client: &'a dyn symmetric_encryption::Client<'a>) { - self.client.set(client); - } - - fn set_iv(&self, _iv: &[u8]) -> ReturnCode { - // nothing because this is ECB - ReturnCode::SUCCESS - } - - fn start_message(&self) {} - - fn set_key(&self, key: &[u8]) -> ReturnCode { - self.set_key(key) - } - - fn crypt( - &'a self, - source: Option<&'a mut [u8]>, - dest: &'a mut [u8], - start_index: usize, - stop_index: usize, - ) -> Option<(ReturnCode, Option<&'a mut [u8]>, &'a mut [u8])> { - match stop_index.checked_sub(start_index) { - None => return Some((ReturnCode::EINVAL, source, dest)), - Some(s) => { - if s > MAX_LENGTH { - return Some((ReturnCode::EINVAL, source, dest)); - } - if s % AES128_BLOCK_SIZE != 0 { - return Some((ReturnCode::EINVAL, source, dest)); - } - } - } - self.dest.replace(dest); - // The crypt API has two cases: separate source and destination - // buffers and a single source buffer. - // If we don't have a separate source buffer, we overwrite the - // destination with the data. This means that read index and write - // index match - // If we do have a separate source buffer, we start writing from - // 0 and the read index is separate. - match source { - None => { - self.do_crypt(start_index, stop_index, start_index); - } - Some(src) => { - self.source.replace(src); - self.do_crypt(start_index, stop_index, 0); - } - } - self.client.map(|client| { - client.crypt_done(self.source.take(), self.dest.take().unwrap()); - }); - None - } -} - -pub static mut AES: Aes<'static> = Aes::new(); - -impl kernel::hil::symmetric_encryption::AES128ECB for Aes<'_> { - fn set_mode_aes128ecb(&self, encrypting: bool) { - self.configure(encrypting); - } -}
diff --git a/chip/src/chip_config.rs b/chip/src/chip_config.rs deleted file mode 100644 index c4ec321..0000000 --- a/chip/src/chip_config.rs +++ /dev/null
@@ -1,34 +0,0 @@ -//! Chip specific configuration. -//! -//! This file includes configuration values for different implementations and -//! uses of the same matcha chip. For example, running the chip on an FPGA -//! requires different parameters from running it in a verilog simulator. -//! Additionally, chips on different platforms can be used differently, so this -//! also permits changing values like the UART baud rate to enable better -//! debugging on platforms that can support it. -//! -//! The configuration used is selected via Cargo features specified when the -//! board is compiled. - -/// Matcha configuration based on the target device. -pub struct Config<'a> { - /// Identifier for the platform. This is useful for debugging to confirm the - /// correct configuration of the chip is being used. - pub name: &'a str, - /// The clock speed of the CPU in Hz. - pub cpu_freq: u32, - /// The clock speed of the peripherals in Hz. - pub peripheral_freq: u32, - /// The baud rate for UART. This allows for a version of the chip that can - /// support a faster baud rate to use it to help with debugging. - pub uart_baudrate: u32, -} - -/// Config for running Matcha in a verilog simulator. -#[cfg(feature = "config_sim_verilator")] -pub const CONFIG: Config = Config { - name: "sim_verilator", - cpu_freq: 500_000, - peripheral_freq: 125_000, - uart_baudrate: 9600, -};
diff --git a/chip/src/gpio.rs b/chip/src/gpio.rs deleted file mode 100644 index 03adf98..0000000 --- a/chip/src/gpio.rs +++ /dev/null
@@ -1,69 +0,0 @@ -//! GPIO instantiation. - -use core::ops::{Index, IndexMut}; - -use kernel::common::StaticRef; -pub use lowrisc::gpio::GpioPin; -use lowrisc::gpio::{pins, GpioRegisters}; -use lowrisc::padctrl::PadCtrlRegisters; - -const PADCTRL_BASE: StaticRef<PadCtrlRegisters> = - unsafe { StaticRef::new(0x4046_0000 as *const PadCtrlRegisters) }; - -const GPIO0_BASE: StaticRef<GpioRegisters> = - unsafe { StaticRef::new(0x4004_0000 as *const GpioRegisters) }; - -pub struct Port<'a> { - pins: [GpioPin<'a>; 32], -} - -impl<'a> Index<usize> for Port<'a> { - type Output = GpioPin<'a>; - - fn index(&self, index: usize) -> &GpioPin<'a> { - &self.pins[index] - } -} - -impl<'a> IndexMut<usize> for Port<'a> { - fn index_mut(&mut self, index: usize) -> &mut GpioPin<'a> { - &mut self.pins[index] - } -} - -pub static mut PORT: Port = Port { - pins: [ - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin0), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin1), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin2), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin3), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin4), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin5), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin6), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin7), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin8), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin9), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin10), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin11), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin12), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin13), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin14), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin15), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin16), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin17), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin18), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin19), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin20), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin21), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin22), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin23), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin24), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin25), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin26), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin27), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin28), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin29), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin30), - GpioPin::new(GPIO0_BASE, PADCTRL_BASE, pins::pin31), - ], -};
diff --git a/chip/src/hmac.rs b/chip/src/hmac.rs deleted file mode 100644 index 182ed53..0000000 --- a/chip/src/hmac.rs +++ /dev/null
@@ -1,7 +0,0 @@ -use kernel::common::StaticRef; -use lowrisc::hmac::{Hmac, HmacRegisters}; - -pub static mut HMAC: Hmac = Hmac::new(HMAC0_BASE); - -const HMAC0_BASE: StaticRef<HmacRegisters> = - unsafe { StaticRef::new(0x4111_0000 as *const HmacRegisters) };
diff --git a/chip/src/i2c.rs b/chip/src/i2c.rs deleted file mode 100644 index 4cc7332..0000000 --- a/chip/src/i2c.rs +++ /dev/null
@@ -1,9 +0,0 @@ -use crate::chip_config::CONFIG; -use kernel::common::StaticRef; -use lowrisc::i2c::{I2c, I2cRegisters}; - -pub static mut I2C: I2c = I2c::new(I2C_BASE, (1 / CONFIG.cpu_freq) * 1000 * 1000); - -// This is a placeholder address as the I2C MMIO interface isn't avaliable yet -const I2C_BASE: StaticRef<I2cRegisters> = - unsafe { StaticRef::new(0x4008_0000 as *const I2cRegisters) };
diff --git a/chip/src/interrupts.rs b/chip/src/interrupts.rs deleted file mode 100644 index d503127..0000000 --- a/chip/src/interrupts.rs +++ /dev/null
@@ -1,210 +0,0 @@ -//! Named interrupts for the Matcha chip. - -#![allow(dead_code)] - -pub const PWRMGRWAKEUP: u32 = 0x50; - -pub const NO_INTERRUPT: u32 = 0; - -pub const UART0_TX_WATERMARK: u32 = 1; -pub const UART0_RX_WATERMARK: u32 = 2; -pub const UART0_TX_EMPTY: u32 = 3; -pub const UART0_RX_OVERFLOW: u32 = 4; -pub const UART0_RX_FRAME_ERR: u32 = 5; -pub const UART0_RX_BREAK_ERR: u32 = 6; -pub const UART0_RX_TIMEOUT: u32 = 7; -pub const UART0_RX_PARITY_ERR: u32 = 8; - -pub const UART1_TX_WATERMARK: u32 = 9; -pub const UART1_RX_WATERMARK: u32 = 10; -pub const UART1_TX_EMPTY: u32 = 11; -pub const UART1_RX_OVERFLOW: u32 = 12; -pub const UART1_RX_FRAME_ERR: u32 = 13; -pub const UART1_RX_BREAK_ERR: u32 = 14; -pub const UART1_RX_TIMEOUT: u32 = 15; -pub const UART1_RX_PARITY_ERR: u32 = 16; - -pub const UART2_TX_WATERMARK: u32 = 17; -pub const UART2_RX_WATERMARK: u32 = 18; -pub const UART2_TX_EMPTY: u32 = 19; -pub const UART2_RX_OVERFLOW: u32 = 20; -pub const UART2_RX_FRAME_ERR: u32 = 21; -pub const UART2_RX_BREAK_ERR: u32 = 22; -pub const UART2_RX_TIMEOUT: u32 = 23; -pub const UART2_RX_PARITY_ERR: u32 = 24; - -pub const UART3_TX_WATERMARK: u32 = 25; -pub const UART3_RX_WATERMARK: u32 = 26; -pub const UART3_TX_EMPTY: u32 = 27; -pub const UART3_RX_OVERFLOW: u32 = 28; -pub const UART3_RX_FRAME_ERR: u32 = 29; -pub const UART3_RX_BREAK_ERR: u32 = 30; -pub const UART3_RX_TIMEOUT: u32 = 31; -pub const UART3_RX_PARITY_ERR: u32 = 32; - -pub const GPIO_PIN0: u32 = 33; -pub const GPIO_PIN1: u32 = 34; -pub const GPIO_PIN2: u32 = 35; -pub const GPIO_PIN3: u32 = 36; -pub const GPIO_PIN4: u32 = 37; -pub const GPIO_PIN5: u32 = 38; -pub const GPIO_PIN6: u32 = 39; -pub const GPIO_PIN7: u32 = 40; -pub const GPIO_PIN8: u32 = 41; -pub const GPIO_PIN9: u32 = 42; -pub const GPIO_PIN10: u32 = 43; -pub const GPIO_PIN11: u32 = 44; -pub const GPIO_PIN12: u32 = 45; -pub const GPIO_PIN13: u32 = 46; -pub const GPIO_PIN14: u32 = 47; -pub const GPIO_PIN15: u32 = 48; -pub const GPIO_PIN16: u32 = 49; -pub const GPIO_PIN17: u32 = 50; -pub const GPIO_PIN18: u32 = 51; -pub const GPIO_PIN19: u32 = 52; -pub const GPIO_PIN20: u32 = 53; -pub const GPIO_PIN21: u32 = 54; -pub const GPIO_PIN22: u32 = 55; -pub const GPIO_PIN23: u32 = 56; -pub const GPIO_PIN24: u32 = 57; -pub const GPIO_PIN25: u32 = 58; -pub const GPIO_PIN26: u32 = 59; -pub const GPIO_PIN27: u32 = 60; -pub const GPIO_PIN28: u32 = 61; -pub const GPIO_PIN29: u32 = 62; -pub const GPIO_PIN30: u32 = 63; -pub const GPIO_PIN31: u32 = 64; - -pub const SPI_DEVICE_RXF: u32 = 65; -pub const SPI_DEVICE_RXLVL: u32 = 66; -pub const SPI_DEVICE_TXLVL: u32 = 67; -pub const SPI_DEVICE_RXERR: u32 = 68; -pub const SPI_DEVICE_RXOVERFLOW: u32 = 69; -pub const SPI_DEVICE_TXUNDERFLOW: u32 = 70; - - -pub const SPI_HOST0_ERROR: u32 = 71; -pub const SPI_HOST0_SPIEVENT: u32 = 72; -pub const SPI_HOST1_ERROR: u32 = 73; -pub const SPI_HOST1_SPIEVENT: u32 = 74; - -pub const I2C0_FMT_WATERMARK: u32 = 75; -pub const I2C0_RX_WATERMARK: u32 = 76; -pub const I2C0_FMT_OVERFLOW: u32 = 77; -pub const I2C0_RX_OVERFLOW: u32 = 78; -pub const I2C0_NAK: u32 = 79; -pub const I2C0_SCL_INTERFERENCE: u32 = 80; -pub const I2C0_SDA_INTERFERENCE: u32 = 81; -pub const I2C0_STRETCH_TIMEOUT: u32 = 82; -pub const I2C0_SDA_UNSTABLE: u32 = 83; -pub const I2C0_TRANS_COMPLETE: u32 = 84; -pub const I2C0_TX_EMPTY: u32 = 85; -pub const I2C0_TX_NONEMPTY: u32 = 86; -pub const I2C0_TX_OVERFLOW: u32 = 87; -pub const I2C0_ACQ_OVERFLOW: u32 = 88; -pub const I2C0_ACK_STOP: u32 = 89; -pub const I2C0_HOST_TIMEOUT: u32 = 90; - -pub const I2C1_FMT_WATERMARK: u32 = 91; -pub const I2C1_RX_WATERMARK: u32 = 92; -pub const I2C1_FMT_OVERFLOW: u32 = 93; -pub const I2C1_RX_OVERFLOW: u32 = 94; -pub const I2C1_NAK: u32 = 95; -pub const I2C1_SCL_INTERFERENCE: u32 = 96; -pub const I2C1_SDA_INTERFERENCE: u32 = 97; -pub const I2C1_STRETCH_TIMEOUT: u32 = 98; -pub const I2C1_SDA_UNSTABLE: u32 = 99; -pub const I2C1_TRANS_COMPLETE: u32 = 100; -pub const I2C1_TX_EMPTY: u32 = 101; -pub const I2C1_TX_NONEMPTY: u32 = 102; -pub const I2C1_TX_OVERFLOW: u32 = 103; -pub const I2C1_ACQ_OVERFLOW: u32 = 104; -pub const I2C1_ACK_STOP: u32 = 105; -pub const I2C1_HOST_TIMEOUT: u32 = 106; - -pub const I2C2_FMT_WATERMARK: u32 = 107; -pub const I2C2_RX_WATERMARK: u32 = 108; -pub const I2C2_FMT_OVERFLOW: u32 = 109; -pub const I2C2_RX_OVERFLOW: u32 = 110; -pub const I2C2_NAK: u32 = 111; -pub const I2C2_SCL_INTERFERENCE: u32 = 112; -pub const I2C2_SDA_INTERFERENCE: u32 = 113; -pub const I2C2_STRETCH_TIMEOUT: u32 = 114; -pub const I2C2_SDA_UNSTABLE: u32 = 115; -pub const I2C2_TRANS_COMPLETE: u32 = 116; -pub const I2C2_TX_EMPTY: u32 = 117; -pub const I2C2_TX_NONEMPTY: u32 = 118; -pub const I2C2_TX_OVERFLOW: u32 = 119; -pub const I2C2_ACQ_OVERFLOW: u32 = 120; -pub const I2C2_ACK_STOP: u32 = 121; -pub const I2C2_HOST_TIMEOUT: u32 = 122; - -pub const PATTGEN_DONE_CH0: u32 = 123; -pub const PATTGEN_DONE_CH1: u32 = 124; - -pub const RV_TIMER_EXPIRED0_0: u32 = 125; - -pub const USBDEV_PKT_RECEIVED: u32 = 126; -pub const USBDEV_PKT_SENT: u32 = 127; -pub const USBDEV_DISCONNECTED: u32 = 128; -pub const USBDEV_HOST_LOST: u32 = 129; -pub const USBDEV_LINK_RESET: u32 = 130; -pub const USBDEV_LINK_SUSPEND: u32 = 131; -pub const USBDEV_LINK_RESUME: u32 = 132; -pub const USBDEV_AV_EMPTY: u32 = 133; -pub const USBDEV_RX_FULL: u32 = 134; -pub const USBDEV_AV_OVERFLOW: u32 = 135; -pub const USBDEV_LINK_IN_ERR: u32 = 136; -pub const USBDEV_RX_CRC_ERR: u32 = 137; -pub const USBDEV_RX_PID_ERR: u32 = 138; -pub const USBDEV_RX_BITSTUFF_ERR: u32 = 139; -pub const USBDEV_FRAME: u32 = 140; -pub const USBDEV_CONNECTED: u32 = 141; -pub const USBDEV_LINK_OUT_ERR: u32 = 142; - -pub const OTP_CTRL_OTP_OPERATION_DONE: u32 = 143; -pub const OTP_CTRL_OTP_ERR: u32 = 144; - -pub const ALERT_CLASSA: u32 = 145; -pub const ALERT_CLASSB: u32 = 146; -pub const ALERT_CLASSC: u32 = 147; -pub const ALERT_CLASSD: u32 = 148; - -pub const PWRMGR_AON_WAKEUP: u32 = 149; - -pub const ADC_CTRL_AON_DEBUG_CABLE: u32 = 150; - -pub const AON_TIMER_AON_WAKEUP_TIMER_EXPIRED: u32 = 151; -pub const AON_TIMER_AON_WATCHDOG_EXPIRED: u32 = 152; - -pub const FLASH_PROG_EMPTY: u32 = 153; -pub const FLASH_PROG_LVL: u32 = 154; -pub const FLASH_RD_FULL: u32 = 155; -pub const FLASH_RD_LVL: u32 = 156; -pub const FLASH_OP_DONE: u32 = 157; - -pub const HMAC_HMAC_DONE: u32 = 158; -pub const HMAC_FIFO_EMPTY: u32 = 159; -pub const HMAC_HMAC_ERR: u32 = 160; - -pub const KMAC_KMAC_DONE: u32 = 161; -pub const KMAC_FIFO_EMPTY: u32 = 162; -pub const KMAC_KMAC_ERR: u32 = 163; - -pub const KEYMGR_OP_DONE: u32 = 164; - -pub const CSRNG_CS_CMD_REQ_DONE: u32 = 165; -pub const CSRNG_CS_ENTROPY_REQ: u32 = 166; -pub const CSRNG_CS_HW_INST_EXC: u32 = 167; -pub const CSRNG_CS_FATAL_ERR: u32 = 168; -pub const ENTROPY_SRC_ES_ENTROPY_VALID: u32 = 169; -pub const ENTROPY_SRC_ES_HEALTH_TEST_FAILED: u32 = 170; -pub const ENTROPY_SRC_ES_FATAL_ERR: u32 = 171; - -pub const EDN0_EDN_CMD_REQ_DONE: u32 = 172; -pub const EDN0_EDN_FATAL_ERR: u32 = 173; - -pub const EDN1_EDN_CMD_REQ_DONE: u32 = 174; -pub const EDN1_EDN_FATAL_ERR: u32 = 175; - -pub const OTBN_DONE: u32 = 176; \ No newline at end of file
diff --git a/chip/src/lib.rs b/chip/src/lib.rs deleted file mode 100644 index 67af24d..0000000 --- a/chip/src/lib.rs +++ /dev/null
@@ -1,21 +0,0 @@ -//! Drivers and chip support for Matcha. - -#![feature(llvm_asm, const_fn, naked_functions)] -#![no_std] -#![crate_name = "matcha"] -#![crate_type = "rlib"] - -mod chip_config; -mod interrupts; -mod plic_constants; - -pub mod aes; -pub mod chip; -pub mod gpio; -pub mod hmac; -pub mod i2c; -pub mod plic; -pub mod pwrmgr; -pub mod timer; -pub mod uart; -pub mod usbdev;
diff --git a/chip/src/pwrmgr.rs b/chip/src/pwrmgr.rs deleted file mode 100644 index 23db221..0000000 --- a/chip/src/pwrmgr.rs +++ /dev/null
@@ -1,7 +0,0 @@ -use kernel::common::StaticRef; -use lowrisc::pwrmgr::{PwrMgr, PwrMgrRegisters}; - -pub static mut PWRMGR: PwrMgr = PwrMgr::new(PWRMGR_BASE); - -const PWRMGR_BASE: StaticRef<PwrMgrRegisters> = - unsafe { StaticRef::new(0x4040_0000 as *const PwrMgrRegisters) };
diff --git a/chip/src/uart.rs b/chip/src/uart.rs deleted file mode 100644 index 63d9b72..0000000 --- a/chip/src/uart.rs +++ /dev/null
@@ -1,10 +0,0 @@ -use crate::chip_config::CONFIG; -use kernel::common::StaticRef; -use lowrisc::uart::{Uart, UartRegisters}; - -pub const UART0_BAUDRATE: u32 = CONFIG.uart_baudrate; - -pub static mut UART0: Uart = Uart::new(UART0_BASE, CONFIG.peripheral_freq); - -const UART0_BASE: StaticRef<UartRegisters> = - unsafe { StaticRef::new(0x4000_0000 as *const UartRegisters) };
diff --git a/chip/src/usbdev.rs b/chip/src/usbdev.rs deleted file mode 100644 index aa70c29..0000000 --- a/chip/src/usbdev.rs +++ /dev/null
@@ -1,7 +0,0 @@ -use kernel::common::StaticRef; -use lowrisc::usbdev::{Usb, UsbRegisters}; - -pub static mut USB: Usb = Usb::new(USB0_BASE); - -const USB0_BASE: StaticRef<UsbRegisters> = - unsafe { StaticRef::new(0x4011_0000 as *const UsbRegisters) };
diff --git a/config/Cargo.toml b/config/Cargo.toml new file mode 100644 index 0000000..a9bff0d --- /dev/null +++ b/config/Cargo.toml
@@ -0,0 +1,4 @@ +[package] +name = "matcha_config" +version = "0.1.0" +edition = "2018"
diff --git a/config/src/lib.rs b/config/src/lib.rs new file mode 100644 index 0000000..49d782c --- /dev/null +++ b/config/src/lib.rs
@@ -0,0 +1,16 @@ +//! Global configuration settings and constants that are shared between the +//! Matcha app and platform. + +#![no_std] + +// TODO(aappleby): Shared capsule/command numbers can't go in matcha_capsule +// right now due to some sort of toolchain mismatch that we need to figure out +// later. + +pub const DRIVER_NUM_ALARM: usize = 0x00000; +pub const DRIVER_NUM_CONSOLE: usize = 0x00001; +pub const DRIVER_NUM_DEBUG_UART: usize = 0x00009; +pub const DRIVER_NUM_STORAGE_MANAGER: usize = 0x50003; +pub const DRIVER_NUM_ELF_LOADER: usize = 0x50004; + +pub const CMD_ELF_LOADER_BOOT_SEL4: usize = 10;
diff --git a/hal/Cargo.toml b/hal/Cargo.toml new file mode 100644 index 0000000..bd27c2b --- /dev/null +++ b/hal/Cargo.toml
@@ -0,0 +1,9 @@ +[package] +name = "matcha_hal" +version = "0.1.0" +edition = "2018" + +[dependencies] +bare-io = "0.2" +kernel = { path = "../../tock/kernel" } +matcha_config = { path = "../config" }
diff --git a/hal/src/debug_uart.rs b/hal/src/debug_uart.rs new file mode 100644 index 0000000..183736d --- /dev/null +++ b/hal/src/debug_uart.rs
@@ -0,0 +1,35 @@ +//! Unsafe synchronous dump-string-to-uart impl and macro for debugging. + +use bare_io::{Cursor, Write}; +use core::fmt; + +pub const TX_BUSY: *const u32 = 0x4000_0010 as *const u32; +pub const TX_PORT: *mut u32 = 0x4000_0018 as *mut u32; + +pub fn send_sync(buf: &[u8], len: usize) { + unsafe { + for i in 0..len { + while (TX_BUSY.read_volatile() & 1) != 0 {} + TX_PORT.write_volatile(buf[i] as u32); + } + } +} + +pub fn vdprintf(args: fmt::Arguments) { + let mut uart_buf = [0u8; 256]; + let mut cur = Cursor::new(&mut uart_buf[..]); + if cur.write_fmt(args).is_ok() { + let pos = cur.position(); + send_sync(&uart_buf, pos as usize); + } +} + +#[macro_export] +macro_rules! dprintf { + ($msg:expr) => ({ + $crate::debug_uart::vdprintf(format_args!($msg)) + }); + ($fmt:expr, $($arg:tt)+) => ({ + $crate::debug_uart::vdprintf(format_args!($fmt, $($arg)+)) + }); +}
diff --git a/hal/src/lib.rs b/hal/src/lib.rs new file mode 100644 index 0000000..bc607a6 --- /dev/null +++ b/hal/src/lib.rs
@@ -0,0 +1,45 @@ +//! Anything in Matcha that needs to poke hardware registers directly will +//! go in this crate. + +#![no_std] +#![feature(asm)] + +pub mod debug_uart; +pub mod mailbox; +pub mod plic; +pub mod plic_constants; + +// Software interrupt enable bits in MIE +pub const USIE_BIT: u32 = 1 << 0; +pub const SSIE_BIT: u32 = 1 << 1; +pub const MSIE_BIT: u32 = 1 << 3; + +// External interrupt enable bits in MIE +pub const UEIE_BIT: u32 = 1 << 8; +pub const SEIE_BIT: u32 = 1 << 9; +pub const MEIE_BIT: u32 = 1 << 11; + +// Global interrupt enable bits in MSTATUS +pub const UIE_BIT: u32 = 0b00000001; +pub const SIE_BIT: u32 = 0b00000010; +pub const MIE_BIT: u32 = 0b00001000; + +pub unsafe fn set_mtvec(v: u32) { + asm!("csrw mtvec, {}", in(reg) v); +} + +pub unsafe fn set_mstatus_bits(mask: u32) { + asm!("csrrs zero, mstatus, {}", in(reg) mask); +} + +pub unsafe fn clear_mstatus_bits(mask: u32) { + asm!("csrrc zero, mstatus, {}", in(reg) mask); +} + +pub unsafe fn set_mie_bits(mask: u32) { + asm!("csrrs zero, mie, {}", in(reg) mask); +} + +pub unsafe fn clear_mie_bits(mask: u32) { + asm!("csrrc zero, mie, {}", in(reg) mask); +}
diff --git a/hal/src/mailbox.rs b/hal/src/mailbox.rs new file mode 100644 index 0000000..f653a2f --- /dev/null +++ b/hal/src/mailbox.rs
@@ -0,0 +1,142 @@ +//! Matcha hardware mailbox. +//! TODO(aappleby): Rework this to match the RTL implementation. + +use core::mem::transmute; +use kernel::common::registers::{register_structs, ReadWrite}; +use kernel::common::StaticRef; + +use crate::dprintf; +use crate::*; + +pub const MAILBOX0_BASE: u32 = 0x400F0000; +pub const MAILBOX1_BASE: u32 = 0x400F1000; +pub const MAILBOX_SIZE_DWORDS: usize = 8; + +register_structs! { + pub MailboxRegisters { + (0x000 => message: [ReadWrite<u32>; 8]), + (0x020 => irq_send: ReadWrite<u32>), + (0x024 => irq_recv: ReadWrite<u32>), + (0x028 => @END), + } +} + +pub struct Mailbox { + regs: StaticRef<MailboxRegisters>, + plic_irq_send: isize, + plic_irq_recv: isize, +} + +pub const MAILBOX0: Mailbox = Mailbox { + regs: unsafe { StaticRef::new(MAILBOX0_BASE as *mut MailboxRegisters) }, + plic_irq_send: 100, + plic_irq_recv: 101, +}; + +pub const MAILBOX1: Mailbox = Mailbox { + regs: unsafe { StaticRef::new(MAILBOX1_BASE as *mut MailboxRegisters) }, + plic_irq_send: 102, + plic_irq_recv: 103, +}; + +// 32-bit-word bitfield helper for the PLIC's irq enable lines. +pub unsafe fn set_bit(base: u32, bit_index: isize) { + let buf: *mut u32 = transmute(base); + let mut bits = buf.offset(bit_index >> 5).read_volatile(); + bits |= 1 << (bit_index & 31); + buf.offset(bit_index >> 5).write_volatile(bits); +} + +impl Mailbox { + pub unsafe fn get_message(&self, message: &mut [u32]) { + if message.len() > MAILBOX_SIZE_DWORDS { + dprintf!("get_message() - Bad message size {}\n", message.len()); + return; + } + + // Empty the mailbox - must be done with dword-sized writes + for i in 0..message.len() { + message[i] = self.regs.message[i].get(); + self.regs.message[i].set(0); + } + } + + pub unsafe fn set_message(&self, message: &[u32]) { + if message.len() > MAILBOX_SIZE_DWORDS { + dprintf!("set_message() - Bad message size {}\n", message.len()); + return; + } + + // Fill the mailbox - must be done with dword-sized writes + for i in 0..message.len() { + self.regs.message[i].set(message[i]); + } + } + + // This requires a small bit of explanation - if an interrupt were to happen + // between the 'if (*flag == 0)' and 'asm("wfi")' statements, we could end up + // waiting forever for an interrupt that had already arrived. To prevent that, + // we have to globally disable interrupts around those statements. Once + // an interrupt has been triggered, 'wfi' will continue and the isr will + // execute immediately after global interrupts are re-enabled. + + unsafe fn wait_until_full(&self) { + while self.regs.irq_send.get() == 0 { + clear_mstatus_bits(MIE_BIT | SIE_BIT); + if self.regs.irq_send.get() == 0 { + asm!("wfi"); + } + set_mstatus_bits(MIE_BIT | SIE_BIT); + } + } + + unsafe fn wait_until_empty(&self) { + while self.regs.irq_send.get() != 0 { + clear_mstatus_bits(MIE_BIT | SIE_BIT); + if self.regs.irq_send.get() != 0 { + asm!("wfi"); + } + set_mstatus_bits(MIE_BIT | SIE_BIT); + } + } + + unsafe fn wait_until_recv(&self) { + while self.regs.irq_recv.get() == 0 { + clear_mstatus_bits(MIE_BIT | SIE_BIT); + if self.regs.irq_recv.get() == 0 { + asm!("wfi"); + } + set_mstatus_bits(MIE_BIT | SIE_BIT); + } + } + + pub unsafe fn send_message(&self, message: &[u32], wait_for_ack: bool) { + self.wait_until_empty(); + self.set_message(message); + self.regs.irq_send.set(1); + + if wait_for_ack { + // Enable the RECV irq line, then wait for RECV. The ISR will disable the + // irq line once it fires. + set_bit(plic::PLIC_EN0, self.plic_irq_recv); + self.wait_until_recv(); + self.regs.irq_recv.set(0); + } + } + + pub unsafe fn recv_message(&self, message: &mut [u32], send_ack: bool) { + // Enable the SEND irq line and wait for new mail. The ISR will disable the + // irq line once it fires. + set_bit(plic::PLIC_EN1, self.plic_irq_send); + self.wait_until_full(); + self.regs.irq_send.set(0); + + // Message has arrived. + self.get_message(message); + + if send_ack { + // Trigger RECV + self.regs.irq_recv.set(1); + } + } +}
diff --git a/chip/src/plic.rs b/hal/src/plic.rs similarity index 93% rename from chip/src/plic.rs rename to hal/src/plic.rs index 9852ce3..59bf065 100644 --- a/chip/src/plic.rs +++ b/hal/src/plic.rs
@@ -1,9 +1,16 @@ //! Platform Level Interrupt Control peripheral driver. +use crate::plic_constants::*; use kernel::common::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite}; use kernel::common::StaticRef; -use crate::plic_constants::*; -//use kernel::debug; + +pub const PLIC_EN0: u32 = 0x41010400; +pub const PLIC_CCCR0: u32 = 0x4101041C; +pub const PLIC_MSIP0: u32 = 0x41010420; + +pub const PLIC_EN1: u32 = 0x41010500; +pub const PLIC_CCCR1: u32 = 0x4101051C; +pub const PLIC_MSIP1: u32 = 0x41010520; register_structs! { pub PlicRegisters {
diff --git a/chip/src/plic_constants.rs b/hal/src/plic_constants.rs similarity index 99% rename from chip/src/plic_constants.rs rename to hal/src/plic_constants.rs index 7498b8a..0c13387 100644 --- a/chip/src/plic_constants.rs +++ b/hal/src/plic_constants.rs
@@ -1796,4 +1796,4 @@ pub const RV_PLIC_ALERT_TEST_REG_OFFSET: usize = 0x600; pub const RV_PLIC_ALERT_TEST_FATAL_FAULT_BIT: u32 = 0; -// End generated register constants for RV_PLIC \ No newline at end of file +// End generated register constants for RV_PLIC
diff --git a/matcha.code-workspace b/matcha.code-workspace new file mode 100644 index 0000000..b20fa7b --- /dev/null +++ b/matcha.code-workspace
@@ -0,0 +1,93 @@ +{ + "folders": [ + { "path": "."} + ], + "settings": { + "files.associations": { + ".*/BUILD": "starlark", + ".*/METADATA": "starlark", + ".*/WORKSPACE": "starlark", + "*.gss": "css", + "*.inc": "c" + }, + "files.exclude": { + ".repo": true, + "autom4te.cache": true, + "cache": true, + "cicd": true, + "manifest": true, + "out": true, + "toolchain": true, + "**/Cargo.lock": true, + "**/target": true, + "**/arch-arm": true, + "**/arch/arm": true, + "**/arch/x86": true, + "**/x86_64": true, + "**/aarch64": true, + "**/arch/64": true, + "**/plat/64": true, + "**/plat/pc99": true, + } + }, + "launch": { + "version": "0.2.0", + "configurations": [ + { + "name": "MatchaDebugger", + "type": "cppdbg", + "request": "launch", + + // This has to be set. + "cwd": "${workspaceFolder}", + + // This has to be set, but it is unused because of our custom launch script. + "program": "../../out/shodan_boot_rom/build-out/multihart_boot_rom/multihart_boot_rom_sim_verilator.elf", + + "MIMode": "gdb", + "miDebuggerPath": "${workspaceFolder}/../../cache/toolchain/bin/riscv32-unknown-elf-gdb", + "miDebuggerServerAddress": "localhost:3333", // If this isn't set, vscode will open another terminal on launch + "logging": { "engineLogging": true }, // optional, enable if you want to see the gdb commands that were sent + + // VSCode claims this is deprecated, but if you use "customLaunchSetupCommands" it won't start the debugging session if this isn't here + // and valid. It does _not_ appear to matter what it's set to. + "targetArchitecture": "x64", // riscv:rv32? + + "customLaunchSetupCommands":[ + // Set gdb current directory. + {"text": "cd ${workspaceFolder}"}, + + // Set app current directory. + {"text": "set cwd ${workspaceFolder}"}, + + // Set source file search path. + {"text": "directory ../../sw/matcha"}, + {"text": "directory ../../sw/tock"}, + + // Load the bootrom executable. + {"text": "file ../../out/shodan_boot_rom/build-out/multihart_boot_rom/multihart_boot_rom_sim_verilator.elf"}, + + // Load additional symbol files. "-file-symbol-file" seems to unload previously loaded symbols, but add-symbol-file works. + {"text": "set confirm off"}, + + // Matcha+TockOS symbols + {"text": "add-symbol-file ../../out/matcha/riscv32imc-unknown-none-elf/debug/matcha_platform"}, + {"text": "add-symbol-file ../../out/matcha/riscv32imc-unknown-none-elf/debug/matcha_app"}, + + // Connect to the Renode gdb server. + {"text": "target remote localhost:3333"}, + ], + + // This is supposed to stop vscode from issuing an "-exec-continue", but it doesn't seem to work. + "launchCompleteCommand": "None" + } + ], + }, + "extensions": { + }, + "tasks": { + "version": "2.0.0", + "tasks": [] + } + } + \ No newline at end of file
diff --git a/platform/.cargo/config.toml b/platform/.cargo/config.toml new file mode 100644 index 0000000..d92c351 --- /dev/null +++ b/platform/.cargo/config.toml
@@ -0,0 +1,13 @@ +[build] +target = "riscv32imc-unknown-none-elf" +target-dir = "../../../out/matcha" +rustflags = [ + "-C", "link-arg=-Tlayout.ld", + "-C", "linker=rust-lld", + "-C", "linker-flavor=ld.lld", + "-C", "relocation-model=dynamic-no-pic", + "-C", "link-arg=-zmax-page-size=512", + "-C", "link-arg=-icf=all", + "-C", "force-frame-pointers=no", + "--remap-path-prefix=$(ROOTDIR)/sw/tock/=", +]
diff --git a/platform/Cargo.toml b/platform/Cargo.toml new file mode 100644 index 0000000..821688e --- /dev/null +++ b/platform/Cargo.toml
@@ -0,0 +1,21 @@ +[package] +name = "matcha_platform" +version = "0.1.0" +authors = ["Tock Project Developers <tock-dev@googlegroups.com>"] +build = "build.rs" +edition = "2018" + +[dependencies] +bare-io = "0.2" + +components = { path = "../../tock/boards/components" } +rv32i = { path = "../../tock/arch/rv32i" } +capsules = { path = "../../tock/capsules" } +kernel = { path = "../../tock/kernel" } +lowrisc = { path = "../../tock/chips/lowrisc" } + +blob_fs = { path = "../blob_fs" } +matcha_capsules = { path = "../capsules" } +matcha_config = { path = "../config" } +matcha_utils = { path = "../utils" } +matcha_hal = { path = "../hal" } \ No newline at end of file
diff --git a/platform/build.rs b/platform/build.rs new file mode 100644 index 0000000..f05f878 --- /dev/null +++ b/platform/build.rs
@@ -0,0 +1,4 @@ +fn main() { + println!("cargo:rerun-if-changed=layout.ld"); + println!("cargo:rerun-if-changed=kernel_layout.ld"); +}
diff --git a/board/kernel_layout.ld b/platform/kernel_layout.ld similarity index 100% rename from board/kernel_layout.ld rename to platform/kernel_layout.ld
diff --git a/board/layout.ld b/platform/layout.ld similarity index 100% rename from board/layout.ld rename to platform/layout.ld
diff --git a/board/rust-toolchain b/platform/rust-toolchain similarity index 100% rename from board/rust-toolchain rename to platform/rust-toolchain
diff --git a/chip/src/chip.rs b/platform/src/chip.rs similarity index 77% rename from chip/src/chip.rs rename to platform/src/chip.rs index 58a95b9..b063c46 100644 --- a/chip/src/chip.rs +++ b/platform/src/chip.rs
@@ -5,23 +5,24 @@ use kernel; use kernel::debug; use kernel::hil::time::Alarm; -use kernel::Chip; use rv32i::csr::{mcause, mie::mie, mip::mip, mtvec::mtvec, CSR}; use rv32i::syscall::SysCall; use rv32i::PMPConfigMacro; -use crate::chip_config::CONFIG; -use crate::gpio; -use crate::hmac; -use crate::interrupts; -use crate::plic; -use crate::pwrmgr; use crate::timer; use crate::uart; -use crate::usbdev; +use matcha_hal::plic; PMPConfigMacro!(4); +pub const CHIP_NAME: &str = "sim_verilator"; +pub const CHIP_CPU_FREQ: u32 = 500_000; +pub const CHIP_PERIPH_FREQ: u32 = 125_000; +pub const CHIP_UART_BPS: u32 = 9600; + +pub const UART0_TX_WATERMARK: u32 = 1; +pub const UART0_RX_PARITY_ERR: u32 = 8; + pub struct Matcha<A: 'static + Alarm<'static>> { userspace_kernel_boundary: SysCall, pmp: PMP, @@ -46,64 +47,12 @@ unsafe fn handle_plic_interrupts(&self) { while let Some(interrupt) = plic::next_pending() { match interrupt { - interrupts::UART0_TX_WATERMARK..=interrupts::UART0_RX_PARITY_ERR => { - uart::UART0.handle_interrupt() - } - int_pin @ interrupts::GPIO_PIN0..=interrupts::GPIO_PIN31 => { - let pin = &gpio::PORT[(int_pin - interrupts::GPIO_PIN0) as usize]; - pin.handle_interrupt(); - } - interrupts::HMAC_HMAC_DONE..=interrupts::HMAC_HMAC_ERR => { - hmac::HMAC.handle_interrupt() - } - interrupts::USBDEV_PKT_RECEIVED..=interrupts::USBDEV_CONNECTED => { - usbdev::USB.handle_interrupt() - } - interrupts::PWRMGRWAKEUP => { - pwrmgr::PWRMGR.handle_interrupt(); - self.check_until_true_or_interrupt( - || pwrmgr::PWRMGR.check_clock_propagation(), - None, - ); - } + UART0_TX_WATERMARK..=UART0_RX_PARITY_ERR => uart::UART0.handle_interrupt(), _ => debug!("Pidx {}", interrupt), } plic::complete(interrupt); } } - - /// Run a function in an interruptable loop. - /// - /// The function will run until it returns true, an interrupt occurs or if - /// `max_tries` is not `None` and that limit is reached. - /// If the function returns true this call will also return true. If an - /// interrupt occurs or `max_tries` is reached this call will return false. - fn check_until_true_or_interrupt<F>(&self, f: F, max_tries: Option<usize>) -> bool - where - F: Fn() -> bool, - { - match max_tries { - Some(t) => { - for _i in 0..t { - if self.has_pending_interrupts() { - return false; - } - if f() { - return true; - } - } - } - None => { - while !self.has_pending_interrupts() { - if f() { - return true; - } - } - } - } - - false - } } impl<A: 'static + Alarm<'static>> kernel::Chip for Matcha<A> { @@ -160,8 +109,8 @@ fn sleep(&self) { unsafe { - pwrmgr::PWRMGR.enable_low_power(); - self.check_until_true_or_interrupt(|| pwrmgr::PWRMGR.check_clock_propagation(), None); + //pwrmgr::PWRMGR.enable_low_power(); + //self.check_until_true_or_interrupt(|| pwrmgr::PWRMGR.check_clock_propagation(), None); rv32i::support::wfi(); } } @@ -176,7 +125,7 @@ unsafe fn print_state(&self, writer: &mut dyn Write) { let _ = writer.write_fmt(format_args!( "\r\n---| Matcha configuration for {} |---", - CONFIG.name + crate::chip::CHIP_NAME )); rv32i::print_riscv_state(writer); }
diff --git a/platform/src/main.rs b/platform/src/main.rs new file mode 100644 index 0000000..83f00c8 --- /dev/null +++ b/platform/src/main.rs
@@ -0,0 +1,227 @@ +//! Board file for Shodan's "Matcha" RISC-V development platform. + +#![no_std] +#![no_main] +#![feature(llvm_asm)] +#![feature(const_fn)] +#![feature(naked_functions)] + +use capsules::virtual_alarm::{MuxAlarm, VirtualMuxAlarm}; +use core::panic::PanicInfo; +use kernel::capabilities; +use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState}; +use kernel::component::Component; +use kernel::hil; +use kernel::hil::time::Alarm; +use kernel::Chip; +use kernel::Platform; +use kernel::{create_capability, debug, static_init}; +use matcha_capsules::debug_uart::DebugUartCapsule; +use matcha_capsules::elf_loader::ElfLoaderCapsule; +use matcha_capsules::storage_manager::StorageManagerCapsule; +use matcha_config::*; +use matcha_hal::dprintf; +use rv32i::csr; + +pub mod chip; +pub mod timer; +pub mod uart; + +/// Panic handler. +#[cfg(not(test))] +#[no_mangle] +#[panic_handler] +pub unsafe extern "C" fn panic_fmt(_pi: &PanicInfo) -> ! { + dprintf!("panic panic panic!\n"); + loop {} +} + +/// These symbols are defined in the linker script. +extern "C" { + /// Beginning of the ROM region containing app images. + static _sapps: u8; + /// End of the ROM region containing app images. + static _eapps: u8; + /// Beginning of the RAM region for app memory. + static mut _sappmem: u8; + /// End of the RAM region for app memory. + static _eappmem: u8; +} + +// Actual memory for holding the active process structures. Need an empty list +// at least. +static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; 4] = + [None, None, None, None]; + +/// Dummy buffer that causes the linker to reserve enough space for the stack. +/// Must be at least 16k in debug builds (@aappleby - not sure why, what's so large?) +#[no_mangle] +#[link_section = ".stack_buffer"] +pub static mut STACK_MEMORY: [u8; 0x4000] = [0; 0x4000]; + +/// A structure representing this platform that holds references to all +/// capsules for this platform. We've included an alarm and console. +struct MatchaPlatform { + console: &'static capsules::console::Console<'static>, + alarm: &'static capsules::alarm::AlarmDriver< + 'static, + VirtualMuxAlarm<'static, crate::timer::RvTimer<'static>>, + >, + debug_uart: &'static DebugUartCapsule, + storage_manager: &'static StorageManagerCapsule, + elf_loader: &'static ElfLoaderCapsule, +} + +/// Mapping of integer syscalls to objects that implement syscalls. +impl Platform for MatchaPlatform { + fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R + where + F: FnOnce(Option<&dyn kernel::Driver>) -> R, + { + match driver_num { + DRIVER_NUM_CONSOLE => f(Some(self.console)), + DRIVER_NUM_ALARM => f(Some(self.alarm)), + DRIVER_NUM_DEBUG_UART => f(Some(self.debug_uart)), + DRIVER_NUM_STORAGE_MANAGER => f(Some(self.storage_manager)), + DRIVER_NUM_ELF_LOADER => f(Some(self.elf_loader)), + _ => f(None), + } + } +} + +/// Reset Handler. +/// +/// This function is called from the arch crate after some very basic RISC-V +/// setup. +#[no_mangle] +pub unsafe fn reset_handler() { + // Basic setup of the platform. + rv32i::init_memory(); + // Ibex-specific handler + crate::chip::configure_trap_handler(); + + dprintf!("sw/matcha/platform/src/main.rs::reset_handler()\n"); + + // initialize capabilities + let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability); + let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability); + + let main_loop_cap = create_capability!(capabilities::MainLoopCapability); + + let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES)); + + let dynamic_deferred_call_clients = + static_init!([DynamicDeferredCallClientState; 1], Default::default()); + let dynamic_deferred_caller = static_init!( + DynamicDeferredCall, + DynamicDeferredCall::new(dynamic_deferred_call_clients) + ); + DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); + + // Create a shared UART channel for the console and for kernel debug. + let uart_mux = components::console::UartMuxComponent::new( + &crate::uart::UART0, + crate::uart::UART0_BAUDRATE, + dynamic_deferred_caller, + ) + .finalize(()); + + let alarm = &crate::timer::TIMER; + alarm.setup(); + + // Create a shared virtualization mux layer on top of a single hardware + // alarm. + let mux_alarm = static_init!( + MuxAlarm<'static, crate::timer::RvTimer>, + MuxAlarm::new(alarm) + ); + hil::time::Alarm::set_alarm_client(&crate::timer::TIMER, mux_alarm); + + // Alarm + let virtual_alarm_user = static_init!( + VirtualMuxAlarm<'static, crate::timer::RvTimer>, + VirtualMuxAlarm::new(mux_alarm) + ); + let scheduler_timer_virtual_alarm = static_init!( + VirtualMuxAlarm<'static, crate::timer::RvTimer>, + VirtualMuxAlarm::new(mux_alarm) + ); + let alarm = static_init!( + capsules::alarm::AlarmDriver<'static, VirtualMuxAlarm<'static, crate::timer::RvTimer>>, + capsules::alarm::AlarmDriver::new( + virtual_alarm_user, + board_kernel.create_grant(&memory_allocation_cap) + ) + ); + hil::time::Alarm::set_alarm_client(virtual_alarm_user, alarm); + + let chip = static_init!( + crate::chip::Matcha<VirtualMuxAlarm<'static, crate::timer::RvTimer>>, + crate::chip::Matcha::new(scheduler_timer_virtual_alarm) + ); + scheduler_timer_virtual_alarm.set_alarm_client(chip.scheduler_timer()); + + // Need to enable all interrupts for Tock Kernel + chip.enable_plic_interrupts(); + // enable interrupts globally + csr::CSR + .mie + .modify(csr::mie::mie::msoft::SET + csr::mie::mie::mtimer::SET + csr::mie::mie::mext::SET); + csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET); + + // Setup the console. + let console = components::console::ConsoleComponent::new(board_kernel, uart_mux).finalize(()); + // Create the debugger object that handles calls to `debug!()`. + components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(()); + + let debug_uart_capsule = static_init!( + DebugUartCapsule, + DebugUartCapsule { + app_data_grant: board_kernel.create_grant(&memory_allocation_cap) + } + ); + + let storage_manager = static_init!( + matcha_capsules::storage_manager::StorageManagerCapsule, + matcha_capsules::storage_manager::StorageManagerCapsule::new( + board_kernel.create_grant(&memory_allocation_cap) + ) + ); + + let elf_loader = static_init!( + matcha_capsules::elf_loader::ElfLoaderCapsule, + matcha_capsules::elf_loader::ElfLoaderCapsule {} + ); + + let platform = MatchaPlatform { + console: console, + alarm: alarm, + debug_uart: debug_uart_capsule, + storage_manager: storage_manager, + elf_loader: elf_loader, + }; + + kernel::procs::load_processes( + board_kernel, + chip, + core::slice::from_raw_parts( + &_sapps as *const u8, + &_eapps as *const u8 as usize - &_sapps as *const u8 as usize, + ), + core::slice::from_raw_parts_mut( + &mut _sappmem as *mut u8, + &_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize, + ), + &mut PROCESSES, + kernel::procs::FaultResponse::Panic, + &process_mgmt_cap, + ) + .unwrap_or_else(|err| { + debug!("Error loading processes!"); + debug!("{:?}", err); + }); + debug!("MatchaPlatform initialisation complete. Entering main loop"); + + let scheduler = components::sched::priority::PriorityComponent::new(board_kernel).finalize(()); + board_kernel.kernel_loop(&platform, chip, None, scheduler, &main_loop_cap); +}
diff --git a/chip/src/timer.rs b/platform/src/timer.rs similarity index 97% rename from chip/src/timer.rs rename to platform/src/timer.rs index 3c2e09e..362afd5 100644 --- a/chip/src/timer.rs +++ b/platform/src/timer.rs
@@ -1,6 +1,5 @@ //! Timer driver. -use crate::chip_config::CONFIG; use kernel::common::cells::OptionalCell; use kernel::common::registers::{register_bitfields, register_structs, ReadWrite, WriteOnly}; use kernel::common::StaticRef; @@ -8,7 +7,7 @@ use kernel::hil::time::{Ticks, Ticks64, Time}; use kernel::ReturnCode; -const PRESCALE: u16 = ((CONFIG.cpu_freq / 10_000) - 1) as u16; // 10Khz +const PRESCALE: u16 = ((crate::chip::CHIP_CPU_FREQ / 10_000) - 1) as u16; // 10Khz /// 10KHz `Frequency` #[derive(Debug)]
diff --git a/platform/src/uart.rs b/platform/src/uart.rs new file mode 100644 index 0000000..f9acb19 --- /dev/null +++ b/platform/src/uart.rs
@@ -0,0 +1,10 @@ +//use crate::chip_config::CONFIG; +use kernel::common::StaticRef; +use lowrisc::uart::{Uart, UartRegisters}; + +pub const UART0_BAUDRATE: u32 = crate::chip::CHIP_UART_BPS; + +pub static mut UART0: Uart = Uart::new(UART0_BASE, crate::chip::CHIP_PERIPH_FREQ); + +const UART0_BASE: StaticRef<UartRegisters> = + unsafe { StaticRef::new(0x4000_0000 as *const UartRegisters) };
diff --git a/utils/Cargo.toml b/utils/Cargo.toml new file mode 100644 index 0000000..2c51401 --- /dev/null +++ b/utils/Cargo.toml
@@ -0,0 +1,9 @@ +[package] +name = "matcha_utils" +version = "0.1.0" +edition = "2018" + +[dependencies] +bare-io = "0.2" + +matcha_hal = { path = "../hal" } \ No newline at end of file
diff --git a/utils/src/elf_loader.rs b/utils/src/elf_loader.rs new file mode 100644 index 0000000..219fd63 --- /dev/null +++ b/utils/src/elf_loader.rs
@@ -0,0 +1,158 @@ +// Trivial elf segment loader, just copies segments straight from the in-memory +// blob to the physical addresses specified in the program header. + +use core::cmp; +use core::mem::transmute; +use core::ptr; +use core::slice; + +use crate::tar_loader; +use matcha_hal::dprintf; + +pub const ELF_MAGIC: u32 = 0x464c457f; + +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct Elf32Header { + pub e_ident: [u8; 16], + pub e_type: u16, /* Relocatable=1, Executable=2 (+ some more ..) */ + pub e_machine: u16, /* Target architecture: MIPS=8 */ + pub e_version: u32, /* Elf version (should be 1) */ + pub e_entry: u32, /* Code entry point */ + pub e_phoff: u32, /* Program header table */ + pub e_shoff: u32, /* Section header table */ + pub e_flags: u32, /* Flags */ + pub e_ehsize: u16, /* ELF header size */ + pub e_phentsize: u16, /* Size of one program segment header */ + pub e_phnum: u16, /* Number of program segment headers */ + pub e_shentsize: u16, /* Size of one section header */ + pub e_shnum: u16, /* Number of section headers */ + pub e_shstrndx: u16, /* Section header index of the string table for section + header names */ +} + +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct Elf32Phdr { + pub p_type: u32, /* Segment type: Loadable segment = 1 */ + pub p_offset: u32, /* Offset of segment in file */ + pub p_vaddr: u32, /* Reqd virtual address of segment when loading */ + pub p_paddr: u32, /* Reqd physical address of segment (ignore) */ + pub p_filesz: u32, /* How many bytes this segment occupies in file */ + pub p_memsz: u32, /* How many bytes this segment should occupy in memory */ + pub p_flags: u32, /* Flags: logical "or" of PF_ constants below */ + pub p_align: u32, /* Reqd alignment of segment in memory */ +} + +pub fn elf_phys_min(segments: &[Elf32Phdr]) -> u32 { + return segments.iter().fold(0xFFFFFFFF, |acc, seg| { + if seg.p_type != 1 { + return acc; + } else { + return cmp::min(acc, seg.p_paddr); + } + }); +} + +pub fn elf_phys_max(segments: &[Elf32Phdr]) -> u32 { + return segments.iter().fold(0, |acc, seg| { + if seg.p_type != 1 { + return acc; + } else { + return cmp::max(acc, seg.p_paddr + seg.p_memsz); + } + }); +} + +pub fn elf_virt_min(segments: &[Elf32Phdr]) -> u32 { + return segments.iter().fold(0xFFFFFFFF, |acc, seg| { + if seg.p_type != 1 { + return acc; + } else { + return cmp::min(acc, seg.p_vaddr); + } + }); +} + +pub fn elf_virt_max(segments: &[Elf32Phdr]) -> u32 { + return segments.iter().fold(0, |acc, seg| { + if seg.p_type != 1 { + return acc; + } else { + return cmp::max(acc, seg.p_vaddr + seg.p_memsz); + } + }); +} + +pub unsafe fn elf_get_segments(elf: *const Elf32Header) -> &'static [Elf32Phdr] { + let base: *const u8 = transmute(elf); + let seg_count = (*elf).e_phnum as usize; + let segments: &[Elf32Phdr] = + slice::from_raw_parts(transmute(base.offset((*elf).e_phoff as isize)), seg_count); + return segments; +} + +pub unsafe fn find_elf(name: &str) -> *const Elf32Header { + let (tar_offset, tar_size) = tar_loader::find_file(name); + + if tar_size > 0 { + let pmagic: *const u32 = transmute(tar_offset); + if pmagic.read_volatile() == ELF_MAGIC { + let elf_header: *const Elf32Header = transmute(tar_offset); + return elf_header; + } + } + + dprintf!("Could not find elf for '{}'\n", name); + return transmute(0); +} + +pub unsafe fn load_elf_segments(elf: &Elf32Header, dst_offset: u32) { + let base: *const u8 = transmute(elf); + let seg_count = elf.e_phnum as usize; + let segments: &[Elf32Phdr] = + slice::from_raw_parts(transmute(base.offset(elf.e_phoff as isize)), seg_count); + + for i in 0..segments.len() { + let seg = &segments[i]; + + // Loadable segment type. + const PT_LOAD: u32 = 1; + if seg.p_type != PT_LOAD { + continue; + } + if seg.p_filesz == 0 { + continue; + } + + let src: *const u8 = transmute(base.offset(seg.p_offset as isize)); + + let txt_size = seg.p_filesz as usize; + let txt_start: *mut u8 = transmute(seg.p_paddr + dst_offset); + let txt_end = txt_start.offset(txt_size as isize); + + dprintf!( + "seg {}: {:?} -> {:?}:{:?} ({} bytes)\n", + i, + src, + txt_start, + txt_end, + txt_size + ); + ptr::copy_nonoverlapping(src, txt_start, txt_size); + + let bss_size = (seg.p_memsz - seg.p_filesz) as usize; + let bss_start = txt_end; + let bss_end = bss_start.offset(bss_size as isize); + + dprintf!( + "bss {}: {:?} -> {:?}:{:?} ({} bytes)\n", + i, + src, + bss_start, + bss_end, + bss_size + ); + ptr::write_bytes(bss_start, 0, bss_size as usize); + } +}
diff --git a/utils/src/lib.rs b/utils/src/lib.rs new file mode 100644 index 0000000..5677c81 --- /dev/null +++ b/utils/src/lib.rs
@@ -0,0 +1,63 @@ +#![no_std] + +use core::mem::transmute; +use matcha_hal::dprintf; + +pub mod elf_loader; +pub mod tar_loader; + +pub const SMC_CONTROL_BLOCK: *mut u32 = 0x49000000 as *mut u32; + +fn round_up_to_page(addr: u32) -> u32 { + return (addr + 4095) & !4095; +} + +// TODO(aappleby): Break this down into smaller pieces and move into app/main +pub fn load_sel4() { + unsafe { + // Look in our tar file for the ELFs we need to boot Shodan. + let sel4_elf = elf_loader::find_elf("kernel"); + let capdl_elf = elf_loader::find_elf("capdl-loader"); + + // If we found all of them, boot in Shodan mode. + if !sel4_elf.is_null() && !capdl_elf.is_null() { + dprintf!("Loading seL4 kernel elf\n"); + elf_loader::load_elf_segments(sel4_elf.as_ref().unwrap(), 0); + + let sel4_segments = elf_loader::elf_get_segments(sel4_elf); + let capdl_segments = elf_loader::elf_get_segments(capdl_elf); + + let sel4_pend = round_up_to_page(elf_loader::elf_phys_max(sel4_segments)); + + dprintf!("Loading capdl-loader to the page after seL4\n"); + elf_loader::load_elf_segments( + capdl_elf.as_ref().unwrap(), + sel4_pend - elf_loader::elf_phys_min(capdl_segments), + ); + + dprintf!("Starting management core\n"); + + let entry_point: u32 = (*sel4_elf).e_entry + - (elf_loader::elf_virt_min(sel4_segments) + - elf_loader::elf_phys_min(sel4_segments)); + + let message = [ + transmute(sel4_pend), + transmute( + sel4_pend + + round_up_to_page( + elf_loader::elf_phys_max(capdl_segments) + - elf_loader::elf_phys_min(capdl_segments), + ), + ), + transmute(sel4_pend - elf_loader::elf_phys_min(capdl_segments)), + transmute((*capdl_elf).e_entry), + ]; + matcha_hal::mailbox::MAILBOX1.set_message(&message); + + SMC_CONTROL_BLOCK.write_volatile(entry_point); + } else { + dprintf!("Missing sel4_elf or capdl_elf\n"); + } + } +}
diff --git a/utils/src/tar_loader.rs b/utils/src/tar_loader.rs new file mode 100644 index 0000000..176d9e8 --- /dev/null +++ b/utils/src/tar_loader.rs
@@ -0,0 +1,82 @@ +// Trivial tar loader. + +use core::mem::transmute; +use matcha_hal::dprintf; + +const EFLASH_START: u32 = 0x44000000; +const EFLASH_END: u32 = 0x45000000; + +#[repr(C, packed)] +pub struct TarHeader { + /* byte offset */ + name: [u8; 100], /* 0 */ + mode: [u8; 8], /* 100 */ + uid: [u8; 8], /* 108 */ + gid: [u8; 8], /* 116 */ + size: [u8; 12], /* 124 */ + mtime: [u8; 12], /* 136 */ + chksum: [u8; 8], /* 148 */ + typeflag: u8, /* 156 */ + linkname: [u8; 100], /* 157 */ + magic: [u8; 6], /* 257 */ + version: [u8; 2], /* 263 */ + uname: [u8; 32], /* 265 */ + gname: [u8; 32], /* 297 */ + devmajor: [u8; 8], /* 329 */ + devminor: [u8; 8], /* 337 */ + prefix: [u8; 155], /* 345 */ + /* 500 */ +} + +impl Default for TarHeader { + fn default() -> Self { + return TarHeader { + name: [0; 100], + mode: [0; 8], + uid: [0; 8], + gid: [0; 8], + size: [0; 12], + mtime: [0; 12], + chksum: [0; 8], + typeflag: 0, + linkname: [0; 100], + magic: [0; 6], + version: [0; 2], + uname: [0; 32], + gname: [0; 32], + devmajor: [0; 8], + devminor: [0; 8], + prefix: [0; 155], + }; + } +} + +fn parse_octal(text: &[u8]) -> u32 { + let mut n: u32 = 0; + for x in text.iter() { + if *x == (0 as u8) { + break; + } + n = (n << 3) | ((*x as u32) - ('0' as u32)); + } + return n; +} + +pub unsafe fn find_file(name: &str) -> (u32, u32) { + let mut cursor = EFLASH_START; + while cursor < EFLASH_END { + let tar_header: *const TarHeader = transmute(cursor); + cursor += 512; + let tar_name = core::str::from_utf8(&(*tar_header).name).unwrap(); + if tar_name.contains(name) { + let tar_size = parse_octal(&(*tar_header).size); + return (cursor, tar_size); + } else { + let tar_size = parse_octal(&(*tar_header).size); + cursor += (tar_size + 511) & !511; + } + } + + dprintf!("Could not find tar entry for '{}'\n", name); + return (0, 0); +}