Merge #253

253: Update result.rs with remaining ReturnCode values r=jrvanwhy a=MirnaMuhammad98

Adding the remaining ReturnCode values that exist in [tock/returncode.rs](https://github.com/tock/tock/blob/master/kernel/src/returncode.rs)

Co-authored-by: Mirna <29131616+MirnaMuhammad98@users.noreply.github.com>
diff --git a/Cargo.toml b/Cargo.toml
index caeae02..99543d9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,6 +29,7 @@
 p256 = { version = "0.5.0" , default-features = false, features = ["arithmetic", "ecdsa", "ecdsa-core"] }
 subtle = { version = "2.3.0", default-features = false, features = ["i128"] }
 generic-array = { version = "0.14.3" }
+libmctp = { version = "0.1.0" }
 
 # We need to override this to allow builds for targets that don't support atomics.
 # Once a version newer then 0.4.11 is released we can update to use that.
diff --git a/Makefile b/Makefile
index e32decb..81829e2 100644
--- a/Makefile
+++ b/Makefile
@@ -18,6 +18,7 @@
 	@echo " - nrf52"
 	@echo " - imxrt1050"
 	@echo " - apollo3"
+	@echo " - stm32f3discovery"
 	@echo
 	@echo "Run 'make setup' to setup Rust to build libtock-rs."
 	@echo "Run 'make <board>' to build libtock-rs for that board"
@@ -132,6 +133,14 @@
 flash-nrf52840:
 	PLATFORM=nrf52840 cargo run $(release) --target=thumbv7em-none-eabi --example $(EXAMPLE) $(features)
 
+.PHONY: stm32f3discovery
+stm32f3discovery:
+	PLATFORM=stm32f3discovery cargo build $(release) --target=thumbv7em-none-eabi --examples $(features)
+	
+.PHONY: flash-stm32f3discovery
+flash-stm32f3discovery:
+	PLATFORM=stm32f3discovery cargo run $(release) --target=thumbv7em-none-eabi --example $(EXAMPLE) $(features)
+
 .PHONY: opentitan
 opentitan:
 	PLATFORM=opentitan cargo build $(release) --target=riscv32imc-unknown-none-elf --examples $(features)
diff --git a/boards/layout_stm32f3discovery.ld b/boards/layout_stm32f3discovery.ld
new file mode 100644
index 0000000..9368003
--- /dev/null
+++ b/boards/layout_stm32f3discovery.ld
@@ -0,0 +1,11 @@
+/* Layout for the stm32f3discovery board, usable by the examples in this repository. */
+
+MEMORY {
+  /* The application region is 64 bytes (0x40) */
+  FLASH (rx) : ORIGIN = 0x08020040, LENGTH = 0x00020000
+  SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 48K
+}
+
+MPU_MIN_ALIGN = 8K;
+
+INCLUDE layout_generic.ld
diff --git a/doc/PlatformDesignStory.md b/doc/PlatformDesignStory.md
new file mode 100644
index 0000000..0632494
--- /dev/null
+++ b/doc/PlatformDesignStory.md
@@ -0,0 +1,572 @@
+`libtock_platform` Design Story
+===============================
+
+Note: At the time of this writing, `libtock_platform` is still a work in
+progress that exists largely in @jrvanwhy's head.
+
+`libtock_platform` is a crate that will contain core abstractions that will be
+used by `libtock_core`'s drivers. For example, it will contain abstractions for
+asynchronous APIs that are lighter weight (in terms of code size and RAM usage)
+than Rust's futures.
+
+This document serves as a justification for, and explanation of, the high-level
+design of `libtock_platform`. Instead of describing the various components and
+how they interact, it starts with a hello world application and extracts some of
+the functionality out into a reusable library. As we do so, we see that
+`libtock_core`'s [design considerations](DesignConsiderations.md) lead
+incrementally to a design for `libtock_platform`.
+
+In order to keep things understandable, this document makes several
+simplifications. Error handling logic is omitted, although we still structure
+the code so as to allow it. We use `unsafe` in places where we should instead
+have an additional, safe, abstraction. We use a simplified form of the Tock 2.0
+system calls, which are currently undergoing design revisions.
+
+## Hello World
+
+We start with the following example app. In order to show how `libtock_platform`
+will handle asynchronous callbacks, it is written in an asynchronous manner.
+
+```rust
+#![no_std]
+
+static GREETING: [u8; 7] = *b"Hello, ";
+static NOUN: [u8; 7] = *b"World!\n";
+static mut DONE: bool = false;
+
+// Driver, command, allow, and subscription numbers.
+const DRIVER: usize = 1;
+const WRITE_DONE: usize = 1;
+const WRITE_BUFFER: usize = 1;
+const START_WRITE: usize = 1;
+
+fn main() {
+    libtock_runtime::subscribe(DRIVER, WRITE_DONE, write_complete, 0);
+    libtock_runtime::const_allow(DRIVER, WRITE_BUFFER, &GREETING);
+    libtock_runtime::command(DRIVER, START_WRITE, GREETING.len(), 0);
+    loop {
+        libtock_runtime::yieldk();
+    }
+}
+
+extern "C" fn write_complete(bytes: usize, _: usize, _: usize, _data: usize) {
+    // Detect if this write completion is a result of writing NOUN (the
+    // second write). If so, return immediately to avoid an infinite loop.
+    unsafe {
+        if DONE { return; }
+        DONE = true;
+    }
+    // At this point, we just finished writing GREETING and need to write NOUN.
+    libtock_runtime::const_allow(DRIVER, WRITE_BUFFER, &NOUN);
+    libtock_runtime::command(DRIVER, START_WRITE, NOUN.len(), 0);
+}
+```
+
+Strictly speaking, in this app, `DONE` could be tracked by passing it as the
+`data` argument to `subscribe`. However, most applications will need to track
+more than 32 bits of persistent state -- and use more than one callback -- so
+they will need to manage persistent state themselves. To make this app
+representative of most apps, we keep the state in userspace memory.
+
+This example assumes that the `libtock_runtime` crate exposes system call
+implementations that look like the following (these are a simplification of the
+Tock 2.0 system calls):
+
+```rust
+pub fn subscribe(driver_num: usize,
+                 subscription_num: usize,
+                 callback: extern "C" fn(usize, usize, usize, usize),
+                 data: usize);
+
+pub fn const_allow(driver_num: usize, buffer_num: usize, buffer: &'static [u8]);
+pub fn command(driver_num: usize, command_num: usize, arg1: usize, arg2: usize);
+pub fn yieldk();
+```
+
+What do we already get "right" in this example? Except for the two intentional
+inefficiencies explained above (performing the write in two steps rather than 1
+and maintaining the `DONE` state in process memory), it is very efficient. It
+has only 3 global variables: `GREETING`, `NOUN`, and `DONE`. It has almost zero
+bookkeeping overhead; it fairly directly makes 8 system calls (`subscribe`,
+`const_allow`, `command`, `yieldk`, `const_allow`, `command`, `yieldk`,
+`yieldk`).
+
+What do we want to improve? It calls system calls directly from application code
+-- there should be a reusable `console` library that implements the system calls
+instead! The application shouldn't need to know what command number starts a
+write, it should just tell the console driver to do that for it.
+
+## Adding a Console Library
+
+Let's start taking some of the console-specific parts and moving them into a new
+crate. The first system call the app makes is to `subscribe` to the write done
+callback, so let's add a function to a new `libtock_console` crate that sets a
+write callback using `subscribe`:
+
+```rust
+#![no_std]
+
+const DRIVER: usize = 1;
+const WRITE_DONE: usize = 1;
+
+fn set_write_callback(callback: fn(bytes: usize, data: usize), data: usize) {
+    libtock_runtime::subscribe(DRIVER, WRITE_DONE, write_complete, data);
+    // We need to store `callback` somewhere -- where to do so?
+}
+
+extern "C" fn write_complete(bytes: usize, _: usize, _: usize, data: usize) {
+    // Hmm, how do we access the callback?
+}
+```
+
+You may notice that the code is not quite complete: `set_write_callback` takes a
+callback but doesn't store it anywhere. We don't want to store it in a global
+variable because doing so would not be zero-cost: the original app didn't need
+to store a function pointer, and we want to do this refactoring without bloating
+the app. We could pass it through `data`, but what if the client code needs to
+use `data` itself? That pattern isn't extensible: if there is another
+asynchronous layer about the console (e.g. a virtualization system), it won't
+have access to `data` to pass its callbacks through.
+
+Instead, we can pass the callback through the type system. We need a new trait
+to represent the callback. This trait won't be specific to `libtock_console`,
+and we'll later use it in unit tests -- which run on Linux, not Tock, so we'll
+put it in the `libtock_platform` crate:
+
+```rust
+pub trait FreeCallback<AsyncResponse> {
+    fn call(response: AsyncResponse);
+}
+```
+
+We call this `FreeCallback` because it represents a free function as opposed to
+a method. (This forshadows `MethodCallback`, which we will need later)
+
+The reason why we made this a shared generic trait rather than adding a
+`libtock_console::Client` trait as the Tock kernel does will be apparent later.
+
+Using this trait, we can now write `libtock_console::set_write_callback`:
+
+```rust
+#![no_std]
+
+use libtock_platform::FreeCallback;
+
+const DRIVER: usize = 1;
+const WRITE_DONE: usize = 1;
+
+pub struct WriteCompleted {
+    pub bytes: usize,
+    pub data: usize,
+}
+
+pub fn set_write_callback<Callback: FreeCallback<WriteCompleted>>(data: usize) {
+    libtock_runtime::subscribe(DRIVER, WRITE_DONE, write_complete::<Callback>, data);
+}
+
+extern "C" fn write_complete<Callback: FreeCallback<WriteCompleted>>(
+    bytes: usize, _: usize, _: usize, data: usize)
+{
+    Callback::call(WriteCompleted { bytes, data });
+}
+```
+
+To finish `libtock_console`, we also need to add `set_write_buffer` (which calls
+`allow`) and `start_write` (which calls `command`), which are much simpler:
+
+```rust
+const WRITE_BUFFER: usize = 1;
+const START_WRITE: usize = 1;
+
+pub fn set_write_buffer(buffer: &'static [u8]) {
+    libtock_runtime::const_allow(DRIVER, WRITE_BUFFER, buffer);
+}
+
+pub fn start_write(bytes: usize) {
+    libtock_runtime::command(DRIVER, START_WRITE, bytes, 0);
+}
+```
+
+We can then make use of `libtock_console` in our app as follows:
+
+```rust
+#![no_std]
+
+static GREETING: [u8; 7] = *b"Hello, ";
+static NOUN: [u8; 7] = *b"World!\n";
+static mut DONE: bool = false;
+
+fn main() {
+    libtock_console::set_write_callback::<App>(0);
+    libtock_console::set_write_buffer(&GREETING);
+    libtock_console::start_write(GREETING.len());
+    loop {
+        libtock_runtime::yieldk();
+    }
+}
+
+struct App;
+
+impl libtock_platform::FreeCallback<libtock_console::WriteCompleted> for App {
+    fn call(_response: WriteCompleted) {
+        unsafe {
+            if DONE { return; }
+            DONE = true;
+        }
+        libtock_console::set_write_buffer(&NOUN);
+        libtock_console::start_write(NOUN.len());
+    }
+}
+```
+
+Now we have a reusable console library! However, we still don't have any unit
+tests.
+
+## Adding a Fake Kernel
+
+A good unit test for the console driver would test not only the driver's
+operation with successful system calls but also also test the driver's
+error-handling logic. That is difficult to do if we test using a real Tock
+kernel in an emulator -- the real kernel has the goal of avoiding system call
+errors! Instead of using a real Tock kernel, driver unit tests should use a
+"fake kernel" that simulates the kernel's functionality while allowing errors to
+be injected.
+
+To keep this document reasonably short and understandable, we have omitted error
+handling, but we can still structure our unit tests in a manner that would allow
+a test to inject errors when error handling logic is added.
+
+To allow the console driver to work with both a real kernel and a fake kernel,
+we add a `Syscalls` trait to `libtock_platform`. When compiled into a Tock
+process binary, `Syscalls` will be implemented by a zero-sized type, which
+avoids wasting non-volatile storage space or RAM area. To avoid passing around
+references to a `Syscalls` implementation, we can pass the `Syscalls` by value
+rather than by reference (i.e. take `self` rather than `&self`). For practical
+use, this requires the `Syscalls` implementations to be `Copy`.
+
+```rust
+pub trait Syscalls: Copy {
+    fn subscribe(self, driver: usize, minor: usize,
+                 callback: extern "C" fn(usize, usize, usize, usize),
+                 data: usize);
+
+    fn const_allow(self, major: usize, minor: usize, buffer: &'static [u8]);
+    fn command(self, major: usize, miner: usize, arg1: usize, arg2: usize);
+    fn yieldk(self);
+}
+```
+
+We then implement `Syscalls` using a real Tock kernel in `libtock_runtime`:
+
+```rust
+#[derive(Clone, Copy)]
+pub struct TockSyscalls;
+
+impl libtock_platform::Syscalls for TockSyscalls {
+    /* Omitted implementation details */
+}
+```
+
+We adapt `libtock_console` to use an app-provided `Syscalls` implementation
+rather than directly calling into `libtock_runtime`:
+
+```rust
+pub fn set_write_callback<S: Syscalls, Callback: FreeCallback<WriteCompleted>>(
+    syscalls: S, data: usize)
+{
+    syscalls.subscribe(1, 1, write_complete::<Callback>, data);
+}
+
+extern "C" fn write_complete<Callback: FreeCallback<WriteCompleted>>(
+    bytes: usize, _: usize, _: usize, data: usize)
+{
+    Callback::call(WriteCompleted { bytes, data });
+}
+
+pub fn set_write_buffer<S: Syscalls>(syscalls: S, buffer: &'static [u8]) {
+    syscalls.const_allow(1, 1, buffer);
+}
+
+pub fn start_write<S: Syscalls>(syscalls: S, bytes: usize) {
+    syscalls.command(1, 1, bytes, 0);
+}
+```
+
+We'll create a new crate, `libtock_unittest`, which contains test utilities such
+as the fake Tock kernel. The fake kernel, unlike
+`libtock_runtime::TockSyscalls`, needs to maintain state, so it cannot be a
+zero-sized type. Instead of implementing `Syscalls` on the fake kernel directly,
+we implement it on a shared reference:
+
+```rust
+type RawCallback = extern "C" fn(usize, usize, usize, usize);
+
+pub struct FakeSyscalls {
+    callback_pending: core::cell::Cell<Option<usize>>,
+    output: core::cell::Cell<Vec<u8>>,
+    write_buffer: core::cell::Cell<Option<&'static [u8]>>,
+    write_callback: core::cell::Cell<Option<RawCallback>>,
+    write_data: core::cell::Cell<usize>,
+}
+
+impl FakeSyscalls {
+    pub fn new() -> Self {
+        FakeSyscalls {
+            callback_pending: Cell::new(None),
+            output: Cell::new(Vec::new()),
+            write_buffer: Cell::new(None),
+            write_callback: Cell::new(None),
+            write_data: Cell::new(0),
+        }
+    }
+
+    pub fn read_buffer(&self) -> &'static [u8] {
+        self.write_buffer.take().unwrap_or(&[])
+    }
+}
+
+impl libtock_platform::Syscalls for &FakeSyscalls {
+    fn subscribe(self, driver: usize, minor: usize, callback: RawCallback, data: usize) {
+        if driver == 1 && minor == 1 {
+            self.write_callback.set(Some(callback));
+            self.write_data.set(data);
+        }
+    }
+
+    fn const_allow(self, major: usize, minor: usize, buffer: &'static [u8]) {
+        if major == 1 && minor == 1 {
+            self.write_buffer.set(Some(buffer));
+        }
+    }
+
+    fn command(self, major: usize, minor: usize, arg1: usize, _arg2: usize) {
+        if major != 1 || minor != 1 { return; }
+        if let Some(buffer) = self.write_buffer.get() {
+            let mut output = self.output.take();
+            let bytes = core::cmp::min(arg1, buffer.len());
+            output.extend_from_slice(&buffer[..bytes]);
+            self.output.set(output);
+            self.callback_pending.set(Some(bytes));
+        }
+    }
+
+    fn yieldk(self) {
+        let bytes = match self.callback_pending.take() {
+            Some(bytes) => bytes,
+            None => return,
+        };
+        if let Some(callback) = self.write_callback.get() {
+            callback(bytes, 0, 0, self.write_data.get());
+        }
+    }
+}
+```
+
+## Adding a Synchronous Adapter
+
+We're still not ready to add unit tests to `libtock_console` yet!
+`libtock_console` is asynchronous, which is difficult to work with in a unit
+test. `libtock_core` should provide synchronous APIs for apps that do not wish
+to be fully asynchronous, so lets go ahead and implement a synchronous API. To
+avoid re-implementing synchronous APIs for every driver, let's make it work
+generically with all `libtock_core` drivers. This is where we benefit from
+making `FreeCallback` a generic trait rather than having a
+`libtock_console::Client` trait.
+
+The synchronous adapter will need to store a copy of an `AsyncResponse`, so its
+callback cannot be a free function (it needs access to `self`). Therefore, we
+add the `MethodCallback` trait to `libtock_platform`:
+
+```rust
+pub trait MethodCallback<AsyncResponse> {
+    fn call(&self, response: AsyncResponse);
+}
+```
+
+Using `MethodCallback`, we can now write `SyncAdapter`. We add `SyncAdapter` to
+a new crate, `libtock_sync`, as not all Tock apps will want it:
+
+```rust
+use libtock_platform::MethodCallback;
+
+pub struct SyncAdapter<AsyncResponse, Syscalls> {
+    response: core::cell::Cell<Option<AsyncResponse>>,
+    syscalls: Syscalls,
+}
+
+impl<AsyncResponse, Syscalls> SyncAdapter<AsyncResponse, Syscalls> {
+    pub const fn new(syscalls: Syscalls) -> SyncAdapter<AsyncResponse, Syscalls> {
+        SyncAdapter { response: core::cell::Cell::new(None), syscalls }
+    }
+}
+
+impl<AsyncResponse, Syscalls: libtock_platform::Syscalls> SyncAdapter<AsyncResponse, Syscalls> {
+    pub fn wait(&self) -> AsyncResponse {
+        loop {
+            match self.response.take() {
+                Some(response) => return response,
+                None => self.syscalls.yieldk(),
+            }
+        }
+    }
+}
+
+impl<AsyncResponse, Syscalls: libtock_platform::Syscalls>
+MethodCallback<AsyncResponse> for SyncAdapter<AsyncResponse, Syscalls> {
+    fn call(&self, response: AsyncResponse) {
+        self.response.set(Some(response));
+    }
+}
+```
+
+## Adding a Unit Test
+
+Before we write the test itself, we should add one more utility to
+`libtock_unittest`. That utility is the `test_component!` macro, which creates a
+thread-local instance of a type and provides `FreeCallback` implementations for
+every `MethodCallback` implementation the type has:
+
+```rust
+#[macro_export]
+macro_rules! test_component {
+    [$link:ident, $name:ident: $comp:ty = $init:expr] => {
+        let $name = std::boxed::Box::leak(std::boxed::Box::new($init)) as &$comp;
+        std::thread_local!(static GLOBAL: std::cell::Cell<Option<&'static $comp>>
+                           = std::cell::Cell::new(None));
+        GLOBAL.with(|g| g.set(Some($name)));
+        struct $link;
+        impl<T> libtock_platform::FreeCallback<T> for $link
+        where $comp: libtock_platform::MethodCallback<T> {
+            fn call(response: T) {
+                GLOBAL.with(|g| g.get().unwrap()).call(response);
+            }
+        }
+    };
+}
+```
+
+We can finally add a unit test to `libtock_console`:
+
+```rust
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn write() {
+        extern crate std;
+
+        use libtock_platform::MethodCallback;
+        use libtock_sync::SyncAdapter;
+        use libtock_unittest::FakeSyscalls;
+        use std::boxed::Box;
+        use std::thread_local;
+        use super::{set_write_buffer, set_write_callback, start_write, WriteCompleted};
+
+        let syscalls: &_ = Box::leak(Box::new(FakeSyscalls::new()));
+        libtock_unittest::test_component![SyncAdapterLink, sync_adapter: SyncAdapter<WriteCompleted, &'static FakeSyscalls>
+                                          = SyncAdapter::new(syscalls)];
+
+        set_write_callback::<_, SyncAdapterLink>(syscalls, 1234);
+        set_write_buffer(syscalls, b"Hello");
+        start_write(syscalls, 5);
+        let response = sync_adapter.wait();
+        assert_eq!(response.bytes, 5);
+        assert_eq!(response.data, 1234);
+        assert_eq!(syscalls.read_buffer(), b"Hello");
+    }
+}
+```
+
+## Adding `static_component!`
+
+We added `libtock_unittest::test_component!` to make it easy to set up
+components in unit tests, but we have no equivalent for apps. Our app still uses
+`unsafe` to access its `DONE` variable. Instead, lets hide that unsafety behind
+a new macro. This macro is only sound in `libtock_runtime`'s single-threaded
+environment, so we add it to `libtock_runtime` directly:
+
+```rust
+#[macro_export]
+macro_rules! static_component {
+    [$link:ident, $name:ident: $comp:ty = $init:expr] => {
+        static mut COMPONENT: $comp = $init;
+        struct $link;
+        impl<T> libtock_platform::FreeCallback<T> for $link
+        where $comp: libtock_platform::MethodCallback<T> {
+            fn call(response: T) {
+                unsafe { &COMPONENT }.call(response);
+            }
+        }
+    };
+}
+```
+
+We can now use `static_component!` in our Hello World app to instantiate the
+`App` struct:
+
+```rust
+#![no_std]
+
+static GREETING: [u8; 7] = *b"Hello, ";
+static NOUN: [u8; 7] = *b"World!\n";
+
+fn main() {
+    libtock_console::set_write_callback::<_, AppLink>(0);
+    libtock_console::set_write_buffer(&GREETING);
+    libtock_console::start_write(GREETING.len());
+    loop {
+        libtock_runtime::yieldk();
+    }
+}
+
+struct App {
+    done: core::cell::Cell<bool>
+}
+
+impl App {
+    pub const fn new() -> App {
+        App {
+            done: core::cell::Cell::new(false)
+        }
+    }
+}
+
+impl MethodCallback<WriteCompleted> for App {
+    fn call(&self, _response: WriteCompleted) {
+        if self.done.get() { return; }
+        self.done.set(true);
+        set_write_buffer(TockSyscalls, &NOUN );
+        start_write(TockSyscalls, NOUN.len() );
+    }
+}
+
+libtock_runtime::static_component![AppLink, APP: App = App::new()];
+```
+
+Now our app has no more unsafe!
+
+## Recap
+
+We wrote a Hello World application that uses Tock's console system calls and
+asynchronous callbacks. We then extracted the console system call interface into
+a reusable library, creating the `FreeCallback` trait along the way.
+
+In order to provide unit tests for the console library, we needed to create
+several new abstractions. We created `Syscalls` so that we can direct tho
+console driver's system calls to a fake kernel. We created the
+`libtock_unittest` crate which contains the fake kernel as well as a
+`test_component!` helper macro. We created `SyncAdapter` so that the unit test
+can be written in a synchronous manner -- although `SyncAdapter` is not
+testing-specific! We created `MethodCallback` because `FreeCallback` is not a
+powerful-enough abstraction on its own for `SyncAdapter`.
+
+We ended up with six Rust crates:
+
+1. `libtock_console`, which contains the console driver logic and unit test
+   code.
+2. `libtock_platform`, which provides abstractions that can be shared with other
+   drivers.
+3. `libtock_runtime`, which contains non-portable system call implementations.
+4. `libtock_sync`, which provides a synchronous interface using
+   `libtock_platform`'s traits.
+5. `libtock_unittest`, which provides a fake Tock kernel and other utilities.
+6. The hello world app itself.
diff --git a/examples-features/ctap.rs b/examples-features/ctap.rs
index 3a66eff..6ca0611 100644
--- a/examples-features/ctap.rs
+++ b/examples-features/ctap.rs
@@ -30,6 +30,8 @@
 use p256::{Scalar, SecretKey};
 use subtle::{Choice, ConditionallySelectable};
 
+libtock_core::stack_size! {0x4000}
+
 #[derive(Debug, Clone, PartialEq, Eq, Copy)]
 pub struct PrivateKey(Scalar);
 
diff --git a/examples/libmctp.rs b/examples/libmctp.rs
new file mode 100644
index 0000000..8623665
--- /dev/null
+++ b/examples/libmctp.rs
@@ -0,0 +1,105 @@
+#![no_std]
+/// This is a example of a MCTP master device
+use libmctp::smbus::{MCTPSMBusContext, VendorIDFormat};
+use libtock::i2c_master::I2cBuffer;
+use libtock::println;
+use libtock::result::TockResult;
+use libtock::syscalls;
+
+libtock_core::stack_size! {0x800}
+
+// The address of this device
+const MY_ID: u8 = 0x23;
+const DEST_ID: u8 = 0x10;
+// Support vendor defined protocol 0x7E
+const MSG_TYPES: [u8; 1] = [0x7E];
+// Specify a PCI vendor ID that we support
+const VENDOR_IDS: [libmctp::smbus::VendorIDFormat; 1] = [VendorIDFormat {
+    // PCI Vendor ID
+    format: 0x00,
+    // PCI VID
+    data: 0x1414,
+    // Extra data
+    numeric_value: 4,
+}];
+
+#[libtock::main]
+async fn main() -> TockResult<()> {
+    let mut drivers = libtock::retrieve_drivers()?;
+    drivers.console.create_console();
+    println!("Starting libmctp example");
+    let i2c_driver = drivers.i2c.init_driver()?;
+
+    // Check that I2C exists
+    if i2c_driver.check_present().is_err() {
+        println!("No I2C device, yielding");
+        loop {
+            unsafe { syscalls::raw::yieldk() };
+        }
+    }
+    println!("Found the I2C device");
+
+    println!("Setting callback");
+    let mut callback = |_, _| {
+        println!("I2C Callback");
+    };
+
+    let _subscription = i2c_driver.subscribe(&mut callback)?;
+    println!("Creating MCTP SMBus Context");
+    let ctx = MCTPSMBusContext::new(MY_ID, &MSG_TYPES, &VENDOR_IDS);
+
+    let mut buf: [u8; 32] = [0; 32];
+
+    println!("Creating the request");
+    let len = ctx
+        .get_request()
+        .get_vendor_defined_message_support(0xB, 0, &mut buf);
+
+    println!("Creating master write buffer");
+    let mut master_write_buffer = I2cBuffer::default();
+    // Skip the first byte, as that is the destination address
+    for (i, d) in buf[1..].iter().enumerate() {
+        master_write_buffer[i] = *d;
+    }
+    let dest_buffer = i2c_driver.init_buffer(&mut master_write_buffer)?;
+    println!("  done");
+
+    let _ = i2c_driver.write(DEST_ID as usize, len.unwrap());
+
+    unsafe { syscalls::raw::yieldk() };
+
+    // Read 4 bytes for the SMBus header
+    let _ = i2c_driver.read(DEST_ID as usize, 4);
+
+    unsafe { syscalls::raw::yieldk() };
+
+    // Copy into a temp buffer
+    let mut temp_buffer = [0; libtock::hmac::DEST_BUFFER_SIZE];
+    dest_buffer.read_bytes(&mut temp_buffer[1..4]);
+
+    // Determine the full length
+    let bytes = ctx.get_length(&temp_buffer).unwrap();
+
+    // Read the full packet. The slave will re-send the data, so do
+    // a full read
+    let _ = i2c_driver.read(DEST_ID as usize, bytes - 1);
+
+    unsafe { syscalls::raw::yieldk() };
+
+    // Copy in the full packet, with space for the destination address
+    dest_buffer.read_bytes(&mut temp_buffer[1..bytes - 1]);
+
+    // Set the destination address as this isn't filled in the buffer from
+    // the kernel
+    temp_buffer[0] = DEST_ID << 1;
+
+    // Decode the response
+    let ret = ctx.decode_packet(&temp_buffer[0..bytes]);
+
+    // Print the outcome of the decode
+    println!("ret: {:?}", ret);
+
+    loop {
+        unsafe { syscalls::raw::yieldk() };
+    }
+}
diff --git a/examples/ninedof.rs b/examples/ninedof.rs
new file mode 100644
index 0000000..ec0724c
--- /dev/null
+++ b/examples/ninedof.rs
@@ -0,0 +1,23 @@
+#![no_std]
+
+use libtock::println;
+use libtock::result::TockResult;
+use libtock::timer::Duration;
+
+libtock_core::stack_size! {0x800}
+
+#[libtock::main]
+async fn main() -> TockResult<()> {
+    let mut drivers = libtock::retrieve_drivers()?;
+
+    let mut timer_driver = drivers.timer.create_timer_driver();
+    let timer_driver = timer_driver.activate()?;
+    drivers.console.create_console();
+
+    loop {
+        println!("Mag:   {}\n", drivers.ninedof.read_magnetometer()?);
+        println!("Accel: {}\n", drivers.ninedof.read_acceleration()?);
+        println!("Gyro:  {}\n", drivers.ninedof.read_gyroscope()?);
+        timer_driver.sleep(Duration::from_ms(500)).await?;
+    }
+}
diff --git a/src/drivers.rs b/src/drivers.rs
index 9b74a28..8604691 100644
--- a/src/drivers.rs
+++ b/src/drivers.rs
@@ -4,6 +4,8 @@
 use crate::ctap::CtapDriverFactory;
 use crate::gpio::GpioDriverFactory;
 use crate::hmac::HmacDriverFactory;
+use crate::i2c_master::I2cDriverFactory;
+use crate::i2c_master_slave::I2cMSDriverFactory;
 use crate::leds::LedsDriverFactory;
 use crate::result::OtherError;
 use crate::result::TockError;
@@ -30,6 +32,8 @@
     pub temperature: TemperatureDriverFactory,
     pub buttons: ButtonsDriverFactory,
     pub adc: AdcDriverFactory,
+    pub i2c_ms: I2cMSDriverFactory,
+    pub i2c: I2cDriverFactory,
     pub rng: RngDriver,
     pub ble_advertising: BleAdvertisingDriverFactory,
     pub ble_scanning: BleScanningDriverFactory,
@@ -77,6 +81,8 @@
     },
     gpio: GpioDriverFactory,
     hmac: HmacDriverFactory,
