aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cortex-m-rt/Cargo.toml5
-rw-r--r--cortex-m-rt/asm.s4
-rw-r--r--cortex-m-rt/build.rs6
-rw-r--r--cortex-m-rt/link.x31
-rw-r--r--cortex-m-rt/memory.x19
-rw-r--r--cortex-m-rt/src/lib.rs56
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)
}
};