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