diff --git a/.github/workflows/boards_build.yml b/.github/workflows/boards_build.yml index 50a29d5..d798495 100644 --- a/.github/workflows/boards_build.yml +++ b/.github/workflows/boards_build.yml @@ -16,6 +16,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 + with: + submodules: "true" - uses: actions-rs/toolchain@v1 with: target: thumbv7em-none-eabi diff --git a/.github/workflows/cargo_audit.yml b/.github/workflows/cargo_audit.yml index 25e8ff2..4ff71b0 100644 --- a/.github/workflows/cargo_audit.yml +++ b/.github/workflows/cargo_audit.yml @@ -9,6 +9,8 @@ jobs: if: github.repository == 'google/OpenSK' steps: - uses: actions/checkout@v2 + with: + submodules: "true" - uses: actions-rs/toolchain@v1 with: target: thumbv7em-none-eabi diff --git a/.github/workflows/cargo_check.yml b/.github/workflows/cargo_check.yml index 07c1c0a..6676e16 100644 --- a/.github/workflows/cargo_check.yml +++ b/.github/workflows/cargo_check.yml @@ -17,6 +17,8 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 + with: + submodules: "true" - uses: actions-rs/toolchain@v1 with: target: thumbv7em-none-eabi diff --git a/.github/workflows/cargo_fmt.yml b/.github/workflows/cargo_fmt.yml index 72dec08..59757a4 100644 --- a/.github/workflows/cargo_fmt.yml +++ b/.github/workflows/cargo_fmt.yml @@ -18,6 +18,8 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 + with: + submodules: "true" - uses: actions-rs/toolchain@v1 with: target: thumbv7em-none-eabi diff --git a/.github/workflows/cbor_test.yml b/.github/workflows/cbor_test.yml index 84625c8..a8f1b01 100644 --- a/.github/workflows/cbor_test.yml +++ b/.github/workflows/cbor_test.yml @@ -12,6 +12,8 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 + with: + submodules: "true" - uses: actions-rs/toolchain@v1 with: target: thumbv7em-none-eabi diff --git a/.github/workflows/crypto_test.yml b/.github/workflows/crypto_test.yml index a879661..1740280 100644 --- a/.github/workflows/crypto_test.yml +++ b/.github/workflows/crypto_test.yml @@ -14,6 +14,8 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 + with: + submodules: "true" - uses: actions-rs/toolchain@v1 with: target: thumbv7em-none-eabi diff --git a/.github/workflows/opensk_build.yml b/.github/workflows/opensk_build.yml index f51637d..cb2fb6f 100644 --- a/.github/workflows/opensk_build.yml +++ b/.github/workflows/opensk_build.yml @@ -13,6 +13,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 + with: + submodules: "true" - uses: actions-rs/toolchain@v1 with: target: thumbv7em-none-eabi diff --git a/.github/workflows/opensk_test.yml b/.github/workflows/opensk_test.yml index ece41e7..588dab6 100644 --- a/.github/workflows/opensk_test.yml +++ b/.github/workflows/opensk_test.yml @@ -14,6 +14,8 @@ jobs: steps: - uses: actions/checkout@v2 + with: + submodules: "true" - uses: actions-rs/toolchain@v1 with: target: thumbv7em-none-eabi diff --git a/.github/workflows/reproducible.yml b/.github/workflows/reproducible.yml index 4489a93..66df550 100644 --- a/.github/workflows/reproducible.yml +++ b/.github/workflows/reproducible.yml @@ -14,6 +14,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 + with: + submodules: "true" - uses: actions-rs/toolchain@v1 with: target: thumbv7em-none-eabi diff --git a/Cargo.toml b/Cargo.toml index 4c2d16c..7b75429 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,9 @@ license = "Apache-2.0" edition = "2018" [dependencies] -libtock = { path = "third_party/libtock-rs" } +libtock_core = { path = "third_party/libtock-rs/core" } +libtock_drivers = { path = "third_party/libtock-drivers" } +lang_items = { path = "third_party/lang-items" } cbor = { path = "libraries/cbor" } crypto = { path = "libraries/crypto" } byteorder = { version = "1", default-features = false } @@ -18,12 +20,12 @@ arrayref = "0.3.6" subtle = { version = "2.2", default-features = false, features = ["nightly"] } [features] -debug_allocations = ["libtock/debug_allocations"] -debug_ctap = ["crypto/derive_debug"] -panic_console = ["libtock/panic_console"] -std = ["cbor/std", "crypto/std", "crypto/derive_debug"] +debug_allocations = ["lang_items/debug_allocations"] +debug_ctap = ["crypto/derive_debug", "libtock_drivers/debug_ctap"] +panic_console = ["lang_items/panic_console"] +std = ["cbor/std", "crypto/std", "crypto/derive_debug", "lang_items/std"] ram_storage = [] -verbose = ["debug_ctap"] +verbose = ["debug_ctap", "libtock_drivers/verbose_usb"] with_ctap1 = ["crypto/with_ctap1"] with_ctap2_1 = [] diff --git a/deploy.py b/deploy.py index d9661c0..d956911 100755 --- a/deploy.py +++ b/deploy.py @@ -373,6 +373,7 @@ class OpenSKInstaller: ] env = os.environ.copy() env["RUSTFLAGS"] = " ".join(rust_flags) + env["APP_HEAP_SIZE"] = str(APP_HEAP_SIZE) command = [ "cargo", "build", "--release", "--target={}".format(props.arch), @@ -893,8 +894,22 @@ if __name__ == "__main__": dest="application", action="store_const", const="crypto_bench", - help=("Compiles and installs the crypto_bench example that tests " + help=("Compiles and installs the crypto_bench example that benchmarks " "the performance of the cryptographic algorithms on the board.")) + apps_group.add_argument( + "--panic_test", + dest="application", + action="store_const", + const="panic_test", + help=("Compiles and installs the panic_test example that immediately " + "triggers a panic.")) + apps_group.add_argument( + "--oom_test", + dest="application", + action="store_const", + const="oom_test", + help=("Compiles and installs the oom_test example that tests the " + "allocator until an out-of-memory error occurs.")) main_parser.set_defaults(features=["with_ctap1"]) diff --git a/examples/crypto_bench.rs b/examples/crypto_bench.rs index 95a82d2..ff92ba2 100644 --- a/examples/crypto_bench.rs +++ b/examples/crypto_bench.rs @@ -17,24 +17,26 @@ #[macro_use] extern crate alloc; extern crate crypto; -extern crate libtock; +extern crate lang_items; +extern crate libtock_drivers; use alloc::vec::Vec; use core::fmt::Write; use crypto::{ aes256, cbc, ecdsa, rng256, sha256, Decrypt16BytesBlock, Encrypt16BytesBlock, Hash256, }; -use libtock::console::Console; -use libtock::timer; -use libtock::timer::Timer; -use libtock::timer::Timestamp; +use libtock_drivers::console::Console; +use libtock_drivers::result::FlexUnwrap; +use libtock_drivers::timer; +use libtock_drivers::timer::Timer; +use libtock_drivers::timer::Timestamp; fn main() { let mut console = Console::new(); // Setup the timer with a dummy callback (we only care about reading the current time, but the // API forces us to set an alarm callback too). let mut with_callback = timer::with_callback(|_, _| {}); - let timer = with_callback.init().unwrap(); + let timer = with_callback.init().flex_unwrap(); let mut rng = rng256::TockRng256 {}; @@ -158,11 +160,11 @@ where writeln!(console, "----------------------------------------").unwrap(); let mut count = 1; for _ in 0..30 { - let start = Timestamp::::from_clock_value(timer.get_current_clock()); + let start = Timestamp::::from_clock_value(timer.get_current_clock().flex_unwrap()); for _ in 0..count { f(); } - let end = Timestamp::::from_clock_value(timer.get_current_clock()); + let end = Timestamp::::from_clock_value(timer.get_current_clock().flex_unwrap()); let elapsed = (end - start).ms(); writeln!( console, @@ -172,6 +174,7 @@ where elapsed / (count as f64) ) .unwrap(); + console.flush(); if elapsed > 1000.0 { break; } diff --git a/examples/oom_test.rs b/examples/oom_test.rs new file mode 100644 index 0000000..665993b --- /dev/null +++ b/examples/oom_test.rs @@ -0,0 +1,35 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![no_std] + +extern crate alloc; +extern crate crypto; +extern crate lang_items; +extern crate libtock_drivers; + +use alloc::vec::Vec; +use core::fmt::Write; +use libtock_drivers::console::Console; + +fn main() { + writeln!(Console::new(), "****************************************").unwrap(); + for i in 0.. { + writeln!(Console::new(), "Allocating {} bytes...", 1 << i).unwrap(); + let x: Vec = Vec::with_capacity(1 << i); + writeln!(Console::new(), "Allocated!").unwrap(); + drop(x); + writeln!(Console::new(), "Dropped!").unwrap(); + } +} diff --git a/examples/panic_test.rs b/examples/panic_test.rs new file mode 100644 index 0000000..71c70b0 --- /dev/null +++ b/examples/panic_test.rs @@ -0,0 +1,24 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![no_std] + +extern crate alloc; +extern crate crypto; +extern crate lang_items; +extern crate libtock_drivers; + +fn main() { + panic!("Bye world!") +} diff --git a/libraries/crypto/Cargo.toml b/libraries/crypto/Cargo.toml index 40a2f2f..ead1294 100644 --- a/libraries/crypto/Cargo.toml +++ b/libraries/crypto/Cargo.toml @@ -10,10 +10,10 @@ license = "Apache-2.0" edition = "2018" [dependencies] -libtock = { path = "../../third_party/libtock-rs" } +libtock_drivers = { path = "../../third_party/libtock-drivers" } cbor = { path = "../cbor" } arrayref = "0.3.6" -subtle = { version = "2.2", default-features = false, features = ["nightly"] } +subtle = { version = "2.2.3", default-features = false, features = ["nightly"] } byteorder = { version = "1", default-features = false } hex = { version = "0.3.2", default-features = false, optional = true } ring = { version = "0.16.11", optional = true } diff --git a/libraries/crypto/src/lib.rs b/libraries/crypto/src/lib.rs index bfc129e..031cfa3 100644 --- a/libraries/crypto/src/lib.rs +++ b/libraries/crypto/src/lib.rs @@ -21,7 +21,6 @@ extern crate subtle; #[macro_use] extern crate arrayref; extern crate byteorder; -extern crate libtock; #[macro_use] extern crate cbor; diff --git a/libraries/crypto/src/rng256.rs b/libraries/crypto/src/rng256.rs index 572e21e..9657bf2 100644 --- a/libraries/crypto/src/rng256.rs +++ b/libraries/crypto/src/rng256.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use libtock::rng; +use libtock_drivers::rng; // Lightweight RNG trait to generate uniformly distributed 256 bits. pub trait Rng256 { diff --git a/patches/libtock-rs/01-linked_list_allocator.patch b/patches/libtock-rs/01-linked_list_allocator.patch deleted file mode 100644 index 97a3695..0000000 --- a/patches/libtock-rs/01-linked_list_allocator.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/Cargo.toml b/Cargo.toml -index 29d9b79..30081f3 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -6,7 +6,7 @@ license = "MIT/Apache-2.0" - edition = "2018" - - [dependencies] --linked_list_allocator = "0.6.4" -+linked_list_allocator = "0.6.6" - - [dev-dependencies] - corepack = { version = "0.4.0", default-features = false, features = ["alloc"] } diff --git a/patches/libtock-rs/02-panic_console.patch b/patches/libtock-rs/02-panic_console.patch deleted file mode 100644 index 01d37e4..0000000 --- a/patches/libtock-rs/02-panic_console.patch +++ /dev/null @@ -1,81 +0,0 @@ -diff --git a/Cargo.toml b/Cargo.toml ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -7,6 +7,9 @@ - - [dependencies] - linked_list_allocator = "0.6.6" -+ -+[features] -+panic_console = [] - - [dev-dependencies] - corepack = { version = "0.4.0", default-features = false, features = ["alloc"] } -diff --git a/src/lang_items.rs b/src/lang_items.rs -index ab2c945..deef73b 100644 ---- a/src/lang_items.rs -+++ b/src/lang_items.rs -@@ -18,10 +18,14 @@ - //! `rustc_main`. That's covered by the `_start` function in the root of this - //! crate. - -+#[cfg(feature = "panic_console")] -+use crate::console::Console; - use crate::led; - use crate::timer; - use crate::timer::Duration; - use core::alloc::Layout; -+#[cfg(feature = "panic_console")] -+use core::fmt::Write; - use core::panic::PanicInfo; - - #[lang = "start"] -@@ -42,11 +46,7 @@ - } - } - --#[panic_handler] --fn panic_handler(_info: &PanicInfo) -> ! { -+fn flash_all_leds() -> ! { -- // Signal a panic using the LowLevelDebug capsule (if available). -- super::debug::low_level_status_code(1); -- - // Flash all LEDs (if available). - loop { - for led in led::all() { -@@ -60,6 +59,34 @@ - } - } - -+#[cfg(feature = "panic_console")] -+#[panic_handler] -+fn panic_handler(info: &PanicInfo) -> ! { -+ // Signal a panic using the LowLevelDebug capsule (if available). -+ super::debug::low_level_status_code(1); -+ -+ let mut console = Console::new(); -+ writeln!(console, "{}", info).ok(); -+ // Force the kernel to report the panic cause, by reading an invalid address. -+ // The memory protection unit should be setup by the Tock kernel to prevent apps from accessing -+ // address zero. -+ unsafe { -+ core::ptr::read_volatile(0 as *const usize); -+ } -+ // We still flash the LEDs in case for some reason the previous line didn't cause a crash in -+ // the kernel. -+ flash_all_leds(); -+} -+ -+#[cfg(not(feature = "panic_console"))] -+#[panic_handler] -+fn panic_handler(_info: &PanicInfo) -> ! { -+ // Signal a panic using the LowLevelDebug capsule (if available). -+ super::debug::low_level_status_code(1); -+ -+ flash_all_leds(); -+} -+ - #[alloc_error_handler] - fn cycle_leds(_: Layout) -> ! { - loop { - diff --git a/patches/libtock-rs/03-timer.patch b/patches/libtock-rs/03-timer.patch deleted file mode 100644 index 7b8a5d9..0000000 --- a/patches/libtock-rs/03-timer.patch +++ /dev/null @@ -1,72 +0,0 @@ -diff --git a/src/timer.rs b/src/timer.rs -index ae60b07..2e7d544 100644 ---- a/src/timer.rs -+++ b/src/timer.rs -@@ -178,7 +178,7 @@ impl<'a> Timer<'a> { - } - } - --#[derive(Copy, Clone, Debug)] -+#[derive(Copy, Clone, Debug, PartialEq)] - pub struct ClockFrequency { - hz: usize, - } -@@ -196,21 +196,53 @@ pub struct ClockValue { - } - - impl ClockValue { -+ pub const fn new(num_ticks: isize, clock_hz: usize) -> ClockValue { -+ ClockValue { -+ num_ticks, -+ clock_frequency: ClockFrequency { hz: clock_hz }, -+ } -+ } -+ - pub fn num_ticks(&self) -> isize { - self.num_ticks - } - -+ // Computes (value * factor) / divisor, even when value * factor >= isize::MAX. -+ fn scale_int(value: isize, factor: isize, divisor: isize) -> isize { -+ // As long as isize is not i64, this should be fine. If not, this is an alternative: -+ // factor * (value / divisor) + ((value % divisor) * factor) / divisor -+ ((value as i64 * factor as i64) / divisor as i64) as isize -+ } -+ - pub fn ms(&self) -> isize { -- if self.num_ticks.abs() < isize::MAX / 1000 { -- (1000 * self.num_ticks) / self.clock_frequency.hz() as isize -- } else { -- 1000 * (self.num_ticks / self.clock_frequency.hz() as isize) -- } -+ ClockValue::scale_int(self.num_ticks, 1000, self.clock_frequency.hz() as isize) - } - - pub fn ms_f64(&self) -> f64 { - 1000.0 * (self.num_ticks as f64) / (self.clock_frequency.hz() as f64) - } -+ -+ pub fn wrapping_add(self, duration: Duration) -> ClockValue { -+ // This is a precision preserving formula for scaling an isize. -+ let duration_ticks = -+ ClockValue::scale_int(duration.ms, self.clock_frequency.hz() as isize, 1000); -+ ClockValue { -+ num_ticks: self.num_ticks.wrapping_add(duration_ticks), -+ clock_frequency: self.clock_frequency, -+ } -+ } -+ -+ pub fn wrapping_sub(self, other: ClockValue) -> Option> { -+ if self.clock_frequency == other.clock_frequency { -+ let clock_duration = ClockValue { -+ num_ticks: self.num_ticks - other.num_ticks, -+ clock_frequency: self.clock_frequency, -+ }; -+ Some(Duration::from_ms(clock_duration.ms())) -+ } else { -+ None -+ } -+ } - } - - pub struct Alarm { diff --git a/patches/libtock-rs/04-public_syscalls.patch b/patches/libtock-rs/04-public_syscalls.patch deleted file mode 100644 index 109b6cb..0000000 --- a/patches/libtock-rs/04-public_syscalls.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/src/lib.rs b/src/lib.rs -index 1d4f26b..c1483e9 100644 ---- a/src/lib.rs -+++ b/src/lib.rs -@@ -42,7 +42,7 @@ pub mod syscalls; - - #[cfg(not(any(target_arch = "arm", target_arch = "riscv32")))] - #[path = "syscalls_mock.rs"] --mod syscalls; -+pub mod syscalls; - - #[cfg(any(target_arch = "arm", target_arch = "riscv32"))] - #[global_allocator] diff --git a/patches/libtock-rs/05-bigger_heap.patch b/patches/libtock-rs/05-bigger_heap.patch deleted file mode 100644 index 098737d..0000000 --- a/patches/libtock-rs/05-bigger_heap.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/src/entry_point.rs b/src/entry_point.rs -index a24958c..e907e33 100644 ---- a/src/entry_point.rs -+++ b/src/entry_point.rs -@@ -348,7 +348,7 @@ pub unsafe extern "C" fn rust_start(app_start: usize, stacktop: usize, app_heap_ - // Heap size is set using `elf2tab` with `--app-heap` option, which is - // currently at 1024. If you change the `elf2tab` heap size, make sure to - // make the corresponding change here. -- const HEAP_SIZE: usize = 1024; -+ const HEAP_SIZE: usize = 90000; - - // we could have also bss_end for app_heap_start - let app_heap_start = app_heap_break; diff --git a/patches/libtock-rs/06-no_spin_allocator.patch b/patches/libtock-rs/06-no_spin_allocator.patch deleted file mode 100644 index ec61cf0..0000000 --- a/patches/libtock-rs/06-no_spin_allocator.patch +++ /dev/null @@ -1,77 +0,0 @@ -diff --git a/Cargo.toml b/Cargo.toml -index 844e424..386a9ed 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -6,7 +6,7 @@ license = "MIT/Apache-2.0" - edition = "2018" - - [dependencies] --linked_list_allocator = "0.6.6" -+linked_list_allocator = { version = "0.6.6", default-features = false } - - [features] - panic_console = [] -diff --git a/src/entry_point.rs b/src/entry_point.rs -index 15e1d03..2fe5c40 100644 ---- a/src/entry_point.rs -+++ b/src/entry_point.rs -@@ -1,8 +1,10 @@ - use crate::memop; - use crate::syscalls; --use crate::ALLOCATOR; -+use core::alloc::{GlobalAlloc, Layout}; - use core::intrinsics; - use core::ptr; -+use core::ptr::NonNull; -+use linked_list_allocator::Heap; - - // _start and rust_start are the first two procedures executed when a Tock - // application starts. _start is invoked directly by the Tock kernel; it -@@ -357,7 +359,7 @@ pub unsafe extern "C" fn rust_start(app_start: usize, stacktop: usize, app_heap_ - // Tell the kernel the new app heap break. - memop::set_brk(app_heap_end as *const u8); - -- ALLOCATOR.lock().init(app_heap_start, HEAP_SIZE); -+ HEAP.init(app_heap_start, HEAP_SIZE); - - main(0, ptr::null()); - -@@ -365,3 +367,23 @@ pub unsafe extern "C" fn rust_start(app_start: usize, stacktop: usize, app_heap_ - syscalls::yieldk(); - } - } -+ -+#[cfg(any(target_arch = "arm", target_arch = "riscv32"))] -+#[global_allocator] -+static ALLOCATOR: TockAllocator = TockAllocator; -+ -+static mut HEAP: Heap = Heap::empty(); -+ -+struct TockAllocator; -+ -+unsafe impl GlobalAlloc for TockAllocator { -+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 { -+ HEAP.allocate_first_fit(layout) -+ .ok() -+ .map_or(0 as *mut u8, |allocation| allocation.as_ptr()) -+ } -+ -+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { -+ HEAP.deallocate(NonNull::new_unchecked(ptr), layout) -+ } -+} -diff --git a/src/lib.rs b/src/lib.rs -index c9001bf..2f9c1c0 100644 ---- a/src/lib.rs -+++ b/src/lib.rs -@@ -44,10 +44,6 @@ pub mod syscalls; - #[path = "syscalls_mock.rs"] - pub mod syscalls; - --#[cfg(any(target_arch = "arm", target_arch = "riscv32"))] --#[global_allocator] --static ALLOCATOR: linked_list_allocator::LockedHeap = linked_list_allocator::LockedHeap::empty(); -- - // Dummy structure to force importing the panic_handler and other no_std elements when nothing else - // is imported. - pub struct LibTock; diff --git a/patches/libtock-rs/07-debug_allocations.patch b/patches/libtock-rs/07-debug_allocations.patch deleted file mode 100644 index 13d2eaf..0000000 --- a/patches/libtock-rs/07-debug_allocations.patch +++ /dev/null @@ -1,103 +0,0 @@ -diff --git a/Cargo.toml b/Cargo.toml -index 386a9ed..af3c5db 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -10,6 +10,7 @@ linked_list_allocator = { version = "0.6.6", default-features = false } - - [features] - panic_console = [] -+debug_allocations = [] - - [dev-dependencies] - corepack = { version = "0.4.0", default-features = false, features = ["alloc"] } -diff --git a/src/entry_point.rs b/src/entry_point.rs -index 2fe5c40..545d163 100644 ---- a/src/entry_point.rs -+++ b/src/entry_point.rs -@@ -368,22 +368,82 @@ pub unsafe extern "C" fn rust_start(app_start: usize, stacktop: usize, app_heap_ - } - } - -+#[cfg(feature = "debug_allocations")] -+use core::fmt::Write; -+#[cfg(feature = "debug_allocations")] -+use core::sync::atomic; -+#[cfg(feature = "debug_allocations")] -+use core::sync::atomic::AtomicUsize; -+ - #[cfg(any(target_arch = "arm", target_arch = "riscv32"))] - #[global_allocator] --static ALLOCATOR: TockAllocator = TockAllocator; -+static ALLOCATOR: TockAllocator = TockAllocator::new(); - - static mut HEAP: Heap = Heap::empty(); - --struct TockAllocator; -+// With the "debug_allocations" feature, we use `AtomicUsize` to store the -+// statistics because: -+// - it is `Sync`, so we can use it in a static object (the allocator), -+// - it implements interior mutability, so we can use it in the allocator -+// methods (that take an immutable `&self` reference). -+struct TockAllocator { -+ #[cfg(feature = "debug_allocations")] -+ count: AtomicUsize, -+ #[cfg(feature = "debug_allocations")] -+ size: AtomicUsize, -+} -+ -+impl TockAllocator { -+ const fn new() -> TockAllocator { -+ TockAllocator { -+ #[cfg(feature = "debug_allocations")] -+ count: AtomicUsize::new(0), -+ #[cfg(feature = "debug_allocations")] -+ size: AtomicUsize::new(0), -+ } -+ } -+} - - unsafe impl GlobalAlloc for TockAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { -- HEAP.allocate_first_fit(layout) -+ let ptr = HEAP -+ .allocate_first_fit(layout) - .ok() -- .map_or(0 as *mut u8, |allocation| allocation.as_ptr()) -+ .map_or(ptr::null_mut(), NonNull::as_ptr); -+ #[cfg(feature = "debug_allocations")] -+ { -+ self.count.fetch_add(1, atomic::Ordering::SeqCst); -+ self.size.fetch_add(layout.size(), atomic::Ordering::SeqCst); -+ writeln!( -+ crate::console::Console::new(), -+ "alloc[{}, {}] = {:?} ({} ptrs, {} bytes)", -+ layout.size(), -+ layout.align(), -+ ptr, -+ self.count.load(atomic::Ordering::SeqCst), -+ self.size.load(atomic::Ordering::SeqCst) -+ ) -+ .unwrap(); -+ } -+ ptr - } - - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { -+ #[cfg(feature = "debug_allocations")] -+ { -+ self.count.fetch_sub(1, atomic::Ordering::SeqCst); -+ self.size.fetch_sub(layout.size(), atomic::Ordering::SeqCst); -+ writeln!( -+ crate::console::Console::new(), -+ "dealloc[{}, {}] = {:?} ({} ptrs, {} bytes)", -+ layout.size(), -+ layout.align(), -+ ptr, -+ self.count.load(atomic::Ordering::SeqCst), -+ self.size.load(atomic::Ordering::SeqCst) -+ ) -+ .unwrap(); -+ } - HEAP.deallocate(NonNull::new_unchecked(ptr), layout) - } - } diff --git a/patches/libtock-rs/08-buffered-console.patch b/patches/libtock-rs/08-buffered-console.patch deleted file mode 100644 index fec6963..0000000 --- a/patches/libtock-rs/08-buffered-console.patch +++ /dev/null @@ -1,98 +0,0 @@ -diff --git a/src/console.rs b/src/console.rs -index ecd7ad1..ae1b826 100644 ---- a/src/console.rs -+++ b/src/console.rs -@@ -16,33 +16,63 @@ mod allow_nr { - pub const SHARE_BUFFER: usize = 1; - } - -+const BUFFER_SIZE: usize = 1024; -+ - pub struct Console { -- allow_buffer: [u8; 64], -+ allow_buffer: [u8; BUFFER_SIZE], -+ count_pending: usize, - } - - impl Console { - pub fn new() -> Console { - Console { -- allow_buffer: [0; 64], -+ allow_buffer: [0; BUFFER_SIZE], -+ count_pending: 0, - } - } - -+ fn is_empty(&self) -> bool { -+ self.count_pending == 0 -+ } -+ -+ fn is_full(&self) -> bool { -+ self.allow_buffer.len() == self.count_pending -+ } -+ -+ fn available_len(&self) -> usize { -+ self.allow_buffer.len() - self.count_pending -+ } -+ - pub fn write>(&mut self, text: S) { - let mut not_written_yet = text.as_ref(); - while !not_written_yet.is_empty() { -- let num_bytes_to_print = self.allow_buffer.len().min(not_written_yet.len()); -- self.allow_buffer[..num_bytes_to_print] -+ let num_bytes_to_print = self.available_len().min(not_written_yet.len()); -+ self.allow_buffer[self.count_pending..(self.count_pending + num_bytes_to_print)] - .copy_from_slice(¬_written_yet[..num_bytes_to_print]); -- self.flush(num_bytes_to_print); -+ self.count_pending += num_bytes_to_print; -+ -+ if self.is_full() { -+ self.flush(); -+ } -+ - not_written_yet = ¬_written_yet[num_bytes_to_print..]; - } - } - -- fn flush(&mut self, num_bytes_to_print: usize) { -+ pub fn flush(&mut self) { -+ if self.is_empty() { -+ // Don't trigger any syscall if the buffer is empty. -+ return; -+ } -+ -+ let count = self.count_pending; -+ // Clear the buffer even in case of error, to avoid an infinite loop. -+ self.count_pending = 0; -+ - let result = syscalls::allow( - DRIVER_NUMBER, - allow_nr::SHARE_BUFFER, -- &mut self.allow_buffer[..num_bytes_to_print], -+ &mut self.allow_buffer[..count], - ); - if result.is_err() { - return; -@@ -59,8 +89,7 @@ impl Console { - return; - } - -- let result_code = -- unsafe { syscalls::command(DRIVER_NUMBER, command_nr::WRITE, num_bytes_to_print, 0) }; -+ let result_code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::WRITE, count, 0) }; - if result_code < 0 { - return; - } -@@ -69,6 +98,12 @@ impl Console { - } - } - -+impl Drop for Console { -+ fn drop(&mut self) { -+ self.flush(); -+ } -+} -+ - impl fmt::Write for Console { - fn write_str(&mut self, string: &str) -> Result<(), fmt::Error> { - self.write(string); diff --git a/reproducible/reference_binaries_macos-10.15.sha256sum b/reproducible/reference_binaries_macos-10.15.sha256sum index d2311bf..cd7cf02 100644 --- a/reproducible/reference_binaries_macos-10.15.sha256sum +++ b/reproducible/reference_binaries_macos-10.15.sha256sum @@ -1,9 +1,9 @@ -0b54df6d548849e24d67b9b022ca09cb33c51f078ce85d0c9c4635ffc69902e1 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin -9726082139399889fde1d5aa4005596eecd60726201e02a522aa25870109d252 target/nrf52840dk_merged.hex -052eec0ae526038352b9f7573468d0cf7fb5ec331d4dc1a2df75fdbd514ea5ca third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin -5cf5599d001a9f7be80132b3e83c2a5e28e9c6a70b79058b266a23527e754d41 target/nrf52840_dongle_merged.hex -908d7f4f40936d968b91ab6e19b2406612fe8c2c273d9c0b71ef1f55116780e0 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin -69524a8538ae65637dfaf8709b9cfb4730858dea56d96ae304163d6f5d0dabe0 target/nrf52840_dongle_dfu_merged.hex -34ecbecaebf1188277f2310fe769c8c60310d8576493242712854deb4ba1036e third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin -276bec775183524eb7dbbd107416d90dbadb853771deaa8f49f1baf9d0f216e1 target/nrf52840_mdk_dfu_merged.hex -8e7ad6778dbb86e13613a30487c41b9086f7fe55dc0db234968eb52750b8a94c target/tab/ctap2.tab +91a98f475cb3042dd5184598a8292edb2a414df8d967a35c8f2295826b5a161b third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin +120028d4e4266aff8123db544d99d5d67594c1e7bebdfe3e4172bd20716fb34b target/nrf52840dk_merged.hex +a5943c5311158b0f99370246d37782eb9b12fc36c56387eadb6587a3a4fe8fd5 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin +0aae44b66ed6c8a134809446e95efb3d276182823db20755d0b45baa7cfd6efd target/nrf52840_dongle_merged.hex +663297e3e29b9e2a972b68cea1592aaf965d797242579bb5bca09cd73cdfb637 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin +fadd8a863c8828ceb18a8e3224fedc32261befb5af3b04dfd7cc3d9bccc6cc64 target/nrf52840_dongle_dfu_merged.hex +162a05d056aafc16d4868d5c3aa10518e41299dddd60608f96954dc9cf964cd3 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin +2495d4aa2f86da9308b1024490513272294e3cb2652d366a56de13dcd92bc1d1 target/nrf52840_mdk_dfu_merged.hex +e0ed5715b4df3850d6899e158fef24052cc056f641083950094afbf0aa8c5cd5 target/tab/ctap2.tab diff --git a/reproducible/reference_binaries_ubuntu-18.04.sha256sum b/reproducible/reference_binaries_ubuntu-18.04.sha256sum index d54ddc1..9330561 100644 --- a/reproducible/reference_binaries_ubuntu-18.04.sha256sum +++ b/reproducible/reference_binaries_ubuntu-18.04.sha256sum @@ -1,9 +1,9 @@ -29382e72d0f3c6a72ce9517211952ff29ea270193d7f0ddc48ca69009ee29925 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin -f48b98125b06b81ba3c62657bfd9aee9c2b81a1307173d2a73f110f7cdb29513 target/nrf52840dk_merged.hex -30f239390ae9bef0825731e4c82d40470fc5e9bded2bf0d942e92dbb5d4faba1 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin -97f0998c06c622c92a4504b6f416f548e5b47a1a9b592c6a98ca338450990419 target/nrf52840_dongle_merged.hex -e3acf15d5ae3a22aecff6cc58db5fc311f538f47328d348b7ad7db7f9ab5e72c third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin -bf5a5745d76eeeb38908f6179d5ba07ac2578dd1b55f95e9440cdf893d850ffc target/nrf52840_dongle_dfu_merged.hex -cae312a26a513ada6c198fdc59b2bba3860c51726b817a9fd17a4331ee12c882 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin -6b2da0ff3af55e7fe86177a8d795baab3752a59c55bf0bb0af2fcfec1c983e57 target/nrf52840_mdk_dfu_merged.hex -26706e2fefe6894ffbaa0681454aeda24c69d8aeb5289f8c0e4428cdc7c4fc59 target/tab/ctap2.tab +3feb5d29a3d669107b460a00391440be4ebc5e50461f9ef3248714f4f99c070e third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin +3c4dde09e8e6082a15bbf9d9eedd12de63f70d85c240292aea246f2d83c54f07 target/nrf52840dk_merged.hex +8eebe1c1dfe22003466c2570b3735c54c58ae91b8168582ad363ab79c9230a15 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin +a5e4ce40777ca4de31377bd60dddb92da172afef6ddcbc48c58f43b77809ac26 target/nrf52840_dongle_merged.hex +779d77071d1e629f92210ac313e230bcaea6d77c710210c1ac4b40f8085cdad7 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin +ccacb03f5140bb334843a42d40e9ad3ec56bbf76fdac023bd8d1c9457dc5c228 target/nrf52840_dongle_dfu_merged.hex +f466490d6498f6c06c7c4a717eb437ba2fb06d1985532c23f145d38b9daa8259 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin +a165294acddacd95747d064aff4ecf37654bfa107df49151dbbaf25907468ab4 target/nrf52840_mdk_dfu_merged.hex +54074445657b1842d8c005bb94897c6a60d76c6bfc9b6f9cecac930d3485b930 target/tab/ctap2.tab diff --git a/reproducible/reference_elf2tab_macos-10.15.txt b/reproducible/reference_elf2tab_macos-10.15.txt index c5fc225..0b20950 100644 --- a/reproducible/reference_elf2tab_macos-10.15.txt +++ b/reproducible/reference_elf2tab_macos-10.15.txt @@ -1,12 +1,12 @@ ======================================== Board: nrf52840dk ---------------------------------------- -Min RAM size from sections in ELF: 16 bytes +Min RAM size from sections in ELF: 20 bytes Number of writeable flash regions: 0 Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes. Entry point is in .text section - Adding .text section. Offset: 128 (0x80). Length: 179332 (0x2bc84) bytes. - Adding .stack section. Offset: 179460 (0x2bd04). Length: 16384 (0x4000) bytes. + Adding .text section. Offset: 128 (0x80). Length: 187792 (0x2dd90) bytes. + Adding .stack section. Offset: 187920 (0x2de10). Length: 16384 (0x4000) bytes. Searching for .rel.X sections to add. TBF Header: version: 2 0x2 @@ -16,16 +16,16 @@ TBF Header: init_fn_offset: 85 0x55 protected_size: 20 0x14 - minimum_ram_size: 107424 0x1A3A0 + minimum_ram_size: 107428 0x1A3A4 ======================================== Board: nrf52840_dongle ---------------------------------------- -Min RAM size from sections in ELF: 16 bytes +Min RAM size from sections in ELF: 20 bytes Number of writeable flash regions: 0 Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes. Entry point is in .text section - Adding .text section. Offset: 128 (0x80). Length: 179332 (0x2bc84) bytes. - Adding .stack section. Offset: 179460 (0x2bd04). Length: 16384 (0x4000) bytes. + Adding .text section. Offset: 128 (0x80). Length: 187792 (0x2dd90) bytes. + Adding .stack section. Offset: 187920 (0x2de10). Length: 16384 (0x4000) bytes. Searching for .rel.X sections to add. TBF Header: version: 2 0x2 @@ -35,16 +35,16 @@ TBF Header: init_fn_offset: 85 0x55 protected_size: 20 0x14 - minimum_ram_size: 107424 0x1A3A0 + minimum_ram_size: 107428 0x1A3A4 ======================================== Board: nrf52840_dongle_dfu ---------------------------------------- -Min RAM size from sections in ELF: 16 bytes +Min RAM size from sections in ELF: 20 bytes Number of writeable flash regions: 0 Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes. Entry point is in .text section - Adding .text section. Offset: 128 (0x80). Length: 179332 (0x2bc84) bytes. - Adding .stack section. Offset: 179460 (0x2bd04). Length: 16384 (0x4000) bytes. + Adding .text section. Offset: 128 (0x80). Length: 187792 (0x2dd90) bytes. + Adding .stack section. Offset: 187920 (0x2de10). Length: 16384 (0x4000) bytes. Searching for .rel.X sections to add. TBF Header: version: 2 0x2 @@ -54,16 +54,16 @@ TBF Header: init_fn_offset: 85 0x55 protected_size: 20 0x14 - minimum_ram_size: 107424 0x1A3A0 + minimum_ram_size: 107428 0x1A3A4 ======================================== Board: nrf52840_mdk_dfu ---------------------------------------- -Min RAM size from sections in ELF: 16 bytes +Min RAM size from sections in ELF: 20 bytes Number of writeable flash regions: 0 Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes. Entry point is in .text section - Adding .text section. Offset: 128 (0x80). Length: 179332 (0x2bc84) bytes. - Adding .stack section. Offset: 179460 (0x2bd04). Length: 16384 (0x4000) bytes. + Adding .text section. Offset: 128 (0x80). Length: 187792 (0x2dd90) bytes. + Adding .stack section. Offset: 187920 (0x2de10). Length: 16384 (0x4000) bytes. Searching for .rel.X sections to add. TBF Header: version: 2 0x2 @@ -73,4 +73,4 @@ TBF Header: init_fn_offset: 85 0x55 protected_size: 20 0x14 - minimum_ram_size: 107424 0x1A3A0 + minimum_ram_size: 107428 0x1A3A4 diff --git a/reproducible/reference_elf2tab_ubuntu-18.04.txt b/reproducible/reference_elf2tab_ubuntu-18.04.txt index 8a50445..6a155d5 100644 --- a/reproducible/reference_elf2tab_ubuntu-18.04.txt +++ b/reproducible/reference_elf2tab_ubuntu-18.04.txt @@ -1,12 +1,12 @@ ======================================== Board: nrf52840dk ---------------------------------------- -Min RAM size from sections in ELF: 16 bytes +Min RAM size from sections in ELF: 20 bytes Number of writeable flash regions: 0 Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes. Entry point is in .text section - Adding .text section. Offset: 128 (0x80). Length: 178788 (0x2ba64) bytes. - Adding .stack section. Offset: 178916 (0x2bae4). Length: 16384 (0x4000) bytes. + Adding .text section. Offset: 128 (0x80). Length: 187752 (0x2dd68) bytes. + Adding .stack section. Offset: 187880 (0x2dde8). Length: 16384 (0x4000) bytes. Searching for .rel.X sections to add. TBF Header: version: 2 0x2 @@ -16,16 +16,16 @@ TBF Header: init_fn_offset: 85 0x55 protected_size: 20 0x14 - minimum_ram_size: 107424 0x1A3A0 + minimum_ram_size: 107428 0x1A3A4 ======================================== Board: nrf52840_dongle ---------------------------------------- -Min RAM size from sections in ELF: 16 bytes +Min RAM size from sections in ELF: 20 bytes Number of writeable flash regions: 0 Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes. Entry point is in .text section - Adding .text section. Offset: 128 (0x80). Length: 178788 (0x2ba64) bytes. - Adding .stack section. Offset: 178916 (0x2bae4). Length: 16384 (0x4000) bytes. + Adding .text section. Offset: 128 (0x80). Length: 187752 (0x2dd68) bytes. + Adding .stack section. Offset: 187880 (0x2dde8). Length: 16384 (0x4000) bytes. Searching for .rel.X sections to add. TBF Header: version: 2 0x2 @@ -35,16 +35,16 @@ TBF Header: init_fn_offset: 85 0x55 protected_size: 20 0x14 - minimum_ram_size: 107424 0x1A3A0 + minimum_ram_size: 107428 0x1A3A4 ======================================== Board: nrf52840_dongle_dfu ---------------------------------------- -Min RAM size from sections in ELF: 16 bytes +Min RAM size from sections in ELF: 20 bytes Number of writeable flash regions: 0 Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes. Entry point is in .text section - Adding .text section. Offset: 128 (0x80). Length: 178788 (0x2ba64) bytes. - Adding .stack section. Offset: 178916 (0x2bae4). Length: 16384 (0x4000) bytes. + Adding .text section. Offset: 128 (0x80). Length: 187752 (0x2dd68) bytes. + Adding .stack section. Offset: 187880 (0x2dde8). Length: 16384 (0x4000) bytes. Searching for .rel.X sections to add. TBF Header: version: 2 0x2 @@ -54,16 +54,16 @@ TBF Header: init_fn_offset: 85 0x55 protected_size: 20 0x14 - minimum_ram_size: 107424 0x1A3A0 + minimum_ram_size: 107428 0x1A3A4 ======================================== Board: nrf52840_mdk_dfu ---------------------------------------- -Min RAM size from sections in ELF: 16 bytes +Min RAM size from sections in ELF: 20 bytes Number of writeable flash regions: 0 Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes. Entry point is in .text section - Adding .text section. Offset: 128 (0x80). Length: 178788 (0x2ba64) bytes. - Adding .stack section. Offset: 178916 (0x2bae4). Length: 16384 (0x4000) bytes. + Adding .text section. Offset: 128 (0x80). Length: 187752 (0x2dd68) bytes. + Adding .stack section. Offset: 187880 (0x2dde8). Length: 16384 (0x4000) bytes. Searching for .rel.X sections to add. TBF Header: version: 2 0x2 @@ -73,4 +73,4 @@ TBF Header: init_fn_offset: 85 0x55 protected_size: 20 0x14 - minimum_ram_size: 107424 0x1A3A0 + minimum_ram_size: 107428 0x1A3A4 diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index 605c8f9..0000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly-2020-02-03 diff --git a/rust-toolchain b/rust-toolchain new file mode 120000 index 0000000..c2036a8 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +third_party/libtock-rs/rust-toolchain \ No newline at end of file diff --git a/setup-submodules.sh b/setup-submodules.sh new file mode 100755 index 0000000..e767b78 --- /dev/null +++ b/setup-submodules.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Ensure the script doesn't fail on Github workflows +export TERM=${TERM:-vt100} +done_text="$(tput bold)DONE.$(tput sgr0)" + +set -e + +# Ensure the submodules are pulled and up-to-date +git submodule update --init + +patch_conflict_detected () { + cat </dev/null @@ -30,57 +33,6 @@ check_command () { check_command rustup " Follow the steps under https://rustup.rs/ to install it." check_command pip3 -# Ensure the submodules are pulled and up-to-date -git submodule update --init - -patch_conflict_detected () { - cat < StorageResult { - let code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::GET_INFO, nr, arg) }; - if code < 0 { - Err(StorageError::KernelError { code }) - } else { - Ok(code as usize) - } + let code = syscalls::command(DRIVER_NUMBER, command_nr::GET_INFO, nr, arg); + code.map_err(|e| StorageError::KernelError { + code: e.return_code, + }) } fn memop(nr: u32, arg: usize) -> StorageResult { - let code = unsafe { syscalls::memop(nr, arg) }; + let code = unsafe { syscalls::raw::memop(nr, arg) }; if code < 0 { Err(StorageError::KernelError { code }) } else { @@ -153,8 +151,9 @@ impl Storage for SyscallStorage { return Err(StorageError::NotAligned); } let ptr = self.read_slice(index, value.len())?.as_ptr() as usize; + let code = unsafe { - syscalls::allow_ptr( + syscalls::raw::allow( DRIVER_NUMBER, allow_nr::WRITE_SLICE, // We rely on the driver not writing to the slice. This should use read-only allow @@ -166,11 +165,14 @@ impl Storage for SyscallStorage { if code < 0 { return Err(StorageError::KernelError { code }); } - let code = - unsafe { syscalls::command(DRIVER_NUMBER, command_nr::WRITE_SLICE, ptr, value.len()) }; - if code < 0 { - return Err(StorageError::KernelError { code }); + + let code = syscalls::command(DRIVER_NUMBER, command_nr::WRITE_SLICE, ptr, value.len()); + if let Err(e) = code { + return Err(StorageError::KernelError { + code: e.return_code, + }); } + Ok(()) } @@ -178,9 +180,11 @@ impl Storage for SyscallStorage { let index = Index { page, byte: 0 }; let length = self.page_size(); let ptr = self.read_slice(index, length)?.as_ptr() as usize; - let code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::ERASE_PAGE, ptr, length) }; - if code < 0 { - return Err(StorageError::KernelError { code }); + let code = syscalls::command(DRIVER_NUMBER, command_nr::ERASE_PAGE, ptr, length); + if let Err(e) = code { + return Err(StorageError::KernelError { + code: e.return_code, + }); } Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index b12f77b..ae3ca56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,8 @@ #[macro_use] extern crate alloc; -extern crate libtock; +extern crate lang_items; +extern crate libtock_core; +extern crate libtock_drivers; pub mod embedded_flash; diff --git a/src/main.rs b/src/main.rs index 753f165..2cb7a8c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,14 +22,12 @@ extern crate byteorder; #[cfg(feature = "std")] extern crate core; extern crate ctap2; -extern crate libtock; extern crate subtle; #[macro_use] extern crate cbor; extern crate crypto; mod ctap; -mod usb_ctap_hid; use core::cell::Cell; #[cfg(feature = "debug_ctap")] @@ -38,17 +36,18 @@ use crypto::rng256::TockRng256; use ctap::hid::{ChannelID, CtapHid, KeepaliveStatus, ProcessedPacket}; use ctap::status_code::Ctap2StatusCode; use ctap::CtapState; -use libtock::buttons; -use libtock::buttons::ButtonState; +use libtock_core::result::{CommandError, EALREADY}; +use libtock_drivers::buttons; +use libtock_drivers::buttons::ButtonState; #[cfg(feature = "debug_ctap")] -use libtock::console::Console; -use libtock::led; -use libtock::result::TockValue; -use libtock::syscalls; -use libtock::timer; +use libtock_drivers::console::Console; +use libtock_drivers::led; +use libtock_drivers::result::{FlexUnwrap, TockError}; +use libtock_drivers::timer; #[cfg(feature = "debug_ctap")] -use libtock::timer::Timer; -use libtock::timer::{Duration, StopAlarmError, Timestamp}; +use libtock_drivers::timer::Timer; +use libtock_drivers::timer::{Duration, Timestamp}; +use libtock_drivers::usb_ctap_hid; const KEEPALIVE_DELAY_MS: isize = 100; const KEEPALIVE_DELAY: Duration = Duration::from_ms(KEEPALIVE_DELAY_MS); @@ -58,7 +57,7 @@ fn main() { // Setup the timer with a dummy callback (we only care about reading the current time, but the // API forces us to set an alarm callback too). let mut with_callback = timer::with_callback(|_, _| {}); - let timer = with_callback.init().unwrap(); + let timer = with_callback.init().flex_unwrap(); // Setup USB driver. if !usb_ctap_hid::setup() { @@ -70,7 +69,7 @@ fn main() { let mut ctap_hid = CtapHid::new(); let mut led_counter = 0; - let mut last_led_increment = timer.get_current_clock(); + let mut last_led_increment = timer.get_current_clock().flex_unwrap(); // Main loop. If CTAP1 is used, we register button presses for U2F while receiving and waiting. // The way TockOS and apps currently interact, callbacks need a yield syscall to execute, @@ -87,11 +86,11 @@ fn main() { }; }); #[cfg(feature = "with_ctap1")] - let mut buttons = buttons_callback.init().unwrap(); + let mut buttons = buttons_callback.init().flex_unwrap(); #[cfg(feature = "with_ctap1")] // At the moment, all buttons are accepted. You can customize your setup here. for mut button in &mut buttons { - button.enable().unwrap(); + button.enable().flex_unwrap(); } let mut pkt_request = [0; 64]; @@ -105,7 +104,7 @@ fn main() { None => false, }; - let now = timer.get_current_clock(); + let now = timer.get_current_clock().flex_unwrap(); #[cfg(feature = "with_ctap1")] { if button_touched.get() { @@ -115,7 +114,7 @@ fn main() { // Heavy computation mostly follows a registered touch luckily. Unregistering // callbacks is important to not clash with those from check_user_presence. for mut button in &mut buttons { - button.disable().unwrap(); + button.disable().flex_unwrap(); } drop(buttons); drop(buttons_callback); @@ -153,7 +152,7 @@ fn main() { } } - let now = timer.get_current_clock(); + let now = timer.get_current_clock().flex_unwrap(); if let Some(wait_duration) = now.wrapping_sub(last_led_increment) { if wait_duration > KEEPALIVE_DELAY { // Loops quickly when waiting for U2F user presence, so the next LED blink @@ -188,8 +187,8 @@ fn main() { #[cfg(feature = "debug_ctap")] fn print_packet_notice(notice_text: &str, timer: &Timer) { - let now_us = - (Timestamp::::from_clock_value(timer.get_current_clock()).ms() * 1000.0) as u64; + let now = timer.get_current_clock().flex_unwrap(); + let now_us = (Timestamp::::from_clock_value(now).ms() * 1000.0) as u64; writeln!( Console::new(), "{} at {}.{:06} s", @@ -264,17 +263,17 @@ fn send_keepalive_up_needed( Ok(()) } -fn blink_leds(pattern_seed: isize) { - for l in 0..led::count() { +fn blink_leds(pattern_seed: usize) { + for l in 0..led::count().flex_unwrap() { if (pattern_seed ^ l).count_ones() & 1 != 0 { - led::get(l).unwrap().on(); + led::get(l).flex_unwrap().on().flex_unwrap(); } else { - led::get(l).unwrap().off(); + led::get(l).flex_unwrap().off().flex_unwrap(); } } } -fn wink_leds(pattern_seed: isize) { +fn wink_leds(pattern_seed: usize) { // This generates a "snake" pattern circling through the LEDs. // Fox example with 4 LEDs the sequence of lit LEDs will be the following. // 0 1 2 3 @@ -287,7 +286,7 @@ fn wink_leds(pattern_seed: isize) { // * * // * * * // * * - let count = led::count(); + let count = led::count().flex_unwrap(); let a = (pattern_seed / 2) % count; let b = ((pattern_seed + 1) / 2) % count; let c = ((pattern_seed + 3) / 2) % count; @@ -300,22 +299,22 @@ fn wink_leds(pattern_seed: isize) { _ => l, }; if k == a || k == b || k == c { - led::get(l).unwrap().on(); + led::get(l).flex_unwrap().on().flex_unwrap(); } else { - led::get(l).unwrap().off(); + led::get(l).flex_unwrap().off().flex_unwrap(); } } } fn switch_off_leds() { - for l in 0..led::count() { - led::get(l).unwrap().off(); + for l in 0..led::count().flex_unwrap() { + led::get(l).flex_unwrap().off().flex_unwrap(); } } fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> { // The timeout is N times the keepalive delay. - const TIMEOUT_ITERATIONS: isize = ctap::TOUCH_TIMEOUT_MS / KEEPALIVE_DELAY_MS; + const TIMEOUT_ITERATIONS: usize = ctap::TOUCH_TIMEOUT_MS as usize / KEEPALIVE_DELAY_MS as usize; // First, send a keep-alive packet to notify that the keep-alive status has changed. send_keepalive_up_needed(cid, KEEPALIVE_DELAY)?; @@ -328,10 +327,10 @@ fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> { ButtonState::Released => (), }; }); - let mut buttons = buttons_callback.init().unwrap(); + let mut buttons = buttons_callback.init().flex_unwrap(); // At the moment, all buttons are accepted. You can customize your setup here. for mut button in &mut buttons { - button.enable().unwrap(); + button.enable().flex_unwrap(); } let mut keepalive_response = Ok(()); @@ -343,19 +342,25 @@ fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> { let mut keepalive_callback = timer::with_callback(|_, _| { keepalive_expired.set(true); }); - let mut keepalive = keepalive_callback.init().unwrap(); - let keepalive_alarm = keepalive.set_alarm(KEEPALIVE_DELAY).unwrap(); + let mut keepalive = keepalive_callback.init().flex_unwrap(); + let keepalive_alarm = keepalive.set_alarm(KEEPALIVE_DELAY).flex_unwrap(); // Wait for a button touch or an alarm. - syscalls::yieldk_for(|| button_touched.get() || keepalive_expired.get()); + libtock_drivers::util::yieldk_for(|| button_touched.get() || keepalive_expired.get()); // Cleanup alarm callback. match keepalive.stop_alarm(keepalive_alarm) { Ok(()) => (), - Err(TockValue::Expected(StopAlarmError::AlreadyDisabled)) => { - assert!(keepalive_expired.get()) + Err(TockError::Command(CommandError { + return_code: EALREADY, + .. + })) => assert!(keepalive_expired.get()), + Err(_e) => { + #[cfg(feature = "debug_ctap")] + panic!("Unexpected error when stopping alarm: {:?}", _e); + #[cfg(not(feature = "debug_ctap"))] + panic!("Unexpected error when stopping alarm: "); } - Err(e) => panic!("Unexpected error when stopping alarm: {:?}", e), } // TODO: this may take arbitrary time. The keepalive_delay should be adjusted accordingly, @@ -374,7 +379,7 @@ fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> { // Cleanup button callbacks. for mut button in &mut buttons { - button.disable().unwrap(); + button.disable().flex_unwrap(); } // Returns whether the user was present. diff --git a/third_party/lang-items/Cargo.toml b/third_party/lang-items/Cargo.toml new file mode 100644 index 0000000..39ffbf0 --- /dev/null +++ b/third_party/lang-items/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "lang_items" +version = "0.1.0" +authors = [ + "Tock Project Developers ", + "Guillaume Endignoux ", +] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +libtock_core = { path = "../../third_party/libtock-rs/core", default-features = false, features = ["alloc_init", "custom_panic_handler", "custom_alloc_error_handler"] } +libtock_drivers = { path = "../libtock-drivers" } +linked_list_allocator = { version = "0.8.1", default-features = false } + +[features] +debug_allocations = [] +panic_console = [] +std = [] diff --git a/third_party/lang-items/LICENSE-APACHE b/third_party/lang-items/LICENSE-APACHE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/third_party/lang-items/LICENSE-APACHE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/third_party/lang-items/LICENSE-MIT b/third_party/lang-items/LICENSE-MIT new file mode 100644 index 0000000..80d95b9 --- /dev/null +++ b/third_party/lang-items/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 The Tock Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/lang-items/src/allocator.rs b/third_party/lang-items/src/allocator.rs new file mode 100644 index 0000000..d0a02ec --- /dev/null +++ b/third_party/lang-items/src/allocator.rs @@ -0,0 +1,109 @@ +use crate::util; +use core::alloc::GlobalAlloc; +use core::alloc::Layout; +#[cfg(any(feature = "debug_allocations", feature = "panic_console"))] +use core::fmt::Write; +use core::ptr; +use core::ptr::NonNull; +#[cfg(feature = "debug_allocations")] +use core::sync::atomic; +#[cfg(feature = "debug_allocations")] +use core::sync::atomic::AtomicUsize; +#[cfg(any(feature = "debug_allocations", feature = "panic_console"))] +use libtock_drivers::console::Console; +use linked_list_allocator::Heap; + +static mut HEAP: Heap = Heap::empty(); + +#[no_mangle] +unsafe fn libtock_alloc_init(app_heap_start: usize, app_heap_size: usize) { + HEAP.init(app_heap_start, app_heap_size); +} + +// With the "debug_allocations" feature, we use `AtomicUsize` to store the +// statistics because: +// - it is `Sync`, so we can use it in a static object (the allocator), +// - it implements interior mutability, so we can use it in the allocator +// methods (that take an immutable `&self` reference). +struct TockAllocator { + #[cfg(feature = "debug_allocations")] + count: AtomicUsize, + #[cfg(feature = "debug_allocations")] + size: AtomicUsize, +} + +impl TockAllocator { + const fn new() -> TockAllocator { + TockAllocator { + #[cfg(feature = "debug_allocations")] + count: AtomicUsize::new(0), + #[cfg(feature = "debug_allocations")] + size: AtomicUsize::new(0), + } + } +} + +unsafe impl GlobalAlloc for TockAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + let ptr = HEAP + .allocate_first_fit(layout) + .ok() + .map_or(ptr::null_mut(), NonNull::as_ptr); + #[cfg(feature = "debug_allocations")] + { + self.count.fetch_add(1, atomic::Ordering::SeqCst); + self.size.fetch_add(layout.size(), atomic::Ordering::SeqCst); + writeln!( + Console::new(), + "alloc[{}, {}] = {:?} ({} ptrs, {} bytes)", + layout.size(), + layout.align(), + ptr, + self.count.load(atomic::Ordering::SeqCst), + self.size.load(atomic::Ordering::SeqCst) + ) + .unwrap(); + } + ptr + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + #[cfg(feature = "debug_allocations")] + { + self.count.fetch_sub(1, atomic::Ordering::SeqCst); + self.size.fetch_sub(layout.size(), atomic::Ordering::SeqCst); + writeln!( + Console::new(), + "dealloc[{}, {}] = {:?} ({} ptrs, {} bytes)", + layout.size(), + layout.align(), + ptr, + self.count.load(atomic::Ordering::SeqCst), + self.size.load(atomic::Ordering::SeqCst) + ) + .unwrap(); + } + HEAP.deallocate(NonNull::new_unchecked(ptr), layout) + } +} + +#[cfg(any(target_arch = "arm", target_arch = "riscv32"))] +#[global_allocator] +static ALLOCATOR: TockAllocator = TockAllocator::new(); + +#[alloc_error_handler] +unsafe fn alloc_error_handler(_layout: Layout) -> ! { + util::signal_oom(); + util::signal_panic(); + + #[cfg(feature = "panic_console")] + { + writeln!(Console::new(), "Couldn't allocate: {:?}", _layout).ok(); + // Force the kernel to report the panic cause, by reading an invalid address. + // The memory protection unit should be setup by the Tock kernel to prevent apps from accessing + // address zero. + core::ptr::read_volatile(0 as *const usize); + } + + util::cycle_leds() +} diff --git a/third_party/lang-items/src/lib.rs b/third_party/lang-items/src/lib.rs new file mode 100644 index 0000000..c4fdcf8 --- /dev/null +++ b/third_party/lang-items/src/lib.rs @@ -0,0 +1,9 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![feature(alloc_error_handler)] + +#[cfg(not(feature = "std"))] +mod allocator; +#[cfg(not(feature = "std"))] +mod panic_handler; +#[cfg(not(feature = "std"))] +mod util; diff --git a/third_party/lang-items/src/panic_handler.rs b/third_party/lang-items/src/panic_handler.rs new file mode 100644 index 0000000..abf0a6e --- /dev/null +++ b/third_party/lang-items/src/panic_handler.rs @@ -0,0 +1,26 @@ +use crate::util; +#[cfg(feature = "panic_console")] +use core::fmt::Write; +use core::panic::PanicInfo; +#[cfg(feature = "panic_console")] +use libtock_drivers::console::Console; + +#[panic_handler] +fn panic_handler(_info: &PanicInfo) -> ! { + util::signal_panic(); + + #[cfg(feature = "panic_console")] + { + let mut console = Console::new(); + writeln!(console, "{}", _info).ok(); + console.flush(); + // Force the kernel to report the panic cause, by reading an invalid address. + // The memory protection unit should be setup by the Tock kernel to prevent apps from accessing + // address zero. + unsafe { + core::ptr::read_volatile(0 as *const usize); + } + } + + util::flash_all_leds(); +} diff --git a/third_party/lang-items/src/util.rs b/third_party/lang-items/src/util.rs new file mode 100644 index 0000000..c1a70fd --- /dev/null +++ b/third_party/lang-items/src/util.rs @@ -0,0 +1,46 @@ +use libtock_drivers::led; +use libtock_drivers::timer::{self, Duration}; + +// Signal a panic using the LowLevelDebug capsule (if available). +pub fn signal_panic() { + let _ = libtock_core::syscalls::command1_insecure(8, 1, 1); +} + +// Signal an out-of-memory error using the LowLevelDebug capsule (if available). +pub fn signal_oom() { + let _ = libtock_core::syscalls::command1_insecure(8, 2, 1); +} + +pub fn flash_all_leds() -> ! { + // Flash all LEDs (if available). All errors from syscalls are ignored: we are already inside a + // panic handler so there is nothing much to do if simple drivers (timer, LEDs) don't work. + loop { + if let Ok(leds) = led::all() { + for led in leds { + let _ = led.on(); + } + } + let _ = timer::sleep(Duration::from_ms(100)); + if let Ok(leds) = led::all() { + for led in leds { + let _ = led.off(); + } + } + let _ = timer::sleep(Duration::from_ms(100)); + } +} + +pub fn cycle_leds() -> ! { + // Cycle though all LEDs (if available). All errors from syscalls are ignored: we are already + // inside an error handler so there is nothing much to do if simple drivers (timer, LEDs) don't + // work. + loop { + if let Ok(leds) = led::all() { + for led in leds { + let _ = led.on(); + let _ = timer::sleep(Duration::from_ms(100)); + let _ = led.off(); + } + } + } +} diff --git a/third_party/libtock-drivers/Cargo.toml b/third_party/libtock-drivers/Cargo.toml new file mode 100644 index 0000000..74fe7ac --- /dev/null +++ b/third_party/libtock-drivers/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "libtock_drivers" +version = "0.1.0" +authors = [ + "Tock Project Developers ", + "Guillaume Endignoux ", +] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +libtock_core = { path = "../../third_party/libtock-rs/core" } + +[features] +debug_ctap = [] +verbose_usb = ["debug_ctap"] diff --git a/third_party/libtock-drivers/LICENSE-APACHE b/third_party/libtock-drivers/LICENSE-APACHE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/third_party/libtock-drivers/LICENSE-APACHE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/third_party/libtock-drivers/LICENSE-MIT b/third_party/libtock-drivers/LICENSE-MIT new file mode 100644 index 0000000..80d95b9 --- /dev/null +++ b/third_party/libtock-drivers/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 The Tock Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/libtock-drivers/src/buttons.rs b/third_party/libtock-drivers/src/buttons.rs new file mode 100644 index 0000000..5ab985f --- /dev/null +++ b/third_party/libtock-drivers/src/buttons.rs @@ -0,0 +1,170 @@ +use crate::result::{OtherError, TockResult}; +use core::marker::PhantomData; +use libtock_core::callback::{CallbackSubscription, Consumer}; +use libtock_core::syscalls; + +const DRIVER_NUMBER: usize = 0x00003; + +mod command_nr { + pub const COUNT: usize = 0; + pub const ENABLE_INTERRUPT: usize = 1; + pub const DISABLE_INTERRUPT: usize = 2; + pub const READ: usize = 3; +} + +mod subscribe_nr { + pub const SUBSCRIBE_CALLBACK: usize = 0; +} + +pub fn with_callback(callback: CB) -> WithCallback { + WithCallback { callback } +} + +pub struct WithCallback { + callback: CB, +} + +struct ButtonConsumer; + +impl Consumer> for ButtonConsumer { + fn consume(data: &mut WithCallback, button_num: usize, state: usize, _: usize) { + (data.callback)(button_num, state.into()); + } +} + +impl WithCallback { + pub fn init(&mut self) -> TockResult { + let count = syscalls::command(DRIVER_NUMBER, command_nr::COUNT, 0, 0)?; + + let subscription = syscalls::subscribe::( + DRIVER_NUMBER, + subscribe_nr::SUBSCRIBE_CALLBACK, + self, + )?; + + Ok(Buttons { + count: count as usize, + subscription, + }) + } +} + +pub struct Buttons<'a> { + count: usize, + #[allow(dead_code)] // Used in drop + subscription: CallbackSubscription<'a>, +} + +#[derive(Copy, Clone, Debug)] +pub enum ButtonsError { + NotSupported, + SubscriptionFailed, +} + +impl<'a> Buttons<'a> { + pub fn iter_mut(&mut self) -> ButtonIter { + ButtonIter { + curr_button: 0, + button_count: self.count, + lifetime: PhantomData, + } + } +} + +#[derive(Copy, Clone, Debug)] +pub enum ButtonState { + Pressed, + Released, +} + +impl From for ButtonState { + fn from(state: usize) -> ButtonState { + match state { + 0 => ButtonState::Released, + 1 => ButtonState::Pressed, + _ => unreachable!(), + } + } +} + +impl<'a, 'b> IntoIterator for &'b mut Buttons<'a> { + type Item = ButtonHandle<'b>; + type IntoIter = ButtonIter<'b>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +pub struct ButtonIter<'a> { + curr_button: usize, + button_count: usize, + lifetime: PhantomData<&'a ()>, +} + +impl<'a> Iterator for ButtonIter<'a> { + type Item = ButtonHandle<'a>; + + fn next(&mut self) -> Option { + if self.curr_button < self.button_count { + let item = ButtonHandle { + button_num: self.curr_button, + lifetime: PhantomData, + }; + self.curr_button += 1; + Some(item) + } else { + None + } + } +} + +pub struct ButtonHandle<'a> { + button_num: usize, + lifetime: PhantomData<&'a ()>, +} + +impl<'a> ButtonHandle<'a> { + pub fn enable(&mut self) -> TockResult