Skip to content

Commit 1089ef3

Browse files
bors[bot]jcsooyodaldevoid
committed
Merge #81
81: Add a __pre_init function to be called at the start of the reset handler r=korken89 a=yodaldevoid I needed this for a project so I went ahead and rebased and tweaked @jcsoo 's changes from #71. I will admit, I got a little impatient waiting and that also played into why I did this. If either @jcsoo or @japaric have an issue with this PR, please let me know and I will remove it. I apologize for toes that I have stepped on. Now onto the PR. This is possibly the simplest implementation that is possible. No nightly features were used in this implementation. Also, there is no hand-holding for the end user; if they want to mess with uninitialized statics, that is on them. If you would like me to add more documentation, please let me know what you would like to see. Fixes #17 Co-authored-by: Jonathan Soo <[email protected]> Co-authored-by: Gabriel Smith <[email protected]>
2 parents 96b76f9 + 73e0b2a commit 1089ef3

File tree

4 files changed

+82
-0
lines changed

4 files changed

+82
-0
lines changed

cortex-m-rt/ci/script.sh

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ main() {
99
alignment
1010
minimal
1111
main
12+
pre_init
1213
state
1314
)
1415
local fail_examples=(

cortex-m-rt/examples/pre_init.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//! `cortex-m-rt` based program with a function run before RAM is initialized.
2+
3+
#![deny(warnings)]
4+
#![no_main]
5+
#![no_std]
6+
7+
#[macro_use(entry, pre_init)]
8+
extern crate cortex_m_rt as rt;
9+
extern crate panic_semihosting;
10+
11+
pre_init!(disable_watchdog);
12+
13+
unsafe fn disable_watchdog() {
14+
// Do what you need to disable the watchdog.
15+
}
16+
17+
// the program entry point
18+
entry!(main);
19+
20+
fn main() -> ! {
21+
loop {}
22+
}

cortex-m-rt/link.x.in

+5
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ PROVIDE(UserHardFault = DefaultUserHardFault);
5151
/* # Interrupt vectors */
5252
EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */
5353

54+
/* # Pre-initialization function */
55+
/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function,
56+
then the function this points to will be called before the RAM is initialized. */
57+
PROVIDE(__pre_init = DefaultPreInit);
58+
5459
/* # Sections */
5560
SECTIONS
5661
{

cortex-m-rt/src/lib.rs

+54
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,11 @@
237237
//! have a size of 32 vectors (on ARMv6-M) or 240 vectors (on ARMv7-M). This array is located after
238238
//! `__EXCEPTIONS` in the `.vector_table` section.
239239
//!
240+
//! - `__pre_init`. This is a function to be run before RAM is initialized. It defaults to an empty
241+
//! function. The function called can be changed by calling the `pre_init!` macro. The empty
242+
//! function is not optimized out by default, but if an empty function is passed to `pre_init!` the
243+
//! function call will be optimized out.
244+
//!
240245
//! If you override any exception handler you'll find it as an unmangled symbol, e.g. `SysTick` or
241246
//! `SVCall`, in the output of `objdump`,
242247
//!
@@ -378,6 +383,14 @@
378383
//! println!("cargo:rustc-link-search={}", out.display());
379384
//! }
380385
//! ```
386+
//!
387+
//! ## `pre_init!`
388+
//!
389+
//! A user-defined function can be run at the start of the reset handler, before RAM is
390+
//! initialized. The macro `pre_init!` can be called to set the function to be run. The function is
391+
//! intended to perform actions that cannot wait the time it takes for RAM to be initialized, such
392+
//! as disabling a watchdog. As the function is called before RAM is initialized, any access of
393+
//! static variables will result in undefined behavior.
381394
382395
// # Developer notes
383396
//
@@ -474,8 +487,13 @@ pub unsafe extern "C" fn Reset() -> ! {
474487
static mut __sdata: u32;
475488
static mut __edata: u32;
476489
static __sidata: u32;
490+
491+
fn __pre_init();
477492
}
478493

494+
let pre_init: unsafe extern "C" fn() = __pre_init;
495+
pre_init();
496+
479497
// Initialize RAM
480498
r0::zero_bss(&mut __sbss, &mut __ebss);
481499
r0::init_data(&mut __sdata, &mut __edata, &__sidata);
@@ -531,6 +549,10 @@ pub unsafe extern "C" fn DefaultUserHardFault() {
531549
}
532550
}
533551

552+
#[doc(hidden)]
553+
#[no_mangle]
554+
pub unsafe extern "C" fn DefaultPreInit() {}
555+
534556
/// Macro to define the entry point of the program
535557
///
536558
/// **NOTE** This macro must be invoked once and must be invoked from an accessible module, ideally
@@ -872,3 +894,35 @@ macro_rules! exception {
872894
}
873895
};
874896
}
897+
898+
/// Macro to set the function to be called at the beginning of the reset handler.
899+
///
900+
/// The function must have the signature of `unsafe fn()`.
901+
///
902+
/// The function passed will be called before static variables are initialized. Any access of static
903+
/// variables will result in undefined behavior.
904+
///
905+
/// # Examples
906+
///
907+
/// ``` ignore
908+
/// pre_init!(foo::bar);
909+
///
910+
/// mod foo {
911+
/// pub unsafe fn bar() {
912+
/// // do something here
913+
/// }
914+
/// }
915+
/// ```
916+
#[macro_export]
917+
macro_rules! pre_init {
918+
($handler:path) => {
919+
#[allow(unsafe_code)]
920+
#[deny(private_no_mangle_fns)] // raise an error if this item is not accessible
921+
#[no_mangle]
922+
pub unsafe extern "C" fn __pre_init() {
923+
// validate user handler
924+
let f: unsafe fn() = $handler;
925+
f();
926+
}
927+
}
928+
}

0 commit comments

Comments
 (0)