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);
+}