diff --git a/.gitignore b/.gitignore index e8cecc04..da66475f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ Cargo.lock layout.ld +platform target diff --git a/Cargo.toml b/Cargo.toml index 2fcb4bfa..5641d3ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,12 +6,14 @@ license = "MIT/Apache-2.0" edition = "2018" [features] -alloc = [ "linked_list_allocator" ] +alloc = ["libtock-core/alloc"] +custom_panic_handler = ["libtock-core/custom_panic_handler"] +custom_alloc_error_handler = ["libtock-core/custom_alloc_error_handler"] [dependencies] core = { package = "async-support", path = "async-support" } +libtock-core = { path = "core" } libtock_codegen = { path = "codegen" } -linked_list_allocator = { optional = true, version = "=0.6.5", default-features = false } futures = { version = "0.3.1", default-features = false, features = ["unstable", "cfg-target-has-atomic"] } [dev-dependencies] @@ -22,22 +24,27 @@ serde = { version = "=1.0.84", default-features = false, features = ["derive"] } [[example]] name = "alloc_error" -path = "examples-alloc/alloc_error.rs" -required-features = ["alloc"] +path = "examples-features/alloc_error.rs" +required-features = ["alloc", "custom_alloc_error_handler"] [[example]] name = "ble_scanning" -path = "examples-alloc/ble_scanning.rs" +path = "examples-features/ble_scanning.rs" required-features = ["alloc"] [[example]] name = "libtock_test" -path = "examples-alloc/libtock_test.rs" +path = "examples-features/libtock_test.rs" required-features = ["alloc"] +[[example]] +name = "panic" +path = "examples-features/panic.rs" +required-features = ["custom_panic_handler"] + [[example]] name = "simple_ble" -path = "examples-alloc/simple_ble.rs" +path = "examples-features/simple_ble.rs" required-features = ["alloc"] [profile.dev] @@ -52,4 +59,5 @@ lto = true members = [ "async-support", "codegen", + "core" ] diff --git a/Makefile b/Makefile index d9128138..3e97e223 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,9 @@ setup: examples: PLATFORM=nrf52 cargo build --release --target=thumbv7em-none-eabi --examples PLATFORM=nrf52 cargo build --release --target=thumbv7em-none-eabi --examples --features=alloc - PLATFORM=opentitan cargo build --release --target=riscv32imc-unknown-none-elf --examples + PLATFORM=nrf52 cargo build --release --target=thumbv7em-none-eabi --example panic --features=custom_panic_handler,custom_alloc_error_handler + PLATFORM=nrf52 cargo build --release --target=thumbv7em-none-eabi --example alloc_error --features=alloc,custom_alloc_error_handler + PLATFORM=opentitan cargo build --release --target=riscv32imc-unknown-none-elf --examples # Important: This is testing a platform without atomics support .PHONY: test test: diff --git a/core/Cargo.toml b/core/Cargo.toml new file mode 100644 index 00000000..64fa96ea --- /dev/null +++ b/core/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "libtock-core" +version = "0.1.0" +authors = ["Tock Project Developers "] +edition = "2018" + +[features] +alloc = [ "linked_list_allocator" ] +custom_panic_handler = [] +custom_alloc_error_handler = [] + +[dependencies] +linked_list_allocator = { optional = true, version = "=0.6.5", default-features = false } diff --git a/core/README.md b/core/README.md new file mode 100644 index 00000000..ba9602a3 --- /dev/null +++ b/core/README.md @@ -0,0 +1,33 @@ +# libtock-core + +Core crate of `libtock-rs`. It contains the architecture specific code of `libtock-rs`. In particular: + + * the entry point + * `panic` and `alloc_error` handlers + * the syscalls + * the allocator (optional) + +It has three important feature flags + + * `alloc` - allow for heap. Enables a linked list allocator. + * `custom_panic_handler` - disable the default panic handler and allow definition of a custom one using `#[panic_handler]` + * `custom_alloc_error_handler` - disable the default alloc error handler and allow definition of a custom one using `#[alloc_error_handler]` + +## License + +Licensed under either of + +- Apache License, Version 2.0 + ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +- MIT license + ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +The contribution guidelines are identical to those of `libtock-rs` and can be found here: [contribution guidelines](../CONTRIBUTING.md) diff --git a/core/src/alloc.rs b/core/src/alloc.rs new file mode 100644 index 00000000..05e96695 --- /dev/null +++ b/core/src/alloc.rs @@ -0,0 +1,40 @@ +use core::alloc::GlobalAlloc; +use core::alloc::Layout; +use core::ptr; +use core::ptr::NonNull; +use linked_list_allocator::Heap; + +pub 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(ptr::null_mut(), NonNull::as_ptr) + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + HEAP.deallocate(NonNull::new_unchecked(ptr), layout) + } +} + +#[global_allocator] +static ALLOCATOR: TockAllocator = TockAllocator; + +#[cfg(not(feature = "custom_alloc_error_handler"))] +#[alloc_error_handler] +unsafe fn alloc_error_handler(_: Layout) -> ! { + use crate::syscalls; + + // Print 0x01 using the LowLevelDebug capsule (if available). + let _ = syscalls::command1_insecure(8, 2, 0x01); + + // Signal a panic using the LowLevelDebug capsule (if available). + let _ = syscalls::command1_insecure(8, 1, 0x01); + + loop { + syscalls::raw::yieldk(); + } +} diff --git a/src/callback.rs b/core/src/callback.rs similarity index 100% rename from src/callback.rs rename to core/src/callback.rs diff --git a/core/src/debug/mod.rs b/core/src/debug/mod.rs new file mode 100644 index 00000000..1f306446 --- /dev/null +++ b/core/src/debug/mod.rs @@ -0,0 +1,5 @@ +#[cfg_attr(target_arch = "arm", path = "platform_arm.rs")] +#[cfg_attr(target_arch = "riscv32", path = "platform_riscv32.rs")] +mod platform; + +pub use platform::*; diff --git a/core/src/debug/platform.rs b/core/src/debug/platform.rs new file mode 100644 index 00000000..5f1f9f4a --- /dev/null +++ b/core/src/debug/platform.rs @@ -0,0 +1,3 @@ +pub fn get_stack_pointer() -> usize { + panic!("No generic implementation.") +} diff --git a/core/src/debug/platform_arm.rs b/core/src/debug/platform_arm.rs new file mode 100644 index 00000000..46211b3b --- /dev/null +++ b/core/src/debug/platform_arm.rs @@ -0,0 +1,5 @@ +pub fn get_stack_pointer() -> usize { + let stack_pointer; + unsafe { asm!("mov $0, sp" : "=r"(stack_pointer) : : : "volatile") }; + stack_pointer +} diff --git a/core/src/debug/platform_riscv32.rs b/core/src/debug/platform_riscv32.rs new file mode 100644 index 00000000..7f4a4e0b --- /dev/null +++ b/core/src/debug/platform_riscv32.rs @@ -0,0 +1,5 @@ +pub fn get_stack_pointer() -> usize { + let stack_pointer; + unsafe { asm!("mv $0, sp" : "=r"(stack_pointer) : : : "volatile") }; + stack_pointer +} diff --git a/src/entry_point/mod.rs b/core/src/entry_point/mod.rs similarity index 98% rename from src/entry_point/mod.rs rename to core/src/entry_point/mod.rs index 09044bdb..d63b1747 100644 --- a/src/entry_point/mod.rs +++ b/core/src/entry_point/mod.rs @@ -57,10 +57,6 @@ use core::ptr; #[cfg_attr(target_arch = "riscv32", path = "start_item_riscv32.rs")] #[cfg_attr(target_arch = "arm", path = "start_item_arm.rs")] -#[cfg_attr( - not(any(target_arch = "arm", target_arch = "riscv32")), - path = "start_item_mock.rs" -)] mod start_item; /// The header encoded at the beginning of .text by the linker script. It is diff --git a/src/entry_point/start_item_mock.rs b/core/src/entry_point/start_item.rs similarity index 100% rename from src/entry_point/start_item_mock.rs rename to core/src/entry_point/start_item.rs diff --git a/src/entry_point/start_item_arm.rs b/core/src/entry_point/start_item_arm.rs similarity index 100% rename from src/entry_point/start_item_arm.rs rename to core/src/entry_point/start_item_arm.rs diff --git a/src/entry_point/start_item_riscv32.rs b/core/src/entry_point/start_item_riscv32.rs similarity index 100% rename from src/entry_point/start_item_riscv32.rs rename to core/src/entry_point/start_item_riscv32.rs diff --git a/src/lang_items.rs b/core/src/lang_items.rs similarity index 51% rename from src/lang_items.rs rename to core/src/lang_items.rs index 91a20a1a..b5c2cd47 100644 --- a/src/lang_items.rs +++ b/core/src/lang_items.rs @@ -18,14 +18,7 @@ //! `rustc_main`. That's covered by the `_start` function in the root of this //! crate. -use crate::drivers; -use crate::leds::LedsDriver; -use crate::result::TockResult; -use crate::timer::Duration; -use crate::timer::ParallelSleepDriver; -use core::executor; -use core::panic::PanicInfo; -use futures::future; +use crate::syscalls; #[lang = "start"] extern "C" fn start(main: fn() -> T, _argc: isize, _argv: *const *const u8) -> bool @@ -45,7 +38,7 @@ impl Termination for () { fn check_result(self) {} } -impl Termination for TockResult<()> { +impl Termination for Result { fn check_result(self) { if self.is_err() { unsafe { report_panic() }; @@ -53,44 +46,17 @@ impl Termination for TockResult<()> { } } +#[cfg(not(feature = "custom_panic_handler"))] #[panic_handler] -unsafe fn panic_handler(_info: &PanicInfo) -> ! { +unsafe fn panic_handler(_info: &core::panic::PanicInfo) -> ! { report_panic() } unsafe fn report_panic() -> ! { // Signal a panic using the LowLevelDebug capsule (if available). - super::debug::low_level_status_code(1); + let _ = syscalls::command1_insecure(8, 1, 1); - // Flash all LEDs (if available). - executor::block_on(async { - let mut drivers = drivers::retrieve_drivers_unsafe(); - - let leds_driver = drivers.leds.init_driver(); - let mut timer_driver = drivers.timer.create_timer_driver(); - let timer_driver = timer_driver.activate(); - - if let (Ok(leds_driver), Ok(timer_driver)) = (leds_driver, timer_driver) { - let _ = blink_all_leds(&leds_driver, &timer_driver).await; - } else { - future::pending::<()>().await - } - loop {} - }) -} - -async fn blink_all_leds( - leds_driver: &LedsDriver<'_>, - timer_driver: &ParallelSleepDriver<'_>, -) -> TockResult<()> { loop { - for led in leds_driver.leds() { - led.on()?; - } - timer_driver.sleep(Duration::from_ms(100)).await?; - for led in leds_driver.leds() { - led.off()?; - } - timer_driver.sleep(Duration::from_ms(100)).await?; + syscalls::raw::yieldk(); } } diff --git a/core/src/lib.rs b/core/src/lib.rs new file mode 100644 index 00000000..e465f4d3 --- /dev/null +++ b/core/src/lib.rs @@ -0,0 +1,17 @@ +#![feature(asm, lang_items, naked_functions)] +#![cfg_attr(any(target_arch = "arm", target_arch = "riscv32"), no_std)] +#![cfg_attr(feature = "alloc", feature(alloc_error_handler))] + +#[cfg(feature = "alloc")] +mod alloc; +mod entry_point; +#[cfg(any(target_arch = "arm", target_arch = "riscv32"))] +mod lang_items; + +pub mod callback; +pub mod debug; +pub mod memop; +pub mod result; +pub mod shared_memory; +pub mod syscalls; +pub mod unwind_symbols; diff --git a/src/memop.rs b/core/src/memop.rs similarity index 100% rename from src/memop.rs rename to core/src/memop.rs diff --git a/core/src/result.rs b/core/src/result.rs new file mode 100644 index 00000000..95087383 --- /dev/null +++ b/core/src/result.rs @@ -0,0 +1,30 @@ +#[derive(Copy, Clone)] +pub struct SubscribeError { + pub driver_number: usize, + pub subscribe_number: usize, + pub return_code: isize, +} + +#[derive(Copy, Clone)] +pub struct CommandError { + pub driver_number: usize, + pub command_number: usize, + pub arg1: usize, + pub arg2: usize, + pub return_code: isize, +} + +#[derive(Copy, Clone)] +pub struct AllowError { + pub driver_number: usize, + pub allow_number: usize, + pub return_code: isize, +} + +pub const SUCCESS: isize = 0; +pub const FAIL: isize = -1; +pub const EBUSY: isize = -2; +pub const EALREADY: isize = -3; +pub const EINVAL: isize = -6; +pub const ESIZE: isize = -7; +pub const ENOMEM: isize = -9; diff --git a/src/shared_memory.rs b/core/src/shared_memory.rs similarity index 100% rename from src/shared_memory.rs rename to core/src/shared_memory.rs diff --git a/src/syscalls/mod.rs b/core/src/syscalls/mod.rs similarity index 97% rename from src/syscalls/mod.rs rename to core/src/syscalls/mod.rs index c0289e5e..833c356a 100644 --- a/src/syscalls/mod.rs +++ b/core/src/syscalls/mod.rs @@ -1,9 +1,5 @@ #[cfg_attr(target_arch = "riscv32", path = "platform_riscv32.rs")] #[cfg_attr(target_arch = "arm", path = "platform_arm.rs")] -#[cfg_attr( - not(any(target_arch = "arm", target_arch = "riscv32")), - path = "platform_mock.rs" -)] mod platform; use crate::callback::CallbackSubscription; diff --git a/src/syscalls/platform_mock.rs b/core/src/syscalls/platform.rs similarity index 100% rename from src/syscalls/platform_mock.rs rename to core/src/syscalls/platform.rs diff --git a/src/syscalls/platform_arm.rs b/core/src/syscalls/platform_arm.rs similarity index 100% rename from src/syscalls/platform_arm.rs rename to core/src/syscalls/platform_arm.rs diff --git a/src/syscalls/platform_riscv32.rs b/core/src/syscalls/platform_riscv32.rs similarity index 100% rename from src/syscalls/platform_riscv32.rs rename to core/src/syscalls/platform_riscv32.rs diff --git a/src/unwind_symbols.rs b/core/src/unwind_symbols.rs similarity index 100% rename from src/unwind_symbols.rs rename to core/src/unwind_symbols.rs diff --git a/examples-alloc/alloc_error.rs b/examples-alloc/alloc_error.rs deleted file mode 100644 index ec42b5ac..00000000 --- a/examples-alloc/alloc_error.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Triggers the out-of-memory handler. Should make all LEDs cycle. - -#![no_std] - -extern crate alloc; - -use alloc::vec::Vec; -use libtock::result::TockResult; - -#[libtock::main] -fn main() -> TockResult<()> { - let mut vec = Vec::new(); - loop { - vec.push(0); - } -} diff --git a/examples-features/alloc_error.rs b/examples-features/alloc_error.rs new file mode 100644 index 00000000..40ae9394 --- /dev/null +++ b/examples-features/alloc_error.rs @@ -0,0 +1,31 @@ +// Triggers the out-of-memory handler. Should print an error message. + +#![no_std] +#![feature(alloc_error_handler)] + +extern crate alloc; + +use alloc::vec::Vec; +use core::alloc::Layout; +use core::fmt::Write; +use libtock::result::TockResult; +use libtock::syscalls; + +#[libtock::main] +fn main() -> TockResult<()> { + let mut vec = Vec::new(); + loop { + vec.push(0); + } +} + +#[alloc_error_handler] +unsafe fn alloc_error_handler(_: Layout) -> ! { + if let Ok(drivers) = libtock::retrieve_drivers() { + let mut console = drivers.console.create_console(); + let _ = writeln!(console, "alloc_error_handler called"); + } + loop { + syscalls::raw::yieldk(); + } +} diff --git a/examples-alloc/ble_scanning.rs b/examples-features/ble_scanning.rs similarity index 100% rename from examples-alloc/ble_scanning.rs rename to examples-features/ble_scanning.rs diff --git a/examples-alloc/libtock_test.rs b/examples-features/libtock_test.rs similarity index 100% rename from examples-alloc/libtock_test.rs rename to examples-features/libtock_test.rs diff --git a/examples-features/panic.rs b/examples-features/panic.rs new file mode 100644 index 00000000..5a9123af --- /dev/null +++ b/examples-features/panic.rs @@ -0,0 +1,24 @@ +// Triggers the panic handler. Should print an error message. + +#![no_std] + +use core::fmt::Write; +use core::panic::PanicInfo; +use libtock::result::TockResult; +use libtock::syscalls; + +#[libtock::main] +async fn main() -> TockResult<()> { + panic!("Bye world!"); +} + +#[panic_handler] +unsafe fn panic_handler(_info: &PanicInfo) -> ! { + if let Ok(drivers) = libtock::retrieve_drivers() { + let mut console = drivers.console.create_console(); + let _ = writeln!(console, "panic_handler called"); + } + loop { + syscalls::raw::yieldk(); + } +} diff --git a/examples-alloc/simple_ble.rs b/examples-features/simple_ble.rs similarity index 100% rename from examples-alloc/simple_ble.rs rename to examples-features/simple_ble.rs diff --git a/examples/panic.rs b/examples/panic.rs deleted file mode 100644 index 5abc01af..00000000 --- a/examples/panic.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Triggers the panic handler. Should make all LEDs flash. - -#![no_std] - -use libtock::result::TockResult; - -#[libtock::main] -async fn main() -> TockResult<()> { - panic!("Bye world!"); -} diff --git a/src/alloc.rs b/src/alloc.rs deleted file mode 100644 index 523cb646..00000000 --- a/src/alloc.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::drivers; -use crate::leds::LedsDriver; -use crate::result::TockResult; -use crate::timer::Duration; -use crate::timer::ParallelSleepDriver; -use core::alloc::GlobalAlloc; -use core::alloc::Layout; -use core::executor; -use core::ptr; -use core::ptr::NonNull; -use futures::future; -use linked_list_allocator::Heap; - -pub 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(ptr::null_mut(), NonNull::as_ptr) - } - - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - HEAP.deallocate(NonNull::new_unchecked(ptr), layout) - } -} - -#[global_allocator] -static ALLOCATOR: TockAllocator = TockAllocator; - -#[alloc_error_handler] -unsafe fn alloc_error_handler(_: Layout) -> ! { - executor::block_on(async { - let mut drivers = drivers::retrieve_drivers_unsafe(); - - let leds_driver = drivers.leds.init_driver(); - let mut timer_driver = drivers.timer.create_timer_driver(); - let timer_driver = timer_driver.activate(); - - if let (Ok(leds_driver), Ok(timer_driver)) = (leds_driver, timer_driver) { - let _ = cycle_all_leds(&leds_driver, &timer_driver).await; - } else { - future::pending::<()>().await - } - loop {} - }) -} - -async fn cycle_all_leds( - leds_driver: &LedsDriver<'_>, - timer_driver: &ParallelSleepDriver<'_>, -) -> TockResult<()> { - loop { - for led in leds_driver.leds() { - led.on()?; - timer_driver.sleep(Duration::from_ms(100)).await?; - led.off()?; - } - } -} diff --git a/src/debug/mod.rs b/src/debug/mod.rs index 4596aaa1..3bae6832 100644 --- a/src/debug/mod.rs +++ b/src/debug/mod.rs @@ -3,6 +3,7 @@ mod low_level_debug; use crate::drivers; +use libtock_core::debug as core_debug; pub use low_level_debug::*; @@ -21,22 +22,15 @@ pub fn print_as_hex(value: usize) { let _ = console.write(buffer); } -#[cfg(target_arch = "arm")] pub fn print_stack_pointer() { - let stack_pointer; - unsafe { asm!("mov $0, sp" : "=r"(stack_pointer) : : : "volatile") }; - let mut buffer = [b'\n'; 15]; buffer[0..4].clone_from_slice(b"SP: "); - write_as_hex(&mut buffer[4..15], stack_pointer); + write_as_hex(&mut buffer[4..15], core_debug::get_stack_pointer()); let drivers = unsafe { drivers::retrieve_drivers_unsafe() }; let mut console = drivers.console.create_console(); let _ = console.write(buffer); } -#[cfg(target_arch = "riscv32")] -pub fn print_stack_pointer() {} - #[inline(always)] /// Dumps address /// # Safety diff --git a/src/lib.rs b/src/lib.rs index 0744a53e..0aabb1ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,18 +1,9 @@ -#![feature(asm, lang_items, naked_functions)] -#![cfg_attr(feature = "alloc", feature(alloc_error_handler))] #![cfg_attr(any(target_arch = "arm", target_arch = "riscv32"), no_std)] -#[cfg(feature = "alloc")] -mod alloc; -mod entry_point; -#[cfg(any(target_arch = "arm", target_arch = "riscv32"))] -mod lang_items; - pub mod adc; pub mod ble_composer; pub mod ble_parser; pub mod buttons; -pub mod callback; pub mod console; pub mod debug; pub mod drivers; @@ -20,16 +11,13 @@ pub mod electronics; pub mod futures; pub mod gpio; pub mod leds; -pub mod memop; pub mod result; pub mod rng; pub mod sensors; -pub mod shared_memory; pub mod simple_ble; -pub mod syscalls; pub mod temperature; pub mod timer; -pub mod unwind_symbols; pub use drivers::retrieve_drivers; pub use libtock_codegen::main; +pub use libtock_core::*; diff --git a/src/result.rs b/src/result.rs index 9dc4f161..74b4786a 100644 --- a/src/result.rs +++ b/src/result.rs @@ -1,5 +1,7 @@ use core::fmt; +pub use libtock_core::result::*; + pub type TockResult = Result; #[derive(Copy, Clone)] @@ -18,41 +20,18 @@ impl core::fmt::Debug for TockError { } } -#[derive(Copy, Clone)] -pub struct SubscribeError { - pub driver_number: usize, - pub subscribe_number: usize, - pub return_code: isize, -} - impl From for TockError { fn from(subscribe_error: SubscribeError) -> Self { TockError::Subscribe(subscribe_error) } } -#[derive(Copy, Clone)] -pub struct CommandError { - pub driver_number: usize, - pub command_number: usize, - pub arg1: usize, - pub arg2: usize, - pub return_code: isize, -} - impl From for TockError { fn from(command_error: CommandError) -> Self { TockError::Command(command_error) } } -#[derive(Copy, Clone)] -pub struct AllowError { - pub driver_number: usize, - pub allow_number: usize, - pub return_code: isize, -} - impl From for TockError { fn from(allow_error: AllowError) -> Self { TockError::Allow(allow_error) @@ -88,11 +67,3 @@ impl From for TockError { TockError::Other(OtherError::OutOfRangeError) } } - -pub const SUCCESS: isize = 0; -pub const FAIL: isize = -1; -pub const EBUSY: isize = -2; -pub const EALREADY: isize = -3; -pub const EINVAL: isize = -6; -pub const ESIZE: isize = -7; -pub const ENOMEM: isize = -9;