Merge #147

147: Use the absolute addresses for calculation in entry assembly r=labbott a=labbott

Because RISC-V does not currently have full relocation support,
the addresses in the crt0 header are the exact addreses, not
offsets. This means we don't need to offset by the stack top again
to get the app heap start. Adjust the assembly to account for this.

Co-authored-by: Laura Abbott <laura@labbott.name>
diff --git a/.travis.yml b/.travis.yml
index 651ad97..dae25d0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,7 +7,7 @@
 
 language: rust
 rust:
-  - nightly-2019-11-06
+  - nightly-2020-01-16
 
 os:
   - linux
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 68c463d..1caeca5 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -45,6 +45,7 @@
 [      OK ] Dynamic dispatch
 [      OK ] Formatting
 [      OK ] Heap
+[      OK ] Drivers only instantiable once
 [      OK ] Callbacks
 [      OK ] GPIO initialization
 [      OK ] GPIO activation
diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs
index 6f51b9f..9804e29 100644
--- a/codegen/src/lib.rs
+++ b/codegen/src/lib.rs
@@ -5,7 +5,6 @@
 use proc_macro::TokenStream;
 
 use quote::quote;
-use syn;
 use syn::Error;
 use syn::ItemFn;
 
diff --git a/examples-alloc/libtock_test.rs b/examples-alloc/libtock_test.rs
index d764af3..26cccb4 100644
--- a/examples-alloc/libtock_test.rs
+++ b/examples-alloc/libtock_test.rs
@@ -46,6 +46,7 @@
     test.dynamic_dispatch()?;
     test.formatting()?;
     test.heap()?;
+    test.drivers_only_instantiable_once()?;
     test.callbacks(timer).await?;
     test.gpio(gpio)?;
     Ok(())
@@ -100,6 +101,13 @@
         self.check_if_true(string == "foobar", "Heap")
     }
 
+    fn drivers_only_instantiable_once(&mut self) -> TockResult<()> {
+        self.check_if_true(
+            libtock::retrieve_drivers().is_err(),
+            "Drivers only instantiable once",
+        )
+    }
+
     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/flash.sh b/flash.sh
index a67312c..b241a7a 100755
--- a/flash.sh
+++ b/flash.sh
@@ -4,8 +4,36 @@
 
 artifact="$(basename $1)"
 rust_target_folder="$(readlink -f $(dirname $1)/../..)"
+
+case "${PLATFORM}" in
+    "nrf52"|"nrf52840")
+        tockloader_flags="--jlink --arch cortex-m4 --board nrf52dk --jtag-device nrf52"
+        binary_name=cortex-m4.elf
+        tockload=y
+        ;;
+    "hail")
+        tockloader_flags=""
+        binary_name=cortex-m4.elf
+        tockload=y
+        ;;
+    "riscv32")
+        tockloader_flags=""
+        binary_name=rv32imac.elf
+        tockload=n
+        ;;
+    "opentitan")
+        tockloader_flags=""
+        binary_name=rv32imc.elf
+        tockload=n
+        ;;
+    *)
+        echo "Unknown platform \"${PLATFORM}\""
+        exit 1
+        ;;
+esac
+
 libtock_target_path="${rust_target_folder}/tab/${PLATFORM}/${artifact}"
-elf_file_name="${libtock_target_path}/cortex-m4.elf"
+elf_file_name="${libtock_target_path}/${binary_name}"
 tab_file_name="${libtock_target_path}.tab"
 
 mkdir -p "${libtock_target_path}"
@@ -13,18 +41,10 @@
 
 elf2tab -n "${artifact}" -o "${tab_file_name}" "${elf_file_name}" --stack 2048 --app-heap 1024 --kernel-heap 1024 --protected-region-size=64
 
-case "${PLATFORM}" in
-    "nrf52"|"nrf52840")
-        tockloader_flags="--jlink --arch cortex-m4 --board nrf52dk --jtag-device nrf52"
-        ;;
-    "hail")
-        tockloader_flags=""
-        ;;
-    *)
-        echo "Tockloader flags unknown for platform \"${PLATFORM}\""
-        exit 1
-        ;;
-esac
+if [ $tockload == "n" ]; then
+	echo "Skipping flashing for platform \"${PLATFORM}\""
+	exit 0
+fi
 
 tockloader uninstall ${tockloader_flags} || true
 tockloader install ${tockloader_flags} "${tab_file_name}"
diff --git a/layout_generic.ld b/layout_generic.ld
index 6b96ee5..35b10f4 100644
--- a/layout_generic.ld
+++ b/layout_generic.ld
@@ -86,7 +86,7 @@
     } > FLASH =0xFF
 
     /* Application stack */
