diff options
-rw-r--r-- | cortex-m-rt/ci/script.sh | 24 | ||||
-rw-r--r-- | cortex-m-rt/examples/data_overflow.rs | 30 | ||||
-rw-r--r-- | cortex-m-rt/examples/pre_init.rs | 22 | ||||
-rw-r--r-- | cortex-m-rt/link.x.in | 19 | ||||
-rw-r--r-- | cortex-m-rt/memory.x | 4 | ||||
-rw-r--r-- | cortex-m-rt/src/lib.rs | 54 |
6 files changed, 146 insertions, 7 deletions
diff --git a/cortex-m-rt/ci/script.sh b/cortex-m-rt/ci/script.sh index 902468d..2e070bf 100644 --- a/cortex-m-rt/ci/script.sh +++ b/cortex-m-rt/ci/script.sh @@ -10,8 +10,12 @@ main() { minimal main override-exception + pre_init state ) + local fail_examples=( + data_overflow + ) if [ $TRAVIS_RUST_VERSION = nightly ]; then # linking with GNU LD for ex in "${examples[@]}"; do @@ -23,6 +27,15 @@ main() { -C link-arg=-nostartfiles \ -C link-arg=-Wl,-Tlink.x done + for ex in "${fail_examples[@]}"; do + ! cargo rustc --target $TARGET --example $ex -- \ + -C link-arg=-nostartfiles \ + -C link-arg=-Wl,-Tlink.x + + ! cargo rustc --target $TARGET --example $ex --release -- \ + -C link-arg=-nostartfiles \ + -C link-arg=-Wl,-Tlink.x + done cargo rustc --target $TARGET --example device --features device -- \ -C link-arg=-nostartfiles \ @@ -44,6 +57,17 @@ main() { -Z linker-flavor=ld.lld \ -C link-arg=-Tlink.x done + for ex in "${fail_examples[@]}"; do + ! cargo rustc --target $TARGET --example $ex -- \ + -C linker=rust-lld \ + -Z linker-flavor=ld.lld \ + -C link-arg=-Tlink.x + + ! cargo rustc --target $TARGET --example $ex --release -- \ + -C linker=rust-lld \ + -Z linker-flavor=ld.lld \ + -C link-arg=-Tlink.x + done cargo rustc --target $TARGET --example device --features device -- \ -C linker=rust-lld \ diff --git a/cortex-m-rt/examples/data_overflow.rs b/cortex-m-rt/examples/data_overflow.rs new file mode 100644 index 0000000..396f1c8 --- /dev/null +++ b/cortex-m-rt/examples/data_overflow.rs @@ -0,0 +1,30 @@ +//! This is not an example; this is a linker overflow detection test +//! which should fail to link due to .data overflowing FLASH. + +#![deny(warnings)] +#![no_main] +#![no_std] + +#[macro_use(entry)] +extern crate cortex_m_rt as rt; +extern crate panic_abort; + +use core::ptr; + +entry!(main); + +// This large static array uses most of .rodata +static RODATA: [u8; 48*1024] = [1u8; 48*1024]; + +// This large mutable array causes .data to use the rest of FLASH +// without also overflowing RAM. +static mut DATA: [u8; 16*1024] = [1u8; 16*1024]; + +fn main() -> ! { + unsafe { + let _bigdata = ptr::read_volatile(&RODATA as *const u8); + let _bigdata = ptr::read_volatile(&DATA as *const u8); + } + + loop {} +} diff --git a/cortex-m-rt/examples/pre_init.rs b/cortex-m-rt/examples/pre_init.rs new file mode 100644 index 0000000..7258936 --- /dev/null +++ b/cortex-m-rt/examples/pre_init.rs @@ -0,0 +1,22 @@ +//! `cortex-m-rt` based program with a function run before RAM is initialized. + +#![deny(warnings)] +#![no_main] +#![no_std] + +#[macro_use(entry, pre_init)] +extern crate cortex_m_rt as rt; +extern crate panic_semihosting; + +pre_init!(disable_watchdog); + +unsafe fn disable_watchdog() { + // Do what you need to disable the watchdog. +} + +// the program entry point +entry!(main); + +fn main() -> ! { + loop {} +} diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index 5fa7dbf..23f406d 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -51,6 +51,11 @@ PROVIDE(UserHardFault = DefaultUserHardFault); /* # Interrupt vectors */ EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ +/* # Pre-initialization function */ +/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function, + then the function this points to will be called before the RAM is initialized. */ +PROVIDE(__pre_init = DefaultPreInit); + /* # Sections */ SECTIONS { @@ -84,24 +89,24 @@ SECTIONS } > FLASH /* ### .rodata */ - .rodata : + .rodata : ALIGN(4) { *(.rodata .rodata.*); - /* 4-byte align the end (VMA) of this section */ - /* WHY? To my knowledge there's no way to indicate the alignment of *LMA* so we align *this* - section with the goal of using its end address as the LMA of .data */ + /* 4-byte align the end (VMA) of this section. + This is required by LLD to ensure the LMA of the following .data + section will have the correct alignment. */ . = ALIGN(4); } > FLASH /* ## Sections in RAM */ /* ### .data */ - .data : AT(ADDR(.rodata) + SIZEOF(.rodata)) /* LMA */ + .data : ALIGN(4) { *(.data .data.*); . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - } > RAM + } > RAM AT > FLASH /* VMA of .data */ __sdata = ADDR(.data); @@ -111,7 +116,7 @@ SECTIONS __sidata = LOADADDR(.data); /* ### .bss */ - .bss : + .bss : ALIGN(4) { *(.bss .bss.*); diff --git a/cortex-m-rt/memory.x b/cortex-m-rt/memory.x index 3d97414..6268ea6 100644 --- a/cortex-m-rt/memory.x +++ b/cortex-m-rt/memory.x @@ -1,8 +1,12 @@ /* Device specific memory layout */ +/* This file is used to build the cortex-m-rt examples, + but not other applications using cortex-m-rt. */ + MEMORY { /* FLASH and RAM are mandatory memory regions */ + /* Update examples/data_overflow.rs if you change these sizes. */ FLASH : ORIGIN = 0x08000000, LENGTH = 64K RAM : ORIGIN = 0x20000000, LENGTH = 20K diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 60c8034..cecb5f8 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -237,6 +237,11 @@ //! have a size of 32 vectors (on ARMv6-M) or 240 vectors (on ARMv7-M). This array is located after //! `__EXCEPTIONS` in the `.vector_table` section. //! +//! - `__pre_init`. This is a function to be run before RAM is initialized. It defaults to an empty +//! function. The function called can be changed by calling the `pre_init!` macro. The empty +//! function is not optimized out by default, but if an empty function is passed to `pre_init!` the +//! function call will be optimized out. +//! //! If you override any exception handler you'll find it as an unmangled symbol, e.g. `SysTick` or //! `SVCall`, in the output of `objdump`, //! @@ -378,6 +383,14 @@ //! println!("cargo:rustc-link-search={}", out.display()); //! } //! ``` +//! +//! ## `pre_init!` +//! +//! A user-defined function can be run at the start of the reset handler, before RAM is +//! initialized. The macro `pre_init!` can be called to set the function to be run. The function is +//! intended to perform actions that cannot wait the time it takes for RAM to be initialized, such +//! as disabling a watchdog. As the function is called before RAM is initialized, any access of +//! static variables will result in undefined behavior. // # Developer notes // @@ -474,8 +487,13 @@ pub unsafe extern "C" fn Reset() -> ! { static mut __sdata: u32; static mut __edata: u32; static __sidata: u32; + + fn __pre_init(); } + let pre_init: unsafe extern "C" fn() = __pre_init; + pre_init(); + // Initialize RAM r0::zero_bss(&mut __sbss, &mut __ebss); r0::init_data(&mut __sdata, &mut __edata, &__sidata); @@ -531,6 +549,10 @@ pub unsafe extern "C" fn DefaultUserHardFault() { } } +#[doc(hidden)] +#[no_mangle] +pub unsafe extern "C" fn DefaultPreInit() {} + /// Macro to define the entry point of the program /// /// **NOTE** This macro must be invoked once and must be invoked from an accessible module, ideally @@ -872,3 +894,35 @@ macro_rules! exception { } }; } + +/// Macro to set the function to be called at the beginning of the reset handler. +/// +/// The function must have the signature of `unsafe fn()`. +/// +/// The function passed will be called before static variables are initialized. Any access of static +/// variables will result in undefined behavior. +/// +/// # Examples +/// +/// ``` ignore +/// pre_init!(foo::bar); +/// +/// mod foo { +/// pub unsafe fn bar() { +/// // do something here +/// } +/// } +/// ``` +#[macro_export] +macro_rules! pre_init { + ($handler:path) => { + #[allow(unsafe_code)] + #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible + #[no_mangle] + pub unsafe extern "C" fn __pre_init() { + // validate user handler + let f: unsafe fn() = $handler; + f(); + } + } +} |