diff options
-rw-r--r-- | cortex-m-rt/Cargo.toml | 5 | ||||
-rw-r--r-- | cortex-m-rt/asm.s | 4 | ||||
-rw-r--r-- | cortex-m-rt/build.rs | 6 | ||||
-rw-r--r-- | cortex-m-rt/link.x | 31 | ||||
-rw-r--r-- | cortex-m-rt/memory.x | 19 | ||||
-rw-r--r-- | cortex-m-rt/src/lib.rs | 56 |
6 files changed, 99 insertions, 22 deletions
diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 9648b76..4d5e592 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -10,4 +10,7 @@ repository = "https://github.com/japaric/cortex-m-rt" version = "0.5.0" [dependencies] -r0 = "0.2.1"
\ No newline at end of file +r0 = "0.2.1" + +[build-dependencies] +cc = "1.0.10" diff --git a/cortex-m-rt/asm.s b/cortex-m-rt/asm.s new file mode 100644 index 0000000..1ad7721 --- /dev/null +++ b/cortex-m-rt/asm.s @@ -0,0 +1,4 @@ + .global HardFault +HardFault: + mrs r0, MSP + b UserHardFault diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index 1d0160c..70b7a43 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -1,3 +1,5 @@ +extern crate cc; + use std::env; use std::fs::File; use std::io::Write; @@ -9,6 +11,10 @@ fn main() { has_fpu(&target); is_armv6m(&target); + if target.starts_with("thumbv") { + cc::Build::new().file("asm.s").compile("asm"); + } + // Put the linker script somewhere the linker can find it let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); File::create(out.join("link.x")) diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index 1f5fd6f..0fb3592 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -1,35 +1,44 @@ /* # Developer notes - Symbols that start with a double underscore (__) are considered "private" + - Symbols that start with a single underscore (_) are considered "semi-public"; they can be overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { static mut __sbss }`). + - `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a symbol if not dropped if it appears in or near the front of the linker arguments and "it's not needed" by any of the preceding objects (linker arguments) + - `PROVIDE` is used to provide default values that can be overridden by a user linker script + - On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see "Address (..) is out of bounds" in the disassembly produced by `objdump`. */ +/* Provides information about the memory layout of the device */ +/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */ INCLUDE memory.x + +/* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */ +/* This will usually be provided by a device crate generated using svd2rust (see `interrupts.x`) */ INCLUDE interrupts.x -/* # Entry point */ +/* # Entry point = reset vector */ ENTRY(__reset); EXTERN(__RESET_VECTOR); /* depends on the `__reset` symbol */ -EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ - /* # Exception vectors */ /* This is effectively weak aliasing at the linker level */ /* The user can override any of these aliases by defining the corresponding symbol themselves (cf. the `exception!` macro) */ +EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ + EXTERN(DefaultHandler); PROVIDE(NMI = DefaultHandler); -PROVIDE(HardFault = DefaultHandler); +EXTERN(HardFault); PROVIDE(MemManage = DefaultHandler); PROVIDE(BusFault = DefaultHandler); PROVIDE(UsageFault = DefaultHandler); @@ -39,7 +48,7 @@ PROVIDE(PendSV = DefaultHandler); PROVIDE(SysTick = DefaultHandler); /* # Interrupt vectors */ -EXTERN(__INTERRUPTS); /* to be provided by the device crate or equivalent */ +EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ /* # User overridable symbols I */ /* Lets the user place the stack in a different RAM region */ @@ -57,15 +66,15 @@ SECTIONS LONG(_stack_start); /* Reset vector */ - KEEP(*(.vector_table.reset_vector)); + KEEP(*(.vector_table.reset_vector)); /* this is `__RESET_VECTOR` symbol */ __reset_vector = ABSOLUTE(.); /* Exceptions */ - KEEP(*(.vector_table.exceptions)); + KEEP(*(.vector_table.exceptions)); /* this is `__EXCEPTIONS` symbol */ __eexceptions = ABSOLUTE(.); /* Device specific interrupts */ - KEEP(*(.vector_table.interrupts)); + KEEP(*(.vector_table.interrupts)); /* this is `__INTERRUPTS` symbol */ __einterrupts = ABSOLUTE(.); } > FLASH @@ -79,7 +88,7 @@ SECTIONS /* ### .rodata */ .rodata : { - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + . = ALIGN(4); /* 4-byte align the start (VMA) of this section */ /* __srodata = ABSOLUTE(.); */ *(.rodata .rodata.*); @@ -187,7 +196,7 @@ Set '_stext' to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)"); ASSERT(__sgot == __egot, " .got section detected in the input files. Dynamic relocations are not -supported. If you are linking to C code compiled using the `gcc` crate +supported. If you are linking to C code compiled using the `cc` crate then modify your build script to compile the C code _without_ the --fPIC flag. See the documentation of the `gcc::Config.fpic` method for +-fPIC flag. See the documentation of the `cc::Build.pic` method for details."); diff --git a/cortex-m-rt/memory.x b/cortex-m-rt/memory.x new file mode 100644 index 0000000..8027efc --- /dev/null +++ b/cortex-m-rt/memory.x @@ -0,0 +1,19 @@ +/* Device specific memory layout */ + +MEMORY +{ + /* FLASH and RAM are mandatory memory regions */ + FLASH : ORIGIN = 0x08000000, LENGTH = 64K + RAM : ORIGIN = 0x20000000, LENGTH = 20K + + /* More memory regions can declared: for example this is a second RAM region */ + /* CCRAM : ORIGIN = 0x10000000, LENGTH = 8K */ +} + +/* The location of the stack can be overridden using the `_stack_start` symbol. + By default it will be placed at the end of the RAM region */ +/* _stack_start = ORIGIN(CCRAM) + LENGTH(CCRAM); */ + +/* The location of the .text section can be overridden using the `_stext` symbol. + By default it will place after .vector_table */ +/* _stext = ORIGIN(FLASH) + 0x100; */ diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index e0ddb76..128d7b4 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -1,4 +1,16 @@ //! Minimal startup / runtime for Cortex-M microcontrollers +//! +//! TODO +//! +//! # Example +//! +//! # User interface +//! +//! ## `memory.x` +//! +//! ## `interrupts.x` +//! +//! # Diagnostics // # Developer notes // @@ -11,7 +23,32 @@ extern crate r0; +/// Registers stacked (pushed into the stack) during an exception +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct ExceptionFrame { + /// (General purpose) Register 0 + pub r0: u32, + /// (General purpose) Register 1 + pub r1: u32, + /// (General purpose) Register 2 + pub r2: u32, + /// (General purpose) Register 3 + pub r3: u32, + /// (General purpose) Register 12 + pub r12: u32, + /// Linker Register + pub lr: u32, + /// Program Counter + pub pc: u32, + /// Program Status Register + pub xpsr: u32, +} + /// Returns a pointer into which the heap can be placed +/// +/// The start of the heap is guaranteed to be 4-byte aligned; that is the pointer returned by this +/// function is a multiple of 4. #[inline] pub fn heap_start() -> *mut u32 { extern "C" { @@ -153,12 +190,12 @@ pub static __EXCEPTIONS: [Option<unsafe extern "C" fn()>; 14] = [ /// /// Usage: `exception!(ExceptionName, path::to::handler)` /// -/// All exceptions are serviced by the `DefaultHandler` exception handler unless overridden using -/// this macro. `ExceptionName` can be one of are: +/// All exceptions are serviced by the `DefaultHandler` unless overridden using this macro. +/// `ExceptionName` can be one of: /// -/// - `DefaultHandler` (a) -- `fn(u8) -> !` -- the argument is the exception number (VECTACTIVE) +/// - `DefaultHandler` (a) -- `fn(u8)` -- the argument is the exception number (VECTACTIVE) /// - `NMI` -- `fn()` -/// - `HardFault` -- `fn() -> !` +/// - `HardFault` -- `fn(&ExceptionFrame) -> !` /// - `MemManage` -- `fn()` /// - `BusFault` -- `fn()` /// - `UsageFault` -- `fn()` @@ -171,7 +208,6 @@ pub static __EXCEPTIONS: [Option<unsafe extern "C" fn()>; 14] = [ /// using this macro. /// /// (b) Not available on ARMv6-M -// XXX should we prevent the fault handlers from returning? #[macro_export] macro_rules! exception { (DefaultHandler, $path:path) => { @@ -179,7 +215,7 @@ macro_rules! exception { #[export_name = "DefaultHandler"] pub unsafe extern "C" fn __impl_DefaultHandler() { // validate the signature of the user provided handler - let f: fn(u8) -> ! = $path; + let f: fn(u8) = $path; const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; @@ -191,12 +227,12 @@ macro_rules! exception { (HardFault, $path:path) => { #[allow(non_snake_case)] - #[export_name = "HardFault"] - pub unsafe extern "C" fn __impl_HardFault() { + #[export_name = "UserHardFault"] + pub unsafe extern "C" fn __impl_UserHardFault(ef: &$crate::ExceptionFrame) { // validate the signature of the user provided handler - let f: fn() -> ! = $path; + let f: fn(&$crate::ExceptionFrame) -> ! = $path; - f() + f(ef) } }; |