-    .stack :
+    .stack (NOLOAD) :
     {
         . = . + STACK_SIZE;
 
diff --git a/layout_opentitan.ld b/layout_opentitan.ld
index ab475fc..db48eef 100644
--- a/layout_opentitan.ld
+++ b/layout_opentitan.ld
@@ -1,9 +1,16 @@
 /* Layout for the RISC-V 32 boards, used by the examples in this repository. */
 
 MEMORY {
-  /* The TBF header region is 32 bytes (0x20) */
-  FLASH (rx) : ORIGIN = 0x20030020, LENGTH = 32M
-  SRAM (rwx) : ORIGIN = 0x10000000, LENGTH = 512K
+  /*
+   * The TBF header can change in size so use 0x40 combined with
+   * --protected-region-size with elf2tab to cover a header upto that
+   * size.
+   *
+   * Note that the SRAM address may need to be changed depending on
+   * the kernel binary, check for the actual address of APP_MEMORY!
+   */
+  FLASH (rx) : ORIGIN = 0x20030040, LENGTH = 32M
+  SRAM (rwx) : ORIGIN = 0x10002800, LENGTH = 512K
 }
 
 /*
diff --git a/layout_riscv32.ld b/layout_riscv32.ld
index e3aba2c..df7d4b6 100644
--- a/layout_riscv32.ld
+++ b/layout_riscv32.ld
@@ -1,9 +1,16 @@
 /* Layout for the RISC-V 32 boards, used by the examples in this repository. */
 
 MEMORY {
-  /* The TBF header region is 32 bytes (0x20) */
-  FLASH (rx) : ORIGIN = 0x20430020, LENGTH = 32M
-  SRAM (rwx) : ORIGIN = 0x80000000, LENGTH = 512K
+  /*
+   * The TBF header can change in size so use 0x40 combined with
+   * --protected-region-size with elf2tab to cover a header upto that
+   * size.
+   *
+   * Note that the SRAM address may need to be changed depending on
+   * the kernel binary, check for the actual address of APP_MEMORY!
+   */
+  FLASH (rx) : ORIGIN = 0x20430040, LENGTH = 32M
+  SRAM (rwx) : ORIGIN = 0x80002400, LENGTH = 512K
 }
 
 /*
diff --git a/run_all_checks.sh b/run_all_checks.sh
index c445608..3dde5ff 100755
--- a/run_all_checks.sh
+++ b/run_all_checks.sh
@@ -5,6 +5,6 @@
 export PLATFORM=nrf52 # The specific platform doesn't matter for tests
 
 cargo fmt --all -- --check
-cargo test --workspace
 cargo clippy --workspace --all-targets
+cargo test --workspace
 ./build_examples.sh
diff --git a/rust-toolchain b/rust-toolchain
index 22e9048..20d9cda 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1 +1 @@
-nightly-2019-11-06
+nightly-2020-01-16
diff --git a/src/drivers.rs b/src/drivers.rs
index a8e1e98..4e7eff8 100644
--- a/src/drivers.rs
+++ b/src/drivers.rs
@@ -38,9 +38,15 @@
 
 /// Retrieve [Drivers] struct. Returns struct only once.
 pub fn retrieve_drivers() -> TockResult<Drivers> {
-    match unsafe { DRIVERS_SINGLETON.take() } {
-        Some(drivers) => Ok(drivers),
-        None => Err(TockError::Other(OtherError::DriverAlreadyTaken)),
+    static mut DRIVER_TAKEN: bool = false;
+
+    unsafe {
+        if DRIVER_TAKEN {
+            Err(TockError::Other(OtherError::DriverAlreadyTaken))
+        } else {
+            DRIVER_TAKEN = true;
+            Ok(retrieve_drivers_unsafe())
+        }
     }
 }
 
@@ -73,24 +79,3 @@
     humidity_sensor: HumiditySensor,
     ninedof: NinedofDriver,
 };
-
-static mut DRIVERS_SINGLETON: Option<Drivers> = Some(DRIVERS);
-
-#[cfg(test)]
-mod test {
-    use super::*;
-
-    #[test]
-    pub fn can_be_retrieved_once() {
-        reset_drivers_singleton();
-
-        assert!(retrieve_drivers().is_ok());
-        assert!(retrieve_drivers().is_err());
-    }
-
-    fn reset_drivers_singleton() {
-        unsafe {
-            DRIVERS_SINGLETON = Some(DRIVERS);
-        };
-    }
-}
diff --git a/src/lang_items.rs b/src/lang_items.rs
index b8731a2..9c301eb 100644
--- a/src/lang_items.rs
+++ b/src/lang_items.rs
@@ -27,11 +27,12 @@
 use core::panic::PanicInfo;
 
 #[lang = "start"]
-extern "C" fn start<T>(main: fn() -> T, _argc: isize, _argv: *const *const u8)
+extern "C" fn start<T>(main: fn() -> T, _argc: isize, _argv: *const *const u8) -> bool
 where
     T: Termination,
 {
     main().check_result();
+    true // Need to return anything sized. Otherwise, a linker error pops up. (See https://github.com/tock/libtock-rs/issues/138)
 }
 
 #[lang = "termination"]