aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cortex-m-rt/ci/script.sh1
-rw-r--r--cortex-m-rt/examples/pre_init.rs22
-rw-r--r--cortex-m-rt/link.x.in5
-rw-r--r--cortex-m-rt/src/lib.rs54
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();
+ }
+ }
+}