diff options
-rw-r--r-- | cortex-m-rt/ci/script.sh | 1 | ||||
-rw-r--r-- | cortex-m-rt/examples/pre_init.rs | 22 | ||||
-rw-r--r-- | cortex-m-rt/link.x.in | 5 | ||||
-rw-r--r-- | cortex-m-rt/src/lib.rs | 54 |
4 files changed, 82 insertions, 0 deletions
diff --git a/cortex-m-rt/ci/script.sh b/cortex-m-rt/ci/script.sh index 2baec51..ac6df17 100644 --- a/cortex-m-rt/ci/script.sh +++ b/cortex-m-rt/ci/script.sh @@ -9,6 +9,7 @@ main() { alignment minimal main + pre_init state ) local fail_examples=( 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 dfcf262..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 { 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(); + } + } +} |