+    i2c_ms: I2cMSDriverFactory,
+    i2c: I2cDriverFactory,
     temperature: TemperatureDriverFactory,
     rng: RngDriver,
     ambient_light_sensor: AmbientLightSensor,
diff --git a/src/i2c_master.rs b/src/i2c_master.rs
new file mode 100644
index 0000000..55f2ee1
--- /dev/null
+++ b/src/i2c_master.rs
@@ -0,0 +1,112 @@
+use crate::callback::CallbackSubscription;
+use crate::callback::Consumer;
+use crate::result::TockResult;
+use crate::syscalls;
+use core::marker::PhantomData;
+use core::ops::Deref;
+use core::ops::DerefMut;
+use libtock_core::shared_memory::SharedMemory;
+
+const DRIVER_NUMBER: usize = 0x20003;
+
+pub const BUFFER_SIZE: usize = 64;
+
+mod command_nr {
+    pub const CHECK_PRESENT: usize = 0;
+    pub const WRITE: usize = 1;
+    pub const READ: usize = 2;
+    pub const WRITE_READ: usize = 3;
+}
+
+mod subscribe_nr {
+    pub const SUBSCRIBE_CALLBACK: usize = 1;
+}
+
+mod allow_nr {
+    pub const BUFFER: usize = 1;
+}
+
+#[non_exhaustive]
+pub struct I2cDriverFactory;
+
+impl I2cDriverFactory {
+    pub fn init_driver(&mut self) -> TockResult<I2cDriver> {
+        let i2c = I2cDriver {
+            lifetime: PhantomData,
+        };
+        Ok(i2c)
+    }
+}
+
+struct I2cEventConsumer;
+
+impl<CB: FnMut(usize, usize)> Consumer<CB> for I2cEventConsumer {
+    fn consume(callback: &mut CB, _: usize, _: usize, _: usize) {
+        callback(0, 0);
+    }
+}
+
+pub struct I2cBuffer {
+    buffer: [u8; BUFFER_SIZE],
+}
+
+impl Default for I2cBuffer {
+    fn default() -> Self {
+        I2cBuffer {
+            buffer: [0; BUFFER_SIZE],
+        }
+    }
+}
+
+impl Deref for I2cBuffer {
+    type Target = [u8; BUFFER_SIZE];
+
+    fn deref(&self) -> &Self::Target {
+        &self.buffer
+    }
+}
+
+impl DerefMut for I2cBuffer {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.buffer
+    }
+}
+
+pub struct I2cDriver<'a> {
+    lifetime: PhantomData<&'a ()>,
+}
+
+impl<'a> I2cDriver<'a> {
+    pub fn init_buffer(&self, buffer: &'a mut I2cBuffer) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::BUFFER, &mut buffer.buffer).map_err(Into::into)
+    }
+
+    pub fn subscribe<CB: FnMut(usize, usize)>(
+        &self,
+        callback: &'a mut CB,
+    ) -> TockResult<CallbackSubscription> {
+        syscalls::subscribe::<I2cEventConsumer, _>(
+            DRIVER_NUMBER,
+            subscribe_nr::SUBSCRIBE_CALLBACK,
+            callback,
+        )
+        .map_err(Into::into)
+    }
+
+    pub fn check_present(&self) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::CHECK_PRESENT, 0, 0).map_err(Into::into)
+    }
+
+    pub fn write(&self, address: usize, length: usize) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::WRITE, address, length).map_err(Into::into)
+    }
+
+    pub fn read(&self, address: usize, length: usize) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::READ, address, length).map_err(Into::into)
+    }
+
+    pub fn write_read(&self, address: usize, length: usize) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::WRITE_READ, address, length)
+            .map_err(Into::into)
+    }
+}
diff --git a/src/i2c_master_slave.rs b/src/i2c_master_slave.rs
new file mode 100644
index 0000000..0e3cce6
--- /dev/null
+++ b/src/i2c_master_slave.rs
@@ -0,0 +1,264 @@
+use crate::callback::CallbackSubscription;
+use crate::callback::Consumer;
+use crate::result::TockResult;
+use crate::syscalls;
+use core::marker::PhantomData;
+use core::ops::Deref;
+use core::ops::DerefMut;
+use libtock_core::shared_memory::SharedMemory;
+
+const DRIVER_NUMBER: usize = 0x20006;
+
+pub const MASTER_BUFFER_SIZE: usize = 32;
+pub const SLAVE_BUFFER_SIZE: usize = 32;
+
+mod command_nr {
+    pub const CHECK_PRESENT: usize = 0;
+    pub const MASTER_WRITE: usize = 1;
+    pub const MASTER_READ: usize = 2;
+    pub const SLAVE_LISTEN: usize = 3;
+    pub const SLAVE_ENABLE_READ: usize = 4;
+    pub const SLAVE_STOP_LISTEN: usize = 5;
+    pub const SLAVE_SET_ADDRESS: usize = 6;
+    pub const MASTER_WRITE_READ: usize = 7;
+}
+
+mod subscribe_nr {
+    pub const SUBSCRIBE_CALLBACK: usize = 0;
+}
+
+mod allow_nr {
+    pub const MASTER_WRIE: usize = 0;
+    pub const MASTER_READ: usize = 1;
+    pub const SLAVE_READ: usize = 2;
+    pub const SLAVE_WRITE: usize = 2;
+}
+
+#[non_exhaustive]
+pub struct I2cMSDriverFactory;
+
+impl I2cMSDriverFactory {
+    pub fn init_driver(&mut self) -> TockResult<I2cMSDriver> {
+        let i2c_ms = I2cMSDriver {
+            lifetime: PhantomData,
+        };
+        Ok(i2c_ms)
+    }
+}
+
+struct I2cMSEventConsumer;
+
+impl<CB: FnMut(usize, usize)> Consumer<CB> for I2cMSEventConsumer {
+    fn consume(callback: &mut CB, _: usize, _: usize, _: usize) {
+        callback(0, 0);
+    }
+}
+
+pub struct I2cMSMasterWriteBuffer {
+    buffer: [u8; MASTER_BUFFER_SIZE],
+}
+
+impl Default for I2cMSMasterWriteBuffer {
+    fn default() -> Self {
+        I2cMSMasterWriteBuffer {
+            buffer: [0; MASTER_BUFFER_SIZE],
+        }
+    }
+}
+
+impl Deref for I2cMSMasterWriteBuffer {
+    type Target = [u8; MASTER_BUFFER_SIZE];
+
+    fn deref(&self) -> &Self::Target {
+        &self.buffer
+    }
+}
+
+impl DerefMut for I2cMSMasterWriteBuffer {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.buffer
+    }
+}
+
+pub struct I2cMSMasterReadBuffer {
+    buffer: [u8; MASTER_BUFFER_SIZE],
+}
+
+impl Default for I2cMSMasterReadBuffer {
+    fn default() -> Self {
+        I2cMSMasterReadBuffer {
+            buffer: [0; MASTER_BUFFER_SIZE],
+        }
+    }
+}
+
+impl Deref for I2cMSMasterReadBuffer {
+    type Target = [u8; MASTER_BUFFER_SIZE];
+
+    fn deref(&self) -> &Self::Target {
+        &self.buffer
+    }
+}
+
+impl DerefMut for I2cMSMasterReadBuffer {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.buffer
+    }
+}
+
+pub struct I2cMSSlaveReadBuffer {
+    buffer: [u8; SLAVE_BUFFER_SIZE],
+}
+
+impl Default for I2cMSSlaveReadBuffer {
+    fn default() -> Self {
+        I2cMSSlaveReadBuffer {
+            buffer: [0; SLAVE_BUFFER_SIZE],
+        }
+    }
+}
+
+impl Deref for I2cMSSlaveReadBuffer {
+    type Target = [u8; SLAVE_BUFFER_SIZE];
+
+    fn deref(&self) -> &Self::Target {
+        &self.buffer
+    }
+}
+
+impl DerefMut for I2cMSSlaveReadBuffer {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.buffer
+    }
+}
+
+pub struct I2cMSSlaveWriteBuffer {
+    buffer: [u8; SLAVE_BUFFER_SIZE],
+}
+
+impl Default for I2cMSSlaveWriteBuffer {
+    fn default() -> Self {
+        I2cMSSlaveWriteBuffer {
+            buffer: [0; SLAVE_BUFFER_SIZE],
+        }
+    }
+}
+
+impl Deref for I2cMSSlaveWriteBuffer {
+    type Target = [u8; SLAVE_BUFFER_SIZE];
+
+    fn deref(&self) -> &Self::Target {
+        &self.buffer
+    }
+}
+
+impl DerefMut for I2cMSSlaveWriteBuffer {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.buffer
+    }
+}
+
+pub struct I2cMSDriver<'a> {
+    lifetime: PhantomData<&'a ()>,
+}
+
+impl<'a> I2cMSDriver<'a> {
+    pub fn init_master_write_buffer(
+        &self,
+        buffer: &'a mut I2cMSMasterWriteBuffer,
+    ) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::MASTER_WRIE, &mut buffer.buffer)
+            .map_err(Into::into)
+    }
+
+    pub fn init_master_read_buffer(
+        &self,
+        buffer: &'a mut I2cMSMasterReadBuffer,
+    ) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::MASTER_READ, &mut buffer.buffer)
+            .map_err(Into::into)
+    }
+
+    pub fn init_slave_read_buffer(
+        &self,
+        buffer: &'a mut I2cMSSlaveReadBuffer,
+    ) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::SLAVE_READ, &mut buffer.buffer).map_err(Into::into)
+    }
+
+    pub fn init_slave_write_buffer(
+        &self,
+        buffer: &'a mut I2cMSSlaveWriteBuffer,
+    ) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::SLAVE_WRITE, &mut buffer.buffer)
+            .map_err(Into::into)
+    }
+
+    pub fn subscribe<CB: FnMut(usize, usize)>(
+        &self,
+        callback: &'a mut CB,
+    ) -> TockResult<CallbackSubscription> {
+        syscalls::subscribe::<I2cMSEventConsumer, _>(
+            DRIVER_NUMBER,
+            subscribe_nr::SUBSCRIBE_CALLBACK,
+            callback,
+        )
+        .map_err(Into::into)
+    }
+
+    pub fn check_present(&self) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::CHECK_PRESENT, 0, 0).map_err(Into::into)
+    }
+
+    pub fn master_write(&self, address: usize, length: usize) -> TockResult<usize> {
+        syscalls::command(
+            DRIVER_NUMBER,
+            command_nr::MASTER_WRITE,
+            address & 0xFFFF | length << 16,
+            0,
+        )
+        .map_err(Into::into)
+    }
+
+    pub fn master_read(&self, address: usize, length: usize) -> TockResult<usize> {
+        syscalls::command(
+            DRIVER_NUMBER,
+            command_nr::MASTER_READ,
+            address & 0xFFFF | length << 16,
+            0,
+        )
+        .map_err(Into::into)
+    }
+
+    pub fn slave_listen(&self) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::SLAVE_LISTEN, 0, 0).map_err(Into::into)
+    }
+
+    pub fn slave_enable_read(&self) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::SLAVE_ENABLE_READ, 0, 0).map_err(Into::into)
+    }
+
+    pub fn slave_stop_listen(&self) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::SLAVE_STOP_LISTEN, 0, 0).map_err(Into::into)
+    }
+
+    pub fn slave_set_address(&self, address: usize) -> TockResult<usize> {
+        syscalls::command(DRIVER_NUMBER, command_nr::SLAVE_SET_ADDRESS, address, 0)
+            .map_err(Into::into)
+    }
+
+    pub fn master_write_read(
+        &self,
+        address: usize,
+        read_length: usize,
+        write_length: usize,
+    ) -> TockResult<usize> {
+        syscalls::command(
+            DRIVER_NUMBER,
+            command_nr::MASTER_WRITE_READ,
+            address & 0xFF | read_length << 8 | write_length << 16,
+            0,
+        )
+        .map_err(Into::into)
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 96d2720..6f5be5a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -13,6 +13,8 @@
 pub mod futures;
 pub mod gpio;
 pub mod hmac;
+pub mod i2c_master;
+pub mod i2c_master_slave;
 pub mod leds;
 pub mod result;
 pub mod rng;