diff options
author | 2021-01-21 02:39:12 +0000 | |
---|---|---|
committer | 2021-01-21 13:18:26 +0100 | |
commit | 4426f26ab0aed70ae2cc433f55ee48f62d7eb46b (patch) | |
tree | 57a88f00c50b1f9d22c368c22ef828b8bd1b7d26 | |
parent | 0e82907ca384d10a7fb1f2b8cc70fdb58c0b2fcf (diff) | |
download | cortex-m-4426f26ab0aed70ae2cc433f55ee48f62d7eb46b.tar.gz cortex-m-4426f26ab0aed70ae2cc433f55ee48f62d7eb46b.tar.zst cortex-m-4426f26ab0aed70ae2cc433f55ee48f62d7eb46b.zip |
Update Reset-in-asm.
* Use arm-none-eabi-gcc to assemble, allowing use of preprocessor to
conditionally enable the FPU for eabihf targets.
* Remove has_fpu configuration from build.rs.
* Remove FpuTrampoline as no longer required.
* Remove the Rust Reset method entirely, since the asm Reset can now
enable FPU and jump to user main.
-rw-r--r-- | cortex-m-rt/asm.S | 105 | ||||
-rw-r--r-- | cortex-m-rt/asm.s | 108 | ||||
-rwxr-xr-x | cortex-m-rt/assemble.sh | 14 | ||||
-rw-r--r-- | cortex-m-rt/bin/thumbv6m-none-eabi.a | bin | 1966 -> 1618 bytes | |||
-rw-r--r-- | cortex-m-rt/bin/thumbv7em-none-eabi.a | bin | 1942 -> 1598 bytes | |||
-rw-r--r-- | cortex-m-rt/bin/thumbv7em-none-eabihf.a | bin | 1942 -> 1622 bytes | |||
-rw-r--r-- | cortex-m-rt/bin/thumbv7m-none-eabi.a | bin | 1942 -> 1598 bytes | |||
-rw-r--r-- | cortex-m-rt/bin/thumbv8m.base-none-eabi.a | bin | 1950 -> 1622 bytes | |||
-rw-r--r-- | cortex-m-rt/bin/thumbv8m.main-none-eabi.a | bin | 1946 -> 1602 bytes | |||
-rw-r--r-- | cortex-m-rt/bin/thumbv8m.main-none-eabihf.a | bin | 1946 -> 1626 bytes | |||
-rw-r--r-- | cortex-m-rt/build.rs | 8 | ||||
-rw-r--r-- | cortex-m-rt/link.x.in | 9 | ||||
-rw-r--r-- | cortex-m-rt/src/lib.rs | 63 |
13 files changed, 134 insertions, 173 deletions
diff --git a/cortex-m-rt/asm.S b/cortex-m-rt/asm.S new file mode 100644 index 0000000..6254129 --- /dev/null +++ b/cortex-m-rt/asm.S @@ -0,0 +1,105 @@ + .cfi_sections .debug_frame + + # Notes for function attributes: + # .type and .thumb_func are _both_ required, otherwise the Thumb mode bit + # will not be set and an invalid vector table is generated. + # LLD requires that section flags are set explicitly. + + .section .HardFaultTrampoline, "ax" + .global HardFaultTrampoline + .type HardFaultTrampoline,%function + .thumb_func + .cfi_startproc + # HardFault exceptions are bounced through this trampoline which grabs the + # stack pointer at the time of the exception and passes it to the user's + # HardFault handler in r0. +HardFaultTrampoline: + # Depending on the stack mode in EXC_RETURN, fetch stack pointer from + # PSP or MSP. + mov r0, lr + mov r1, #4 + tst r0, r1 + bne 0f + mrs r0, MSP + b HardFault +0: + mrs r0, PSP + b HardFault + .cfi_endproc + .size HardFaultTrampoline, . - HardFaultTrampoline + + .section .Reset, "ax" + .global Reset + .type Reset,%function + .thumb_func + .cfi_startproc + # Main entry point after reset. This jumps to the user __pre_init function, + # which cannot be called from Rust code without invoking UB, then + # initialises RAM. If the target has an FPU, it is enabled. Finally, jumps + # to the user main function. +Reset: + # ARMv6-M does not initialise LR, but many tools expect it to be 0xFFFF_FFFF + # when reaching the first call frame, so we set it at startup. + # ARMv7-M and above initialise LR to 0xFFFF_FFFF at reset. + ldr r4,=0xffffffff + mov lr,r4 + + # Run user pre-init code, which must be executed immediately after startup, + # before the potentially time-consuming memory initialisation takes place. + # Example use cases include disabling default watchdogs or enabling RAM. + bl __pre_init + + # Restore LR after calling __pre_init (r4 is preserved by subroutines). + mov lr,r4 + + # Initialise .bss memory. `__sbss` and `__ebss` come from the linker script. + ldr r0,=__sbss + ldr r1,=__ebss + mov r2,#0 +0: + cmp r1, r0 + beq 1f + stm r0!, {r2} + b 0b +1: + + # Initialise .data memory. `__sdata`, `__sidata`, and `__edata` come from the + # linker script. Copy from r2 into r0 until r0 reaches r1. + ldr r0,=__sdata + ldr r1,=__edata + ldr r2,=__sidata +2: + cmp r1, r0 + beq 3f + # load 1 word from r2 to r3, inc r2 + ldm r2!, {r3} + # store 1 word from r3 to r0, inc r0 + stm r0!, {r3} + b 2b +3: + +#ifdef HAS_FPU + # Conditionally enable the FPU. + # Address of SCB.CPACR. + ldr r0, =0xE000ED88 + # Enable access to CP10 and CP11 from both privileged and unprivileged mode. + ldr r1, =(0b1111 << 20) + # RMW. + ldr r2, [r0] + orr r2, r2, r1 + str r2, [r0] + # Barrier is required on some processors. + dsb + isb +#endif + +4: + # Jump to user main function. We use bl for the extended range, but the + # user main function may not return. + bl main + + # Trap on return. + udf + + .cfi_endproc + .size Reset, . - Reset diff --git a/cortex-m-rt/asm.s b/cortex-m-rt/asm.s deleted file mode 100644 index 6cae842..0000000 --- a/cortex-m-rt/asm.s +++ /dev/null @@ -1,108 +0,0 @@ - .cfi_sections .debug_frame - - # LLD requires that the section flags are explicitly set here - .section .HardFaultTrampoline, "ax" - .global HardFaultTrampoline - # .type and .thumb_func are both required; otherwise its Thumb bit does not - # get set and an invalid vector table is generated - .type HardFaultTrampoline,%function - .thumb_func - .cfi_startproc -HardFaultTrampoline: - # depending on the stack mode in EXC_RETURN, fetch stack pointer from - # PSP or MSP - mov r0, lr - mov r1, #4 - tst r0, r1 - bne 0f - mrs r0, MSP - b HardFault -0: - mrs r0, PSP - b HardFault - .cfi_endproc - .size HardFaultTrampoline, . - HardFaultTrampoline - - .section .text.FpuTrampoline, "ax" - .global FpuTrampoline - # .type and .thumb_func are both required; otherwise its Thumb bit does not - # get set and an invalid vector table is generated - .type FpuTrampoline,%function - .thumb_func - .cfi_startproc - # This enables the FPU and jumps to the main function. -FpuTrampoline: - # Address of SCB.CPACR. - ldr r0, =0xE000ED88 - # Enable access to CP10 and CP11 from both privileged and unprivileged mode. - ldr r1, =(0b1111 << 20) - # RMW. - ldr r2, [r0] - orr r2, r2, r1 - str r2, [r0] - # Barrier is required on some processors. - dsb - isb - # Hand execution over to `main`. - bl main - # Note: `main` must not return. `bl` is used only because it has a wider range than `b`. - .cfi_endproc - .size FpuTrampoline, . - FpuTrampoline - - .section .PreResetTrampoline, "ax" - .global PreResetTrampoline - # .type and .thumb_func are both required; otherwise its Thumb bit does not - # get set and an invalid vector table is generated - .type PreResetTrampoline,%function - .thumb_func - .cfi_startproc - # Main entry point. This initializes RAM and invokes __pre_init, which cannot be done in Rust code - # without invoking UB. It then jumps to the Rust `Reset` function. -PreResetTrampoline: - # set LR to the initial value used by the ARMv7-M (0xFFFF_FFFF) - ldr r4,=0xffffffff - mov lr,r4 - - # run the pre-init code - # use cases of __pre_init include - # a) disabling an on-by-default watchdog and - # b) enabling off-by-default RAM - # this means it must be done before the potentially slow RAM init code below is executed, and RAM - # must not be accessed before this call - bl __pre_init - - # the call above clobbers LR, but tools may expect LR to be 0xFFFFFFFF when reaching the first - # call frame, so we restore it to its previous value (r4 is preserved by subroutines) - mov lr,r4 - - # initialize .data and .bss memory - ldr r0,=__sbss - ldr r1,=__ebss - ldr r2,=0 -0: - cmp r1, r0 - beq 1f - stm r0!, {r2} - b 0b -1: - - # copy to here - ldr r0,=__sdata - # ...up to here - ldr r1,=__edata - # copy from here - ldr r2,=__sidata -2: - cmp r1, r0 - beq 3f - # load 1 word from r2 to r3, inc r2 - ldm r2!, {r3} - # store 1 word from r3 to r0, inc r0 - stm r0!, {r3} - b 2b -3: - - # jump to Rust - b Reset - .cfi_endproc - .size PreResetTrampoline, . - PreResetTrampoline diff --git a/cortex-m-rt/assemble.sh b/cortex-m-rt/assemble.sh index cdb3205..b914fed 100755 --- a/cortex-m-rt/assemble.sh +++ b/cortex-m-rt/assemble.sh @@ -9,21 +9,25 @@ crate=cortex-m-rt # remove existing blobs because otherwise this will append object files to the old blobs rm -f bin/*.a -arm-none-eabi-as -march=armv6s-m asm.s -o bin/$crate.o +arm-none-eabi-gcc -c -march=armv6s-m asm.S -o bin/$crate.o ar crs bin/thumbv6m-none-eabi.a bin/$crate.o -arm-none-eabi-as -march=armv7-m asm.s -o bin/$crate.o +arm-none-eabi-gcc -c -march=armv7-m asm.S -o bin/$crate.o ar crs bin/thumbv7m-none-eabi.a bin/$crate.o -arm-none-eabi-as -march=armv7e-m asm.s -o bin/$crate.o +arm-none-eabi-gcc -c -march=armv7e-m asm.S -o bin/$crate.o ar crs bin/thumbv7em-none-eabi.a bin/$crate.o + +arm-none-eabi-gcc -c -march=armv7e-m asm.S -DHAS_FPU -o bin/$crate.o ar crs bin/thumbv7em-none-eabihf.a bin/$crate.o -arm-none-eabi-as -march=armv8-m.base asm.s -o bin/$crate.o +arm-none-eabi-gcc -c -march=armv8-m.base asm.S -o bin/$crate.o ar crs bin/thumbv8m.base-none-eabi.a bin/$crate.o -arm-none-eabi-as -march=armv8-m.main asm.s -o bin/$crate.o +arm-none-eabi-gcc -c -march=armv8-m.main asm.S -o bin/$crate.o ar crs bin/thumbv8m.main-none-eabi.a bin/$crate.o + +arm-none-eabi-gcc -c -march=armv8-m.main -DHAS_FPU asm.S -o bin/$crate.o ar crs bin/thumbv8m.main-none-eabihf.a bin/$crate.o rm bin/$crate.o diff --git a/cortex-m-rt/bin/thumbv6m-none-eabi.a b/cortex-m-rt/bin/thumbv6m-none-eabi.a Binary files differindex 263f15a..3ac0777 100644 --- a/cortex-m-rt/bin/thumbv6m-none-eabi.a +++ b/cortex-m-rt/bin/thumbv6m-none-eabi.a diff --git a/cortex-m-rt/bin/thumbv7em-none-eabi.a b/cortex-m-rt/bin/thumbv7em-none-eabi.a Binary files differindex 56c3c06..d38ee46 100644 --- a/cortex-m-rt/bin/thumbv7em-none-eabi.a +++ b/cortex-m-rt/bin/thumbv7em-none-eabi.a diff --git a/cortex-m-rt/bin/thumbv7em-none-eabihf.a b/cortex-m-rt/bin/thumbv7em-none-eabihf.a Binary files differindex 56c3c06..a782dce 100644 --- a/cortex-m-rt/bin/thumbv7em-none-eabihf.a +++ b/cortex-m-rt/bin/thumbv7em-none-eabihf.a diff --git a/cortex-m-rt/bin/thumbv7m-none-eabi.a b/cortex-m-rt/bin/thumbv7m-none-eabi.a Binary files differindex 1680a5b..038af9f 100644 --- a/cortex-m-rt/bin/thumbv7m-none-eabi.a +++ b/cortex-m-rt/bin/thumbv7m-none-eabi.a diff --git a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a b/cortex-m-rt/bin/thumbv8m.base-none-eabi.a Binary files differindex 3128cf0..ad383aa 100644 --- a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a +++ b/cortex-m-rt/bin/thumbv8m.base-none-eabi.a diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a b/cortex-m-rt/bin/thumbv8m.main-none-eabi.a Binary files differindex 691a095..ef6e77a 100644 --- a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a +++ b/cortex-m-rt/bin/thumbv8m.main-none-eabi.a diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a b/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a Binary files differindex 691a095..44380fb 100644 --- a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a +++ b/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index 67cdfab..c56f14c 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -7,8 +7,6 @@ fn main() { let target = env::var("TARGET").unwrap(); let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - has_fpu(&target); - if target.starts_with("thumbv") { fs::copy( format!("bin/{}.a", target), @@ -81,9 +79,3 @@ handlers."); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=link.x.in"); } - -fn has_fpu(target: &str) { - if target.ends_with("eabihf") { - println!("cargo:rustc-cfg=has_fpu"); - } -} diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index f1a921d..78fa825 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -23,8 +23,9 @@ INCLUDE memory.x /* # Entry point = reset vector */ +EXTERN(__RESET_VECTOR); +EXTERN(Reset); ENTRY(Reset); -EXTERN(__RESET_VECTOR); /* depends on the `Reset` symbol */ /* # Exception vectors */ /* This is effectively weak aliasing at the linker level */ @@ -85,13 +86,15 @@ SECTIONS /* ### .text */ .text _stext : { - /* place these 2 close to each other or the `b` instruction will fail to link */ - *(.PreResetTrampoline); *(.Reset); *(.text .text.*); + + /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`, + so must be placed close to it. */ *(.HardFaultTrampoline); *(.HardFault.*); + . = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */ } > FLASH . = ALIGN(4); /* Ensure __etext is aligned if something unaligned is inserted after .text */ diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 5285bd1..e5e290d 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -192,11 +192,9 @@ //! //! One will always find the following (unmangled) symbols in `cortex-m-rt` applications: //! -//! - `Reset`. This is the reset handler. The microcontroller will executed this function upon +//! - `Reset`. This is the reset handler. The microcontroller will execute this function upon //! booting. This function will call the user program entry point (cf. [`#[entry]`][attr-entry]) -//! using the `main` symbol so you may also find that symbol in your program; if you do, `main` -//! will contain your application code. Some other times `main` gets inlined into `Reset` so you -//! won't find it. +//! using the `main` symbol so you will also find that symbol in your program. //! //! - `DefaultHandler`. This is the default handler. If not overridden using `#[exception] fn //! DefaultHandler(..` this will be an infinite loop. @@ -212,8 +210,8 @@ //! the initial value of the stack pointer; this is where the stack will be located -- the stack //! grows downwards towards smaller addresses. //! -//! - `__RESET_VECTOR`. This is the reset vector, a pointer into the `Reset` handler. This vector is -//! located in the `.vector_table` section after `__STACK_START`. +//! - `__RESET_VECTOR`. This is the reset vector, a pointer to the `Reset` function. This vector +//! is located in the `.vector_table` section after `__STACK_START`. //! //! - `__EXCEPTIONS`. This is the core exceptions portion of the vector table; it's an array of 14 //! exception vectors, which includes exceptions like `HardFault` and `SysTick`. This array is @@ -226,19 +224,11 @@ //! //! - `__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 applying the [`#[pre_init]`][attr-pre_init] -//! attribute to a function. The empty function is not optimized out by default, but if an empty -//! function is passed to [`#[pre_init]`][attr-pre_init] the function call will be optimized out. +//! attribute to a function. //! //! If you override any exception handler you'll find it as an unmangled symbol, e.g. `SysTick` or //! `SVCall`, in the output of `objdump`, //! -//! If you are targeting the `thumbv7em-none-eabihf` target you'll also see a `ResetTrampoline` -//! symbol in the output. To avoid the compiler placing FPU instructions before the FPU has been -//! enabled (cf. `vpush`) `Reset` calls the function `ResetTrampoline` which is marked as -//! `#[inline(never)]` and `ResetTrampoline` calls `main`. The compiler is free to inline `main` -//! into `ResetTrampoline` but it can't inline `ResetTrampoline` into `Reset` -- the FPU is enabled -//! in `Reset`. -//! //! # Advanced usage //! //! ## Setting the program entry point @@ -248,9 +238,9 @@ //! guarantees. //! //! The `Reset` handler will call a symbol named `main` (unmangled) *after* initializing `.bss` and -//! `.data`, and enabling the FPU (if the target is `thumbv7em-none-eabihf`). A function with the -//! `entry` attribute will be set to have the export name "`main`"; in addition, its mutable -//! statics are turned into safe mutable references (see [`#[entry]`][attr-entry] for details). +//! `.data`, and enabling the FPU (if the target has an FPU). A function with the `entry` attribute +//! will be set to have the export name "`main`"; in addition, its mutable statics are turned into +//! safe mutable references (see [`#[entry]`][attr-entry] for details). //! //! The unmangled `main` symbol must have signature `extern "C" fn() -> !` or its invocation from //! `Reset` will result in undefined behavior. @@ -411,7 +401,7 @@ //! *(.ccmram .ccmram.*); //! . = ALIGN(4); //! } > CCMRAM -//! } INSERT AFTER .bss; +//! } //! ``` //! //! You can then use something like this to place a variable into this specific section of memory: @@ -700,8 +690,8 @@ pub use macros::exception; /// /// # Safety /// -/// The function will be called before static variables are initialized. Any access of static -/// variables will result in undefined behavior. +/// The function will be called before memory is initialized, as soon as possible after reset. Any +/// access of memory, including any static variables, will result in undefined behavior. /// /// **Warning**: Due to [rvalue static promotion][rfc1414] static variables may be accessed whenever /// taking a reference to a constant. This means that even trivial expressions such as `&1` in the @@ -918,36 +908,11 @@ pub fn heap_start() -> *mut u32 { unsafe { &mut __sheap } } -/* Entry point */ +// Entry point is Reset. #[doc(hidden)] #[link_section = ".vector_table.reset_vector"] #[no_mangle] -pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = PreResetTrampoline; - -#[doc(hidden)] -#[link_section = ".Reset"] -#[no_mangle] -pub unsafe extern "C" fn Reset() -> ! { - #[allow(clippy::match_single_binding)] - match () { - #[cfg(not(has_fpu))] - () => { - extern "C" { - // This symbol will be provided by the user via `#[entry]` - fn main() -> !; - } - main() - } - #[cfg(has_fpu)] - () => { - extern "C" { - fn FpuTrampoline() -> !; - } - - FpuTrampoline() - } - } -} +pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; #[allow(unused_variables)] #[doc(hidden)] @@ -1008,7 +973,7 @@ pub enum Exception { pub use self::Exception as exception; extern "C" { - fn PreResetTrampoline() -> !; + fn Reset() -> !; fn NonMaskableInt(); |