Merge branch 'master' into allowed
diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml
new file mode 100644
index 0000000..3617c11
--- /dev/null
+++ b/.github/workflows/artifacts.yml
@@ -0,0 +1,53 @@
+name: Artifacts
+on: [push]
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v2
+
+      - name: Install Rust toolchain
+        uses: actions-rs/toolchain@v1.0.6
+        with:
+          profile: minimal
+
+      - name: Install dependencies
+        run: |
+          rustup target add thumbv7em-none-eabi
+          rustup target add riscv32imac-unknown-none-elf
+          rustup target add riscv32imc-unknown-none-elf
+          cargo install elf2tab --version 0.4.0
+
+      - name: Build Hello World
+        run: |
+          FEATURES="alloc" make flash-apollo3  EXAMPLE=hello_world -j2
+          FEATURES="alloc" make flash-hail  EXAMPLE=hello_world -j2
+          FEATURES="alloc" make flash-nucleo_f429zi  EXAMPLE=hello_world -j2
+          FEATURES="alloc" make flash-nucleo_f446re  EXAMPLE=hello_world -j2
+          FEATURES="alloc" make flash-nrf52840  EXAMPLE=hello_world -j2
+          FEATURES="alloc" make flash-opentitan  EXAMPLE=hello_world -j2
+          FEATURES="alloc" make flash-hifive1  EXAMPLE=hello_world -j2
+          FEATURES="alloc" make flash-nrf52  EXAMPLE=hello_world -j2
+
+      - name: Build libtock-test
+        run: |
+          FEATURES="alloc" make flash-apollo3  EXAMPLE=libtock_test -j2
+          FEATURES="alloc" make flash-hail  EXAMPLE=libtock_test -j2
+          FEATURES="alloc" make flash-nucleo_f429zi  EXAMPLE=libtock_test -j2
+          FEATURES="alloc" make flash-nucleo_f446re  EXAMPLE=libtock_test -j2
+          FEATURES="alloc" make flash-nrf52840  EXAMPLE=libtock_test -j2
+          FEATURES="alloc" make flash-opentitan  EXAMPLE=libtock_test -j2
+          FEATURES="alloc" make flash-hifive1  EXAMPLE=libtock_test -j2
+          FEATURES="alloc" make flash-nrf52  EXAMPLE=libtock_test -j2
+
+      - name: Build extra tests
+        run: |
+          FEATURES="alloc" make flash-opentitan  EXAMPLE=hmac -j2
+
+      - name: Archive artifacts
+        uses: actions/upload-artifact@v2
+        with:
+          name: libtock-rs examples
+          path: target/*/tab/*/*/*.tbf
diff --git a/Cargo.toml b/Cargo.toml
index cb8e160..9ac3f91 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,7 +9,11 @@
 alloc = ["libtock_core/alloc"]
 custom_panic_handler = ["libtock_core/custom_panic_handler"]
 custom_alloc_error_handler = ["libtock_core/custom_alloc_error_handler"]
+# In the QEMU-emulated HiFive1 target, we do not have connected GPIO pins or a
+# working timer interface. These features allow the test's user to disable these
+# tests in environments where they will not pass.
 __internal_disable_gpio_in_integration_test = []
+__internal_disable_timer_in_integration_test = []
 
 [dependencies]
 libtock_core = { path = "core" }
diff --git a/Makefile b/Makefile
index 0227e3d..d47b155 100644
--- a/Makefile
+++ b/Makefile
@@ -68,7 +68,8 @@
 .PHONY: test-qemu-hifive
 test-qemu-hifive: kernel-hifive
 	PLATFORM=hifive1 cargo rrv32imac --example libtock_test --features=alloc \
-		--features=__internal_disable_gpio_in_integration_test
+		--features=__internal_disable_gpio_in_integration_test \
+		--features=__internal_disable_timer_in_integration_test
 	cargo run -p test_runner
 
 .PHONY: examples
diff --git a/core/platform/src/error_code.rs b/core/platform/src/error_code.rs
new file mode 100644
index 0000000..ca1c657
--- /dev/null
+++ b/core/platform/src/error_code.rs
@@ -0,0 +1,25 @@
+/// An error code returned by the kernel. Tock's system calls return errors as a
+/// negative `isize`. This wraps the isize, and is useful for adding type safety
+/// to APIs.
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct ErrorCode {
+    // Note: value *should* always be negative, but we do not *verify* that so
+    // unsafe code cannot rely on value being negative.
+    value: isize,
+}
+
+impl ErrorCode {
+    // Converts the given isize into an ErrorCode. Note that the isize should be
+    // negative, although that is not verified to reduce code size. We don't
+    // implement From because not every isize converts sensibly to an ErrorCode.
+    pub fn new(value: isize) -> ErrorCode {
+        ErrorCode { value }
+    }
+}
+
+impl Into<isize> for ErrorCode {
+    fn into(self) -> isize {
+        self.value
+    }
+}
diff --git a/core/platform/src/lib.rs b/core/platform/src/lib.rs
index 5cc7a1f..11543ed 100644
--- a/core/platform/src/lib.rs
+++ b/core/platform/src/lib.rs
@@ -9,5 +9,7 @@
 //      unit test environments.
 
 mod allows;
+mod error_code;
 
 pub use allows::{AllowReadable, Allowed};
+pub use error_code::ErrorCode;
diff --git a/examples-features/libtock_test.rs b/examples-features/libtock_test.rs
index 9a64e67..ac1e541 100644
--- a/examples-features/libtock_test.rs
+++ b/examples-features/libtock_test.rs
@@ -51,6 +51,7 @@
     test.formatting()?;
     test.heap()?;
     test.drivers_only_instantiable_once()?;
+    #[cfg(not(feature = "__internal_disable_timer_in_integration_test"))]
     test.callbacks(timer).await?;
     #[cfg(not(feature = "__internal_disable_gpio_in_integration_test"))]
     test.gpio(gpio)?;
@@ -113,6 +114,10 @@
         )
     }
 
+    #[cfg_attr(
+        feature = "__internal_disable_timer_in_integration_test",
+        allow(dead_code)
+    )]
     async fn callbacks(&mut self, timer_context: &mut DriverContext) -> TockResult<()> {
         let mut callback_hit = false;
         let mut with_callback = timer_context.with_callback(|_, _| callback_hit = true);
diff --git a/test_runner/src/main.rs b/test_runner/src/main.rs
index e297e8e..0bea1cf 100644
--- a/test_runner/src/main.rs
+++ b/test_runner/src/main.rs
@@ -14,7 +14,7 @@
 async fn perform_tests() -> Result<(), Box<dyn std::error::Error>> {
     let mut failed_tests = Vec::new();
 
-    let tests = Command::new("tock/tools/qemu/riscv32-softmmu/qemu-system-riscv32")
+    let tests = Command::new("tock/tools/qemu-build/riscv32-softmmu/qemu-system-riscv32")
         .arg("-M")
         .arg("sifive_e,revb=true")
         .arg("-kernel")
diff --git a/tock b/tock
index 957a890..6e38588 160000
--- a/tock
+++ b/tock
@@ -1 +1 @@
-Subproject commit 957a890e97550db00ca38407d93d2896d2724ec5
+Subproject commit 6e38588c73dbd78d274c00ae7fb7789b78cf6856
diff --git a/tools/flash.sh b/tools/flash.sh
index cee7571..56ffb88 100755
--- a/tools/flash.sh
+++ b/tools/flash.sh
@@ -70,5 +70,10 @@
 	exit 0
 fi
 
+if ! [ -x "$(command -v tockloader)" ]; then
+    echo "Skipping flashing as tockloader isn't installed"
+    exit 0
+fi
+
 tockloader uninstall ${tockloader_flags} || true
 tockloader install ${tockloader_flags} "${tab_file_name}"