Skip to content

Commit aa77c89

Browse files
bors[bot]adamgreigjonas-schievink
authored
Merge #264
264: Tidy up some inline asm and add compiler fences where appropriate r=therealprof a=adamgreig This PR updates the inline asm: * Use compiler-assigned registers instead of specifying r0/r1/r2 * Write multi-line asm as multiple string literals, with normal Rust comments outside the strings * Add ISB after writing to CONTROL as per ARM architectural requirements (see eg app note 321). As far as I can see no other requirements from AN321 apply here. * Add compiler fences around enabling and disabling interrupts * No runtime barriers are required, but the compiler fences ensure the compiler won't reorder instructions around these operations, which would break critical section soundness. * Add compiler fences around DMB, DSB, ISB to align compiler behaviour with the barrier runtime behaviour. * Add compiler fences after the cache enable routines and writing to CONTROL since those routines include an ISB instruction. Open to feedback on whether more or fewer fences are necessary; I've thought about these a bit but I think it's a tricky subject. I think in general the FFI-esque treatment of the new `asm!` block probably does most of what we need, but I'm told LLVM may still reorder instructions around FFI calls, which we really don't want to happen here. Co-authored-by: Adam Greig <[email protected]> Co-authored-by: Jonas Schievink <[email protected]>
2 parents b05a24e + 2b818cb commit aa77c89

16 files changed

+91
-66
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1414
- Associated const `PTR` is introduced to Core Peripherals to
1515
eventually replace the existing `ptr()` API.
1616
- A delay driver based on SysTick.
17+
- You can now use LTO to inline assembly calls, even on stable Rust.
18+
See the `asm/lib.rs` documentation for more details.
19+
20+
### Changed
21+
22+
- Previously, asm calls without the `inline-asm` feature enabled used pre-built
23+
objects which were built by a GCC compiler, while `inline-asm` enabled the
24+
use of `llvm_asm!` calls. The asm system has been replaced with a new
25+
technique which generates Rust static libs for stable calling, and uses the
26+
new `asm!` macro with `inline-asm`. See the `asm/lib.rs` documentation for
27+
more details.
1728

1829
## [v0.6.3] - 2020-07-20
1930

asm/inline.rs

