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/setup.sh b/setup.sh index ad9cbd1..621ce0f 100755 --- a/setup.sh +++ b/setup.sh @@ -51,7 +51,7 @@ echo -n '[-] Copying additional boards to Tock... ' cp -r boards/* third_party/tock/boards echo $done_text -# Apply patches to kernel. Do that in a sub-shell +# Apply patches to kernel. Do that in a sub-shell. ( cd third_party/tock/ && \ for p in ../../patches/tock/[0-9][0-9]-*.patch @@ -66,20 +66,23 @@ echo $done_text done ) -# Now apply patches to libtock-rs. Do that in a sub-shell -( - cd third_party/libtock-rs/ && \ - for p in ../../patches/libtock-rs/[0-9][0-9]-*.patch - do - echo -n '[-] Applying patch "'$(basename $p)'"... ' - if git apply "$p" - then - echo $done_text - else - patch_conflict_detected - fi - done -) +# Now apply patches to libtock-rs. Do that in a sub-shell. +# +# Commented out as there are not patches at the moment, and the pattern fails in +# that case. +#( +# cd third_party/libtock-rs/ && \ +# for p in ../../patches/libtock-rs/[0-9][0-9]-*.patch +# do +# echo -n '[-] Applying patch "'$(basename $p)'"... ' +# if git apply "$p" +# then +# echo $done_text +# else +# patch_conflict_detected +# fi +# done +#) # Ensure we have certificates, keys, etc. so that the tests can run source tools/gen_key_materials.sh