aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cargo/config2
-rw-r--r--.travis.yml1
-rw-r--r--Cargo.toml12
-rw-r--r--asm-cm7-r0p1.s35
-rw-r--r--asm-fpu.s21
-rw-r--r--asm-toolchain1
-rw-r--r--asm-v7.s78
-rw-r--r--asm-v8-main.s43
-rw-r--r--asm-v8.s42
-rw-r--r--asm.rs346
-rw-r--r--asm.s192
-rwxr-xr-xassemble.sh47
-rw-r--r--bin/thumbv6m-none-eabi-lto.abin0 -> 12016 bytes
-rw-r--r--bin/thumbv6m-none-eabi.abin5782 -> 16188 bytes
-rw-r--r--bin/thumbv7em-none-eabi-lto.abin0 -> 16704 bytes
-rw-r--r--bin/thumbv7em-none-eabi.abin11130 -> 20056 bytes
-rw-r--r--bin/thumbv7em-none-eabihf-lto.abin0 -> 17504 bytes
-rw-r--r--bin/thumbv7em-none-eabihf.abin13164 -> 21112 bytes
-rw-r--r--bin/thumbv7m-none-eabi-lto.abin0 -> 15436 bytes
-rw-r--r--bin/thumbv7m-none-eabi.abin8920 -> 19044 bytes
-rw-r--r--bin/thumbv8m.base-none-eabi-lto.abin0 -> 13392 bytes
-rw-r--r--bin/thumbv8m.base-none-eabi.abin8198 -> 17976 bytes
-rw-r--r--bin/thumbv8m.main-none-eabi-lto.abin0 -> 18040 bytes
-rw-r--r--bin/thumbv8m.main-none-eabi.abin13908 -> 22776 bytes
-rw-r--r--bin/thumbv8m.main-none-eabihf-lto.abin0 -> 18776 bytes
-rw-r--r--bin/thumbv8m.main-none-eabihf.abin15948 -> 23764 bytes
-rw-r--r--build.rs13
-rwxr-xr-xcheck-blobs.sh21
-rw-r--r--ci/install.sh4
-rw-r--r--ci/script.sh2
-rw-r--r--src/lib.rs26
-rw-r--r--xtask/Cargo.toml9
-rw-r--r--xtask/src/main.rs216
33 files changed, 619 insertions, 492 deletions
diff --git a/.cargo/config b/.cargo/config
new file mode 100644
index 0000000..8628170
--- /dev/null
+++ b/.cargo/config
@@ -0,0 +1,2 @@
+[alias]
+xtask = "run --package xtask --bin xtask --"
diff --git a/.travis.yml b/.travis.yml
index bbe3d48..7f25eae 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -72,7 +72,6 @@ before_install: set -e
install:
- bash ci/install.sh
- - export PATH="$PATH:$PWD/gcc/bin"
script:
- bash ci/script.sh
diff --git a/Cargo.toml b/Cargo.toml
index 2e55f6a..eddc6fa 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,6 +21,14 @@ volatile-register = "0.2.0"
bitfield = "0.13.2"
embedded-hal = "0.2.4"
+[features]
+cm7-r0p1 = []
+inline-asm = []
+linker-plugin-lto = []
+
+[workspace]
+members = ["xtask"]
+
[package.metadata.docs.rs]
targets = [
"thumbv8m.main-none-eabihf",
@@ -31,7 +39,3 @@ targets = [
"thumbv8m.base-none-eabi",
"thumbv8m.main-none-eabi"
]
-
-[features]
-cm7-r0p1 = []
-inline-asm = []
diff --git a/asm-cm7-r0p1.s b/asm-cm7-r0p1.s
deleted file mode 100644
index 28c3384..0000000
--- a/asm-cm7-r0p1.s
+++ /dev/null
@@ -1,35 +0,0 @@
- .cfi_sections .debug_frame
-
- .section .text.__basepri_max_cm7_r0p1
- .global __basepri_max_cm7_r0p1
- .syntax unified
- .thumb_func
- .cfi_startproc
-__basepri_max_cm7_r0p1:
- mrs r1, PRIMASK
- cpsid i
- tst.w r1, #1
- msr BASEPRI_MAX, r0
- it ne
- bxne lr
- cpsie i
- bx lr
- .cfi_endproc
- .size __basepri_max_cm7_r0p1, . - __basepri_max_cm7_r0p1
-
- .section .text.__basepri_w_cm7_r0p1
- .global __basepri_w_cm7_r0p1
- .syntax unified
- .thumb_func
- .cfi_startproc
-__basepri_w_cm7_r0p1:
- mrs r1, PRIMASK
- cpsid i
- tst.w r1, #1
- msr BASEPRI, r0
- it ne
- bxne lr
- cpsie i
- bx lr
- .cfi_endproc
- .size __basepri_w_cm7_r0p1, . - __basepri_w_cm7_r0p1
diff --git a/asm-fpu.s b/asm-fpu.s
deleted file mode 100644
index 417d199..0000000
--- a/asm-fpu.s
+++ /dev/null
@@ -1,21 +0,0 @@
- .cfi_sections .debug_frame
-
- .section .text.__get_FPSCR
- .global __get_FPSCR
- .thumb_func
- .cfi_startproc
-__get_FPSCR:
- vmrs r0, fpscr
- bx lr
- .cfi_endproc
- .size __get_FPSCR, . - __get_FPSCR
-
- .section .text.__set_FPSCR
- .global __set_FPSCR
- .thumb_func
- .cfi_startproc
-__set_FPSCR:
- vmsr fpscr, r0
- bx lr
- .cfi_endproc
- .size __set_FPSCR, . - __set_FPSCR
diff --git a/asm-toolchain b/asm-toolchain
new file mode 100644
index 0000000..a36829b
--- /dev/null
+++ b/asm-toolchain
@@ -0,0 +1 @@
+nightly-2020-08-26
diff --git a/asm-v7.s b/asm-v7.s
deleted file mode 100644
index 17d7110..0000000
--- a/asm-v7.s
+++ /dev/null
@@ -1,78 +0,0 @@
- .syntax unified
- .cfi_sections .debug_frame
-
- .section .text.__basepri_max
- .global __basepri_max
- .thumb_func
- .cfi_startproc
-__basepri_max:
- msr BASEPRI_MAX, r0
- bx lr
- .cfi_endproc
- .size __basepri_max, . - __basepri_max
-
- .section .text.__basepri_r
- .global __basepri_r
- .thumb_func
- .cfi_startproc
-__basepri_r:
- mrs r0, BASEPRI
- bx lr
- .cfi_endproc
- .size __basepri_r, . - __basepri_r
-
- .section .text.__basepri_w
- .global __basepri_w
- .thumb_func
- .cfi_startproc
-__basepri_w:
- msr BASEPRI, r0
- bx lr
- .cfi_endproc
- .size __basepri_w, . - __basepri_w
-
- .section .text.__faultmask
- .global __faultmask
- .thumb_func
- .cfi_startproc
-__faultmask:
- mrs r0, FAULTMASK
- bx lr
- .cfi_endproc
- .size __faultmask, . - __faultmask
-
- .section .text.__enable_icache
- .global __enable_icache
- .thumb_func
- .cfi_startproc
-__enable_icache:
- ldr r0, =0xE000ED14 @ CCR
- mrs r2, PRIMASK @ save critical nesting info
- cpsid i @ mask interrupts
- ldr r1, [r0] @ read CCR
- orr.w r1, r1, #(1 << 17) @ Set bit 17, IC
- str r1, [r0] @ write it back
- dsb @ ensure store completes
- isb @ synchronize pipeline
- msr PRIMASK, r2 @ unnest critical section
- bx lr
- .cfi_endproc
- .size __enable_icache, . - __enable_icache
-
- .section .text.__enable_dcache
- .global __enable_dcache
- .thumb_func
- .cfi_startproc
-__enable_dcache:
- ldr r0, =0xE000ED14 @ CCR
- mrs r2, PRIMASK @ save critical nesting info
- cpsid i @ mask interrupts
- ldr r1, [r0] @ read CCR
- orr.w r1, r1, #(1 << 16) @ Set bit 16, DC
- str r1, [r0] @ write it back
- dsb @ ensure store completes
- isb @ synchronize pipeline
- msr PRIMASK, r2 @ unnest critical section
- bx lr
- .cfi_endproc
- .size __enable_dcache, . - __enable_dcache
diff --git a/asm-v8-main.s b/asm-v8-main.s
deleted file mode 100644
index 1fad155..0000000
--- a/asm-v8-main.s
+++ /dev/null
@@ -1,43 +0,0 @@
-
- .cfi_sections .debug_frame
-
- .section .text.__msplim_r
- .global __msplim_r
- .thumb_func
- .cfi_startproc
-__msplim_r:
- mrs r0, MSPLIM
- bx lr
- .cfi_endproc
- .size __msplim_r, . - __msplim_r
-
- .section .text.__msplim_w
- .global __msplim_w
- .thumb_func
- .cfi_startproc
-__msplim_w:
- msr MSPLIM, r0
- bx lr
- .cfi_endproc
- .size __msplim_w, . - __msplim_w
-
- .section .text.__psplim_r
- .global __psplim_r
- .thumb_func
- .cfi_startproc
-__psplim_r:
- mrs r0, PSPLIM
- bx lr
- .cfi_endproc
- .size __psplim_r, . - __psplim_r
-
- .section .text.__psplim_w
- .global __psplim_w
- .thumb_func
- .cfi_startproc
-__psplim_w:
- msr PSPLIM, r0
- bx lr
- .cfi_endproc
- .size __psplim_w, . - __psplim_w
-
diff --git a/asm-v8.s b/asm-v8.s
deleted file mode 100644
index 7d3a8c9..0000000
--- a/asm-v8.s
+++ /dev/null
@@ -1,42 +0,0 @@
- .cfi_sections .debug_frame
-
- .section .text.__tt
- .global __tt
- .thumb_func
- .cfi_startproc
-__tt:
- tt r0, r0
- bx lr
- .cfi_endproc
- .size __tt, . - __tt
-
- .section .text.__ttt
- .global __ttt
- .thumb_func
- .cfi_startproc
-__ttt:
- ttt r0, r0
- bx lr
- .cfi_endproc
- .size __ttt, . - __ttt
-
- .section .text.__tta
- .global __tta
- .thumb_func
- .cfi_startproc
-__tta:
- tta r0, r0
- bx lr
- .cfi_endproc
- .size __tta, . - __tta
-
-
- .section .text.__ttat
- .global __ttat
- .thumb_func
- .cfi_startproc
-__ttat:
- ttat r0, r0
- bx lr
- .cfi_endproc
- .size __ttat, . - __ttat
diff --git a/asm.rs b/asm.rs
new file mode 100644
index 0000000..f5b0179
--- /dev/null
+++ b/asm.rs
@@ -0,0 +1,346 @@
+//! Assembly stubs for the `cortex-m` crate.
+//!
+//! We use this file to precompile some assembly stubs into the static libraries you can find in
+//! `bin`. Apps using the `cortex-m` crate then link against those static libraries and don't need
+//! to build this file themselves.
+//!
+//! Nowadays the assembly stubs are no longer actual assembly files, but actually just this Rust
+//! file `asm.rs` that uses unstable inline assembly, coupled with the `xtask` tool to invoke rustc
+//! and build the files.
+//!
+//! Precompiling this to a static lib allows users to call assembly routines from stable Rust, but
+//! also perform [linker plugin LTO] with the precompiled artifacts to completely inline the
+//! assembly routines into their code, which brings the "outline assembly" on par with "real" inline
+//! assembly.
+//!
+//! For developers and contributors to `cortex-m`, this setup means that they don't have to install
+//! any binutils, assembler, or C compiler to hack on the crate. All they need is to run `cargo
+//! xtask assemble` to rebuild the archives from this file.
+//!
+//! Cool, right?
+//!
+//! # Rust version management
+//!
+//! Since inline assembly is still unstable, and we want to ensure that the created blobs are
+//! up-to-date in CI, we have to pin the nightly version we use for this. The nightly toolchain is
+//! stored in `asm-toolchain`.
+//!
+//! The `cargo xtask` automation will automatically install the `asm-toolchain` as well as all
+//! Cortex-M targets needed to generate the blobs.
+//!
+//! [linker plugin LTO]: https://doc.rust-lang.org/stable/rustc/linker-plugin-lto.html
+
+#![feature(asm)]
+#![no_std]
+#![crate_type = "staticlib"]
+#![deny(warnings)]
+
+#[no_mangle]
+pub unsafe extern "C" fn __bkpt() {
+ asm!("bkpt");
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __control_r() -> u32 {
+ let r;
+ asm!("mrs {}, CONTROL", out(reg) r);
+ r
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __control_w(w: u32) {
+ asm!("msr CONTROL, {}", in(reg) w);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __cpsid() {
+ asm!("cpsid i");
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __cpsie() {
+ asm!("cpsie i");
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __delay(cyc: u32) {
+ asm!("
+ 1:
+ nop
+ subs {}, #1
+ bne 1b
+ // Branch to 1 instead of __delay does not generate R_ARM_THM_JUMP8 relocation, which breaks
+ // linking on the thumbv6m-none-eabi target
+ ", in(reg) cyc);
+}
+
+// FIXME do we need compiler fences here or should we expect them in the caller?
+#[no_mangle]
+pub unsafe extern "C" fn __dmb() {
+ asm!("dmb 0xF");
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __dsb() {
+ asm!("dsb 0xF");
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __isb() {
+ asm!("isb 0xF");
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __msp_r() -> u32 {
+ let r;
+ asm!("mrs {}, MSP", out(reg) r);
+ r
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __msp_w(val: u32) {
+ asm!("msr MSP, {}", in(reg) val);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __nop() {
+ // NOTE: This is a `pure` asm block, but applying that option allows the compiler to eliminate
+ // the nop entirely (or to collapse multiple subsequent ones). Since the user probably wants N
+ // nops when they call `nop` N times, let's not add that option.
+ asm!("nop");
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __primask() -> u32 {
+ // FIXME: rename to __primask_r
+ let r;
+ asm!("mrs {}, PRIMASK", out(reg) r);
+ r
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __psp_r() -> u32 {
+ let r;
+ asm!("mrs {}, PSP", out(reg) r);
+ r
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __psp_w(val: u32) {
+ asm!("msr PSP, {}", in(reg) val);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __sev() {
+ asm!("sev");
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __udf() {
+ asm!("udf #0");
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __wfe() {
+ asm!("wfe");
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __wfi() {
+ asm!("wfi");
+}
+
+#[cfg(armv7m)]
+pub mod v7m {
+ #[no_mangle]
+ pub unsafe extern "C" fn __basepri_max(val: u8) {
+ asm!("msr BASEPRI_MAX, {}", in(reg) val);
+ }
+
+ #[no_mangle]
+ pub unsafe extern "C" fn __basepri_r() -> u8 {
+ let r;
+ asm!("mrs {}, BASEPRI", out(reg) r);
+ r
+ }
+
+ #[no_mangle]
+ pub unsafe extern "C" fn __basepri_w(val: u8) {
+ asm!("msr BASEPRI, {}", in(reg) val);
+ }
+
+ #[no_mangle]
+ pub unsafe extern "C" fn __faultmask() -> u32 {
+ let r;
+ asm!("mrs {}, FAULTMASK", out(reg) r);
+ r
+ }
+
+ // FIXME: compiler_fences necessary?
+ #[no_mangle]
+ pub unsafe extern "C" fn __enable_icache() {
+ asm!(
+ "
+ ldr r0, =0xE000ED14 @ CCR
+ mrs r2, PRIMASK @ save critical nesting info
+ cpsid i @ mask interrupts
+ ldr r1, [r0] @ read CCR
+ orr.w r1, r1, #(1 << 17) @ Set bit 17, IC
+ str r1, [r0] @ write it back
+ dsb @ ensure store completes
+ isb @ synchronize pipeline
+ msr PRIMASK, r2 @ unnest critical section
+ ",
+ out("r0") _,
+ out("r1") _,
+ out("r2") _,
+ );
+ }
+
+ #[no_mangle]
+ pub unsafe extern "C" fn __enable_dcache() {
+ asm!(
+ "
+ ldr r0, =0xE000ED14 @ CCR
+ mrs r2, PRIMASK @ save critical nesting info
+ cpsid i @ mask interrupts
+ ldr r1, [r0] @ read CCR
+ orr.w r1, r1, #(1 << 16) @ Set bit 16, DC
+ str r1, [r0] @ write it back
+ dsb @ ensure store completes
+ isb @ synchronize pipeline
+ msr PRIMASK, r2 @ unnest critical section
+ ",
+ out("r0") _,
+ out("r1") _,
+ out("r2") _,
+ );
+ }
+}
+
+#[cfg(armv7em)]
+mod v7em {
+ #[no_mangle]
+ pub unsafe extern "C" fn __basepri_max_cm7_r0p1(val: u8) {
+ asm!(
+ "
+ mrs r1, PRIMASK
+ cpsid i
+ tst.w r1, #1
+ msr BASEPRI_MAX, {}
+ it ne
+ bxne lr
+ cpsie i
+ ",
+ in(reg) val,
+ out("r1") _,
+ );
+ }
+
+ #[no_mangle]
+ pub unsafe extern "C" fn __basepri_w_cm7_r0p1(val: u8) {
+ asm!(
+ "
+ mrs r1, PRIMASK
+ cpsid i
+ tst.w r1, #1
+ msr BASEPRI, {}
+ it ne
+ bxne lr
+ cpsie i
+ ",
+ in(reg) val,
+ out("r1") _,
+ );
+ }
+}
+
+/// Baseline and Mainline.
+#[cfg(armv8m)]
+pub mod v8m {
+ #[no_mangle]
+ pub unsafe extern "C" fn __tt(mut target: u32) -> u32 {
+ asm!("tt {target}, {target}", target = inout(reg) target);
+ target
+ }
+
+ #[no_mangle]
+ pub unsafe extern "C" fn __ttt(mut target: u32) -> u32 {
+ asm!("ttt {target}, {target}", target = inout(reg) target);
+ target
+ }
+
+ #[no_mangle]
+ pub unsafe extern "C" fn __tta(mut target: u32) -> u32 {
+ asm!("tta {target}, {target}", target = inout(reg) target);
+ target
+ }
+
+ #[no_mangle]
+ pub unsafe extern "C" fn __ttat(mut target: u32) -> u32 {
+ asm!("ttat {target}, {target}", target = inout(reg) target);
+ target
+ }
+}
+
+/// Mainline only.
+#[cfg(armv8m_main)]
+pub mod v8m_main {
+ #[no_mangle]
+ pub unsafe extern "C" fn __msplim_r() -> u32 {
+ let r;
+ asm!("mrs {}, MSPLIM", out(reg) r);
+ r
+ }
+
+ #[no_mangle]
+ pub unsafe extern "C" fn __msplim_w(val: u32) {
+ asm!("msr MSPLIM, {}", in(reg) val);
+ }
+
+ #[no_mangle]
+ pub unsafe extern "C" fn __psplim_r() -> u32 {
+ let r;
+ asm!("mrs {}, PSPLIM", out(reg) r);
+ r
+ }
+
+ #[no_mangle]
+ pub unsafe extern "C" fn __psplim_w(val: u32) {
+ asm!("msr PSPLIM, {}", in(reg) val);
+ }
+}
+
+/// All targets with FPU.
+#[cfg(has_fpu)]
+pub mod fpu {
+ #[no_mangle]
+ pub unsafe extern "C" fn __get_FPSCR() -> u32 {
+ let r;
+ asm!("vmrs {}, fpscr", out(reg) r);
+ r
+ }
+
+ #[no_mangle]
+ pub unsafe extern "C" fn __set_FPSCR(val: u32) {
+ asm!("vmsr fpscr, {}", in(reg) val);
+ }
+}
+
+/// We *must* define a panic handler here, even though nothing here should ever be able to panic.
+///
+/// We prove that nothing will ever panic by calling a function that doesn't exist. If the panic
+/// handler gets linked in, this causes a linker error. We always build this file with optimizations
+/// enabled, but even without them the panic handler should never be linked in.
+#[panic_handler]
+fn panic(_: &core::panic::PanicInfo) -> ! {
+ extern "C" {
+ #[link_name = "cortex-m internal error: panic handler not optimized out, please file an \
+ issue at https://github.com/rust-embedded/cortex-m"]
+ fn __cortex_m_should_not_panic() -> !;
+ }
+
+ unsafe {
+ __cortex_m_should_not_panic();
+ }
+}
diff --git a/asm.s b/asm.s
deleted file mode 100644
index 3d1a54b..0000000
--- a/asm.s
+++ /dev/null
@@ -1,192 +0,0 @@
- .cfi_sections .debug_frame
-
- .section .text.__bkpt
- .global __bkpt
- .thumb_func
- .cfi_startproc
-__bkpt:
- bkpt
- bx lr
- .cfi_endproc
- .size __bkpt, . - __bkpt
-
- .section .text.__control_r
- .global __control_r
- .thumb_func
- .cfi_startproc
-__control_r:
- mrs r0, CONTROL
- bx lr
- .cfi_endproc
- .size __control_r, . - __control_r
-
- .section .text.__control_w
- .global __control_w
- .thumb_func
- .cfi_startproc
-__control_w:
- msr CONTROL, r0
- bx lr
- .cfi_endproc
- .size __control_w, . - __control_w
-
-
- .section .text.__cpsid
- .global __cpsid
- .thumb_func
- .cfi_startproc
-__cpsid:
- cpsid i
- bx lr
- .cfi_endproc
- .size __cpsid, . - __cpsid
-
- .section .text.__cpsie
- .global __cpsie
- .thumb_func
- .cfi_startproc
-__cpsie:
- cpsie i
- bx lr
- .cfi_endproc
- .size __cpsie, . - __cpsie
-
- .section .text.__delay
- .global __delay
- .syntax unified
- .thumb_func
- .cfi_startproc
-__delay:
-1:
- nop
- subs r0, #1
- bne 1b // Branch to 1 instead of __delay does not generate R_ARM_THM_JUMP8 relocation, which breaks linking on the thumbv6m-none-eabi target
- bx lr
- .cfi_endproc
- .size __delay, . - __delay
-
- .section .text.__dmb
- .global __dmb
- .thumb_func
- .cfi_startproc
-__dmb:
- dmb 0xF
- bx lr
- .cfi_endproc
- .size __dmb, . - __dmb
-
- .section .text.__dsb
- .global __dsb
- .thumb_func
- .cfi_startproc
-__dsb:
- dsb 0xF
- bx lr
- .cfi_endproc
- .size __dsb, . - __dsb
-
- .section .text.__isb
- .global __isb
- .thumb_func
- .cfi_startproc
-__isb:
- isb 0xF
- bx lr
- .cfi_endproc
- .size __isb, . - __isb
-
- .section .text.__msp_r
- .global __msp_r
- .thumb_func
- .cfi_startproc
-__msp_r:
- mrs r0, MSP
- bx lr
- .cfi_endproc
- .size __msp_r, . - __msp_r
-
- .section .text.__msp_w
- .global __msp_w
- .thumb_func
-__msp_w:
- msr MSP, r0
- bx lr
- .size __msp_w, . - __msp_w
-
- .section .text.__nop
- .global __nop
- .thumb_func
- .cfi_startproc
-__nop:
- bx lr
- .cfi_endproc
- .size __nop, . - __nop
-
- .section .text.__primask
- .global __primask
- .thumb_func
- .cfi_startproc
-__primask:
- mrs r0, PRIMASK
- bx lr
- .cfi_endproc
- .size __primask, . - __primask
-
- .section .text.__psp_r
- .global __psp_r
- .thumb_func
- .cfi_startproc
-__psp_r:
- mrs r0, PSP
- bx lr
- .cfi_endproc
- .size __psp_r, . - __psp_r
-
- .section .text.__psp_w
- .global __psp_w
- .thumb_func
-__psp_w:
- msr PSP, r0
- bx lr
- .size __psp_w, . - __psp_w
-
- .section .text.__sev
- .global __sev
- .thumb_func
- .cfi_startproc
-__sev:
- sev
- bx lr
- .cfi_endproc
- .size __sev, . - __sev
-
-
- .section .text.__udf
- .global __udf
- .thumb_func
- .cfi_startproc
-__udf:
- udf
- .cfi_endproc
- .size __udf, . - __udf
-
- .section .text.__wfe
- .global __wfe
- .thumb_func
- .cfi_startproc
-__wfe:
- wfe
- bx lr
- .cfi_endproc
- .size __wfe, . - __wfe
-
-
- .section .text.__wfi
- .global __wfi
- .thumb_func
- .cfi_startproc
-__wfi:
- wfi
- bx lr
- .cfi_endproc
- .size __wfi, . - __wfi
diff --git a/assemble.sh b/assemble.sh
deleted file mode 100755
index 070481a..0000000
--- a/assemble.sh
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env bash
-
-set -euxo pipefail
-
-# cflags taken from cc 1.0.22
-
-crate=cortex-m
-
-# remove existing blobs because otherwise this will append object files to the old blobs
-rm -f bin/*.a
-
-pwd=$(pwd)
-flags=(-g --debug-prefix-map "$pwd=.")
-
-arm-none-eabi-as "${flags[@]}" -march=armv6s-m asm.s -o bin/$crate.o
-ar crs bin/thumbv6m-none-eabi.a bin/$crate.o
-
-arm-none-eabi-as "${flags[@]}" -march=armv7-m asm.s -o bin/$crate.o
-arm-none-eabi-as "${flags[@]}" -march=armv7-m asm-v7.s -o bin/$crate-v7.o
-ar crs bin/thumbv7m-none-eabi.a bin/$crate.o bin/$crate-v7.o
-
-arm-none-eabi-as "${flags[@]}" -march=armv7e-m asm.s -o bin/$crate.o
-arm-none-eabi-as "${flags[@]}" -march=armv7e-m asm-fpu.s -mfpu=fpv4-sp-d16 -o bin/$crate-v7-fpu.o
-arm-none-eabi-as "${flags[@]}" -march=armv7e-m asm-cm7-r0p1.s -o bin/$crate-cm7-r0p1.o
-arm-none-eabi-as "${flags[@]}" -march=armv7e-m asm-v7.s -o bin/$crate-v7.o
-ar crs bin/thumbv7em-none-eabi.a bin/$crate.o bin/$crate-v7.o bin/$crate-cm7-r0p1.o
-ar crs bin/thumbv7em-none-eabihf.a bin/$crate.o bin/$crate-v7.o bin/$crate-cm7-r0p1.o bin/$crate-v7-fpu.o
-
-arm-none-eabi-as "${flags[@]}" -march=armv8-m.base asm.s -o bin/$crate.o
-arm-none-eabi-as "${flags[@]}" -march=armv8-m.base asm-v8.s -o bin/$crate-v8.o
-ar crs bin/thumbv8m.base-none-eabi.a bin/$crate.o bin/$crate-v8.o
-
-arm-none-eabi-as "${flags[@]}" -march=armv8-m.main asm.s -o bin/$crate.o
-arm-none-eabi-as "${flags[@]}" -march=armv8-m.main asm-v7.s -o bin/$crate-v7.o
-arm-none-eabi-as "${flags[@]}" -march=armv8-m.main asm-v8.s -o bin/$crate-v8.o
-arm-none-eabi-as "${flags[@]}" -march=armv8-m.main asm-v8-main.s -o bin/$crate-v8-main.o
-arm-none-eabi-as "${flags[@]}" -march=armv8-m.main asm-fpu.s -mfpu=fpv5-sp-d16 -o bin/$crate-v8-fpu.o
-ar crs bin/thumbv8m.main-none-eabi.a bin/$crate.o bin/$crate-v7.o bin/$crate-v8.o bin/$crate-v8-main.o
-ar crs bin/thumbv8m.main-none-eabihf.a bin/$crate.o bin/$crate-v7.o bin/$crate-v8.o bin/$crate-v8-main.o bin/$crate-v8-fpu.o
-
-rm bin/$crate.o
-rm bin/$crate-v7.o
-rm bin/$crate-v7-fpu.o
-rm bin/$crate-v8-fpu.o
-rm bin/$crate-cm7-r0p1.o
-rm bin/$crate-v8.o
-rm bin/$crate-v8-main.o
diff --git a/bin/thumbv6m-none-eabi-lto.a b/bin/thumbv6m-none-eabi-lto.a
new file mode 100644
index 0000000..4d2f02c
--- /dev/null
+++ b/bin/thumbv6m-none-eabi-lto.a
Binary files differ
diff --git a/bin/thumbv6m-none-eabi.a b/bin/thumbv6m-none-eabi.a
index b2f72b4..beedd73 100644
--- a/bin/thumbv6m-none-eabi.a
+++ b/bin/thumbv6m-none-eabi.a
Binary files differ
diff --git a/bin/thumbv7em-none-eabi-lto.a b/bin/thumbv7em-none-eabi-lto.a
new file mode 100644
index 0000000..7b8a4f8
--- /dev/null
+++ b/bin/thumbv7em-none-eabi-lto.a
Binary files differ
diff --git a/bin/thumbv7em-none-eabi.a b/bin/thumbv7em-none-eabi.a
index 5d5c48f..588e5cd 100644
--- a/bin/thumbv7em-none-eabi.a
+++ b/bin/thumbv7em-none-eabi.a
Binary files differ
diff --git a/bin/thumbv7em-none-eabihf-lto.a b/bin/thumbv7em-none-eabihf-lto.a
new file mode 100644
index 0000000..4efadd8
--- /dev/null
+++ b/bin/thumbv7em-none-eabihf-lto.a
Binary files differ
diff --git a/bin/thumbv7em-none-eabihf.a b/bin/thumbv7em-none-eabihf.a
index 1570f83..fd08ba5 100644
--- a/bin/thumbv7em-none-eabihf.a
+++ b/bin/thumbv7em-none-eabihf.a
Binary files differ
diff --git a/bin/thumbv7m-none-eabi-lto.a b/bin/thumbv7m-none-eabi-lto.a
new file mode 100644
index 0000000..28e5860
--- /dev/null
+++ b/bin/thumbv7m-none-eabi-lto.a
Binary files differ
diff --git a/bin/thumbv7m-none-eabi.a b/bin/thumbv7m-none-eabi.a
index 51ab710..4559ad4 100644
--- a/bin/thumbv7m-none-eabi.a
+++ b/bin/thumbv7m-none-eabi.a
Binary files differ
diff --git a/bin/thumbv8m.base-none-eabi-lto.a b/bin/thumbv8m.base-none-eabi-lto.a
new file mode 100644
index 0000000..ee46792
--- /dev/null
+++ b/bin/thumbv8m.base-none-eabi-lto.a
Binary files differ
diff --git a/bin/thumbv8m.base-none-eabi.a b/bin/thumbv8m.base-none-eabi.a
index 33bcff2..26d25bd 100644
--- a/bin/thumbv8m.base-none-eabi.a
+++ b/bin/thumbv8m.base-none-eabi.a
Binary files differ
diff --git a/bin/thumbv8m.main-none-eabi-lto.a b/bin/thumbv8m.main-none-eabi-lto.a
new file mode 100644
index 0000000..e3aa0cf
--- /dev/null
+++ b/bin/thumbv8m.main-none-eabi-lto.a
Binary files differ
diff --git a/bin/thumbv8m.main-none-eabi.a b/bin/thumbv8m.main-none-eabi.a
index 1b2418d..10bbf53 100644
--- a/bin/thumbv8m.main-none-eabi.a
+++ b/bin/thumbv8m.main-none-eabi.a
Binary files differ
diff --git a/bin/thumbv8m.main-none-eabihf-lto.a b/bin/thumbv8m.main-none-eabihf-lto.a
new file mode 100644
index 0000000..1c25494
--- /dev/null
+++ b/bin/thumbv8m.main-none-eabihf-lto.a
Binary files differ
diff --git a/bin/thumbv8m.main-none-eabihf.a b/bin/thumbv8m.main-none-eabihf.a
index 312dcd2..0651788 100644
--- a/bin/thumbv8m.main-none-eabihf.a
+++ b/bin/thumbv8m.main-none-eabihf.a
Binary files differ
diff --git a/build.rs b/build.rs
index d53dea5..dc9b3a0 100644
--- a/build.rs
+++ b/build.rs
@@ -7,10 +7,17 @@ fn main() {
let name = env::var("CARGO_PKG_NAME").unwrap();
if target.starts_with("thumb") {
+ let suffix = if env::var_os("CARGO_FEATURE_LINKER_PLUGIN_LTO").is_some() {
+ "-lto"
+ } else {
+ ""
+ };
+
fs::copy(
- format!("bin/{}.a", target),
+ format!("bin/{}{}.a", target, suffix),
out_dir.join(format!("lib{}.a", name)),
- ).unwrap();
+ )
+ .unwrap();
println!("cargo:rustc-link-lib=static={}", name);
println!("cargo:rustc-link-search={}", out_dir.display());
@@ -25,7 +32,7 @@ fn main() {
} else if target.starts_with("thumbv7em-") {
println!("cargo:rustc-cfg=cortex_m");
println!("cargo:rustc-cfg=armv7m");
- println!("cargo:rustc-cfg=armv7em"); // (not currently used)
+ println!("cargo:rustc-cfg=armv7em"); // (not currently used)
} else if target.starts_with("thumbv8m.base") {
println!("cargo:rustc-cfg=cortex_m");
println!("cargo:rustc-cfg=armv8m");
diff --git a/check-blobs.sh b/check-blobs.sh
deleted file mode 100755
index 166b4a4..0000000
--- a/check-blobs.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env bash
-
-# Checks that the blobs are up to date with the committed assembly files
-
-set -euxo pipefail
-
-for lib in bin/*.a; do
- filename=$(basename "$lib")
- arm-none-eabi-objdump -Cd "$lib" > "bin/${filename%.a}.before"
-done
-
-./assemble.sh
-
-for lib in bin/*.a; do
- filename=$(basename "$lib")
- arm-none-eabi-objdump -Cd "$lib" > "bin/${filename%.a}.after"
-done
-
-for cksum in bin/*.after; do
- diff -u "$cksum" "${cksum%.after}.before"
-done
diff --git a/ci/install.sh b/ci/install.sh
index 371cc8e..fb3e52d 100644
--- a/ci/install.sh
+++ b/ci/install.sh
@@ -6,10 +6,6 @@ main() {
rustup target add $TARGET
;;
esac
-
- mkdir gcc
-
- curl -L https://developer.arm.com/-/media/Files/downloads/gnu-rm/7-2018q2/gcc-arm-none-eabi-7-2018-q2-update-linux.tar.bz2?revision=bc2c96c0-14b5-4bb4-9f18-bceb4050fee7?product=GNU%20Arm%20Embedded%20Toolchain,64-bit,,Linux,7-2018-q2-update | tar --strip-components=1 -C gcc -xj
}
main
diff --git a/ci/script.sh b/ci/script.sh
index 7c30993..fc1e754 100644
--- a/ci/script.sh
+++ b/ci/script.sh
@@ -29,7 +29,7 @@ main() {
esac
if [ $TARGET = x86_64-unknown-linux-gnu ]; then
- ./check-blobs.sh
+ cargo xtask check-blobs
fi
if [ $TRAVIS_RUST_VERSION = nightly ]; then
diff --git a/src/lib.rs b/src/lib.rs
index 5dbb8f5..723816a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -24,6 +24,32 @@
//!
//! The disadvantage is that `inline-asm` requires a nightly toolchain.
//!
+//! ## `cm7-r0p1`
+//!
+//! This feature enables workarounds for errata found on Cortex-M7 chips with revision r0p1. Some
+//! functions in this crate only work correctly on those chips if this Cargo feature is enabled
+//! (the functions are documented accordingly).
+//!
+//! ## `linker-plugin-lto`
+//!
+//! This feature links against prebuilt assembly blobs that are compatible with [Linker-Plugin LTO].
+//! This allows inlining assembly routines into the caller, even without the `inline-asm` feature,
+//! and works on stable Rust (but note the drawbacks below!).
+//!
+//! If you want to use this feature, you need to be aware of a few things:
+//!
+//! - You need to make sure that `-Clinker-plugin-lto` is passed to rustc. Please refer to the
+//! [Linker-Plugin LTO] documentation for details.
+//!
+//! - You have to use a Rust version whose LLVM version is compatible with the toolchain in
+//! `asm-toolchain`.
+//!
+//! - Due to a [Rust bug][rust-lang/rust#75940], this option does not work with optimization
+//! levels `s` and `z`.
+//!
+//! [Linker-Plugin LTO]: https://doc.rust-lang.org/stable/rustc/linker-plugin-lto.html
+//! [rust-lang/rust#75940]: https://github.com/rust-lang/rust/issues/75940
+//!
//! # Minimum Supported Rust Version (MSRV)
//!
//! This crate is guaranteed to compile on stable Rust 1.31 and up. It *might*
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
new file mode 100644
index 0000000..9d35164
--- /dev/null
+++ b/xtask/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "xtask"
+version = "0.0.0"
+authors = ["The Cortex-M Team <cortex-m@teams.rust-embedded.org>"]
+edition = "2018"
+publish = false
+
+[dependencies]
+ar = "0.8.0"
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
new file mode 100644
index 0000000..ab59f57
--- /dev/null
+++ b/xtask/src/main.rs
@@ -0,0 +1,216 @@
+//! `cargo xtask` automation.
+//!
+//! Please refer to <https://github.com/matklad/cargo-xtask/> for an explanation of the concept.
+//!
+//! Also see the docs in `asm.rs`.
+
+use process::Stdio;
+use std::env::{self, current_dir};
+use std::{
+ collections::BTreeMap,
+ fs::{self, File},
+ process::{self, Command},
+};
+
+fn toolchain() -> String {
+ fs::read_to_string("asm-toolchain")
+ .unwrap()
+ .trim()
+ .to_string()
+}
+
+fn rustc() -> Command {
+ let mut cmd = Command::new("rustc");
+ cmd.arg(format!("+{}", toolchain()));
+ cmd
+}
+
+fn assemble_really(target: &str, cfgs: &[&str], plugin_lto: bool) {
+ let mut cmd = rustc();
+
+ // Set the codegen target.
+ cmd.arg("--target").arg(target);
+ // Set all the `--cfg` directives for the target.
+ cmd.args(cfgs.iter().map(|cfg| format!("--cfg={}", cfg)));
+
+ // We want some level of debuginfo to allow unwinding through the functions.
+ cmd.arg("-g");
+ // We always optimize the assembly shims. There's not really any reason not to.
+ cmd.arg("-O");
+
+ // rustc will usually add frame pointers by default to aid with debugging, but that is a high
+ // overhead for the tiny assembly routines.
+ cmd.arg("-Cforce-frame-pointers=no");
+
+ // We don't want any system-specific paths to show up since we ship the result to other users.
+ // Add `--remap-path-prefix $(pwd)=.`.
+ let mut dir = current_dir().unwrap().as_os_str().to_os_string();
+ dir.push("=.");
+ cmd.arg("--remap-path-prefix").arg(dir);
+
+ // We let rustc build a single object file, not a staticlib, since the latter pulls in loads of
+ // code that will never be used (`compiler_builtins` and `core::fmt`, etc.). We build the static
+ // archive by hand after compiling.
+ cmd.arg("--emit=obj");
+
+ if plugin_lto {
+ // Make artifacts compatible with Linker-Plugin LTO (and incompatible with everything else).
+ cmd.arg("-Clinker-plugin-lto");
+ }
+
+ let file_stub = if plugin_lto {
+ format!("{}-lto", target)
+ } else {
+ target.to_string()
+ };
+
+ let obj_file = format!("bin/{}.o", file_stub);
+
+ // Pass output and input file.
+ cmd.arg("-o").arg(&obj_file);
+ cmd.arg("asm.rs");
+
+ println!("{:?}", cmd);
+ let status = cmd.status().unwrap();
+ assert!(status.success());
+
+ // Archive `target.o` -> `bin/target.a`.
+ let mut builder = ar::Builder::new(File::create(format!("bin/{}.a", file_stub)).unwrap());
+
+ // Use `append`, not `append_path`, to avoid adding any filesystem metadata (modification times,
+ // etc.).
+ let file = fs::read(&obj_file).unwrap();
+ builder
+ .append(
+ &ar::Header::new(obj_file.as_bytes().to_vec(), file.len() as u64),
+ &*file,
+ )
+ .unwrap();
+
+ fs::remove_file(&obj_file).unwrap();
+}
+
+fn assemble(target: &str, cfgs: &[&str]) {
+ assemble_really(target, cfgs, false);
+ assemble_really(target, cfgs, true);
+}
+
+// `--target` -> `--cfg` list (mirrors what `build.rs` does).
+static TARGETS: &[(&str, &[&str])] = &[
+ ("thumbv6m-none-eabi", &[]),
+ ("thumbv7m-none-eabi", &["armv7m"]),
+ ("thumbv7em-none-eabi", &["armv7m", "armv7em"]),
+ ("thumbv7em-none-eabihf", &["armv7m", "armv7em", "has_fpu"]),
+ ("thumbv8m.base-none-eabi", &["armv8m", "armv8m_base"]),
+ (
+ "thumbv8m.main-none-eabi",
+ &["armv7m", "armv8m", "armv8m_main"],
+ ),
+ (
+ "thumbv8m.main-none-eabihf",
+ &["armv7m", "armv8m", "armv8m_main", "has_fpu"],
+ ),
+];
+
+fn assemble_blobs() {
+ let mut cmd = rustc();
+ cmd.arg("-V");
+ cmd.stdout(Stdio::null());
+ let status = cmd.status().unwrap();
+
+ if !status.success() {
+ let toolchain = toolchain();
+ println!(
+ "asm toolchain {} does not seem to be installed. installing it now.",
+ toolchain
+ );
+
+ let mut rustup = Command::new("rustup");
+ let status = rustup.arg("install").arg(&toolchain).status().unwrap();
+ assert!(status.success(), "rustup command failed: {:?}", rustup);
+
+ let mut rustup = Command::new("rustup");
+ let status = rustup
+ .arg("target")
+ .arg("add")
+ .args(TARGETS.iter().map(|(target, _)| *target))
+ .arg("--toolchain")
+ .arg(toolchain)
+ .status()
+ .unwrap();
+ assert!(status.success(), "rustup command failed: {:?}", rustup);
+ }
+
+ for (target, cfgs) in TARGETS {
+ println!("building artifacts for {}", target);
+ assemble(target, cfgs);
+ }
+}
+
+fn check_blobs() {
+ // Load each `.a` file in `bin` into memory.
+ let mut files_before = BTreeMap::new();
+ for entry in fs::read_dir("bin").unwrap() {
+ let entry = entry.unwrap();
+ if entry.path().extension().unwrap() == "a" {
+ files_before.insert(
+ entry
+ .path()
+ .file_name()
+ .unwrap()
+ .to_str()
+ .unwrap()
+ .to_string(),
+ fs::read(entry.path()).unwrap(),
+ );
+ }
+ }
+
+ assemble_blobs();
+
+ let mut files_after = BTreeMap::new();
+ for entry in fs::read_dir("bin").unwrap() {
+ let entry = entry.unwrap();
+ if entry.path().extension().unwrap() == "a" {
+ files_after.insert(
+ entry
+ .path()
+ .file_name()
+ .unwrap()
+ .to_str()
+ .unwrap()
+ .to_string(),
+ fs::read(entry.path()).unwrap(),
+ );
+ }
+ }
+
+ // Ensure they contain the same files.
+ let before = files_before.keys().collect::<Vec<_>>();
+ let after = files_after.keys().collect::<Vec<_>>();
+ assert_eq!(before, after);
+
+ for ((file, before), (_, after)) in files_before.iter().zip(files_after.iter()) {
+ if before != after {
+ panic!("{} differs between rebuilds", file);
+ }
+ }
+
+ println!("Blobs identical.");
+}
+
+fn main() {
+ let subcommand = env::args().skip(1).next();
+ match subcommand.as_deref() {
+ Some("assemble") => assemble_blobs(),
+ Some("check-blobs") => check_blobs(),
+ _ => {
+ eprintln!("usage: cargo xtask <subcommand>");
+ eprintln!();
+ eprintln!("subcommands:");
+ eprintln!(" assemble Reassemble the pre-built artifacts");
+ eprintln!(" check-blobs Check that the pre-built artifacts are up-to-date and reproducible");
+ process::exit(1);
+ }
+ }
+}