Lines changed: 80 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
//! All of these functions should be blanket-`unsafe`. `cortex-m` provides safe wrappers where
77
//! applicable.
88
9+
use core::sync::atomic::{Ordering, compiler_fence};
10+
911
#[inline(always)]
1012
pub unsafe fn __bkpt() {
1113
asm!("bkpt");
@@ -20,45 +22,62 @@ pub unsafe fn __control_r() -> u32 {
2022

2123
#[inline(always)]
2224
pub unsafe fn __control_w(w: u32) {
23-
asm!("msr CONTROL, {}", in(reg) w);
25+
// ISB is required after writing to CONTROL,
26+
// per ARM architectural requirements (see Application Note 321).
27+
asm!(
28+
"msr CONTROL, {}",
29+
"isb",
30+
in(reg) w
31+
);
32+
33+
// Ensure memory accesses are not reordered around the CONTROL update.
34+
compiler_fence(Ordering::SeqCst);
2435
}
2536

2637
#[inline(always)]
2738
pub unsafe fn __cpsid() {
2839
asm!("cpsid i");
40+
41+
// Ensure no subsequent memory accesses are reordered to before interrupts are disabled.
42+
compiler_fence(Ordering::SeqCst);
2943
}
3044

3145
#[inline(always)]
3246
pub unsafe fn __cpsie() {
47+
// Ensure no preceeding memory accesses are reordered to after interrupts are enabled.
48+
compiler_fence(Ordering::SeqCst);
49+
3350
asm!("cpsie i");
3451
}
3552

3653
#[inline(always)]
3754
pub unsafe fn __delay(cyc: u32) {
38-
asm!("
39-
1:
40-
nop
41-
subs {}, #1
42-
bne 1b
43-
// Branch to 1 instead of delay does not generate R_ARM_THM_JUMP8 relocation, which breaks
44-
// linking on the thumbv6m-none-eabi target
45-
", in(reg) cyc);
55+
// Use local labels to avoid R_ARM_THM_JUMP8 relocations which fail on thumbv6m.
56+
asm!(
57+
"1:",
58+
"nop",
59+
"subs {}, #1",
60+
"bne 1b",
61+
in(reg) cyc
62+
);
4663
}
4764

48-
// FIXME do we need compiler fences here or should we expect them in the caller?
4965
#[inline(always)]
5066
pub unsafe fn __dmb() {
51-
asm!("dmb 0xF");
67+
asm!("dmb");
68+
compiler_fence(Ordering::SeqCst);
5269
}
5370

5471
#[inline(always)]
5572
pub unsafe fn __dsb() {
56-
asm!("dsb 0xF");
73+
asm!("dsb");
74+
compiler_fence(Ordering::SeqCst);
5775
}
5876

5977
#[inline(always)]
6078
pub unsafe fn __isb() {
61-
asm!("isb 0xF");
79+
asm!("isb");
80+
compiler_fence(Ordering::SeqCst);
6281
}
6382

6483
#[inline(always)]
@@ -93,28 +112,28 @@ pub unsafe fn __nop() {
93112
#[inline(always)]
94113
pub unsafe fn __pc_r() -> u32 {
95114
let r;
96-
asm!("mov {}, R15", out(reg) r);
115+
asm!("mov {}, pc", out(reg) r);
97116
r
98117
}
99118

100119
// NOTE: No FFI shim, this requires inline asm.
101120
#[inline(always)]
102121
pub unsafe fn __pc_w(val: u32) {
103-
asm!("mov R15, {}", in(reg) val);
122+
asm!("mov pc, {}", in(reg) val);
104123
}
105124

106125
// NOTE: No FFI shim, this requires inline asm.
107126
#[inline(always)]
108127
pub unsafe fn __lr_r() -> u32 {
109128
let r;
110-
asm!("mov {}, R14", out(reg) r);
129+
asm!("mov {}, lr", out(reg) r);
111130
r
112131
}
113132

114133
// NOTE: No FFI shim, this requires inline asm.
115134
#[inline(always)]
116135
pub unsafe fn __lr_w(val: u32) {
117-
asm!("mov R14, {}", in(reg) val);
136+
asm!("mov lr, {}", in(reg) val);
118137
}
119138

120139
#[inline(always)]
@@ -161,6 +180,8 @@ pub unsafe fn __wfi() {
161180
pub use self::v7m::*;
162181
#[cfg(any(armv7m, armv8m_main))]
163182
mod v7m {
183+
use core::sync::atomic::{Ordering, compiler_fence};
184+
164185
#[inline(always)]
165186
pub unsafe fn __basepri_max(val: u8) {
166187
asm!("msr BASEPRI_MAX, {}", in(reg) val);
@@ -185,45 +206,42 @@ mod v7m {
185206
r
186207
}
187208

188-
// FIXME: compiler_fences necessary?
189209
#[inline(always)]
190210
pub unsafe fn __enable_icache() {
191211
asm!(
192-
"
193-
ldr r0, =0xE000ED14 @ CCR
194-
mrs r2, PRIMASK @ save critical nesting info
195-
cpsid i @ mask interrupts
196-
ldr r1, [r0] @ read CCR
197-
orr.w r1, r1, #(1 << 17) @ Set bit 17, IC
198-
str r1, [r0] @ write it back
199-
dsb @ ensure store completes
200-
isb @ synchronize pipeline
201-
msr PRIMASK, r2 @ unnest critical section
202-
",
203-
out("r0") _,
204-
out("r1") _,
205-
out("r2") _,
212+
"ldr {0}, =0xE000ED14", // CCR
213+
"mrs {2}, PRIMASK", // save critical nesting info
214+
"cpsid i", // mask interrupts
215+
"ldr {1}, [{0}]", // read CCR
216+
"orr.w {1}, {1}, #(1 << 17)", // Set bit 17, IC
217+
"str {1}, [{0}]", // write it back
218+
"dsb", // ensure store completes
219+
"isb", // synchronize pipeline
220+
"msr PRIMASK, {2}", // unnest critical section
221+
out(reg) _,
222+
out(reg) _,
223+
out(reg) _,
206224
);
225+
compiler_fence(Ordering::SeqCst);
207226
}
208227

209228
#[inline(always)]
210229
pub unsafe fn __enable_dcache() {
211230
asm!(
212-
"
213-
ldr r0, =0xE000ED14 @ CCR
214-
mrs r2, PRIMASK @ save critical nesting info
215-
cpsid i @ mask interrupts
216-
ldr r1, [r0] @ read CCR
217-
orr.w r1, r1, #(1 << 16) @ Set bit 16, DC
218-
str r1, [r0] @ write it back
219-
dsb @ ensure store completes
220-
isb @ synchronize pipeline
221-
msr PRIMASK, r2 @ unnest critical section
222-
",
223-
out("r0") _,
224-
out("r1") _,
225-
out("r2") _,
231+
"ldr {0}, =0xE000ED14", // CCR
232+
"mrs {2}, PRIMASK", // save critical nesting info
233+
"cpsid i", // mask interrupts
234+
"ldr {1}, [{0}]", // read CCR
235+
"orr.w {1}, {1}, #(1 << 16)", // Set bit 16, DC
236+
"str {1}, [{0}]", // write it back
237+
"dsb", // ensure store completes
238+
"isb", // synchronize pipeline
239+
"msr PRIMASK, {2}", // unnest critical section
240+
out(reg) _,
241+
out(reg) _,
242+
out(reg) _,
226243
);
244+
compiler_fence(Ordering::SeqCst);
227245
}
228246
}
229247

@@ -234,34 +252,30 @@ mod v7em {
234252
#[inline(always)]
235253
pub unsafe fn __basepri_max_cm7_r0p1(val: u8) {
236254
asm!(
237-
"
238-
mrs r1, PRIMASK
239-
cpsid i
240-
tst.w r1, #1
241-
msr BASEPRI_MAX, {}
242-
it ne
243-
bxne lr
244-
cpsie i
245-
",
255+
"mrs {1}, PRIMASK",
256+
"cpsid i",
257+
"tst.w {1}, #1",
258+
"msr BASEPRI_MAX, {0}",
259+
"it ne",
260+
"bxne lr",
261+
"cpsie i",
246262
in(reg) val,
247-
out("r1") _,
263+
out(reg) _,
248264
);
249265
}
250266

251267
#[inline(always)]
252268
pub unsafe fn __basepri_w_cm7_r0p1(val: u8) {
253269
asm!(
254-
"
255-
mrs r1, PRIMASK
256-
cpsid i
257-
tst.w r1, #1
258-
msr BASEPRI, {}
259-
it ne
260-
bxne lr
261-
cpsie i
262-
",
270+
"mrs {1}, PRIMASK",
271+
"cpsid i",
272+
"tst.w {1}, #1",
273+
"msr BASEPRI, {0}",
274+
"it ne",
275+
"bxne lr",
276+
"cpsie i",
263277
in(reg) val,
264-
out("r1") _,
278+
out(reg) _,
265279
);
266280
}
267281
}

bin/thumbv6m-none-eabi-lto.a

492 Bytes
Binary file not shown.

bin/thumbv6m-none-eabi.a

928 Bytes
Binary file not shown.

bin/thumbv7em-none-eabi-lto.a

-924 Bytes
Binary file not shown.

bin/thumbv7em-none-eabi.a

1008 Bytes
Binary file not shown.

bin/thumbv7em-none-eabihf-lto.a

-908 Bytes
Binary file not shown.

bin/thumbv7em-none-eabihf.a

976 Bytes
Binary file not shown.

bin/thumbv7m-none-eabi-lto.a

-556 Bytes
Binary file not shown.

bin/thumbv7m-none-eabi.a

1004 Bytes
Binary file not shown.

bin/thumbv8m.base-none-eabi-lto.a

548 Bytes
Binary file not shown.

bin/thumbv8m.base-none-eabi.a

908 Bytes
Binary file not shown.

bin/thumbv8m.main-none-eabi-lto.a

-472 Bytes
Binary file not shown.

bin/thumbv8m.main-none-eabi.a

976 Bytes
Binary file not shown.

bin/thumbv8m.main-none-eabihf-lto.a

-436 Bytes
Binary file not shown.

bin/thumbv8m.main-none-eabihf.a

972 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)