Skip to content

Commit fc454e4

Browse files
committed
Move asm for asm module into the asm module directly.
This is the first step of removing the asm::inner module entirely.
1 parent 14d0e9a commit fc454e4

2 files changed

Lines changed: 92 additions & 169 deletions

File tree

cortex-m/src/asm.rs

Lines changed: 92 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#[cfg(cortex_m)]
66
use core::arch::asm;
7+
#[cfg(cortex_m)]
8+
use core::sync::atomic::{Ordering, compiler_fence};
79

810
pub mod inner;
911

@@ -34,14 +36,35 @@ pub fn bkpt() {
3436
#[inline]
3537
#[cortex_m_macros::asm_cfg(cortex_m)]
3638
pub fn delay(cycles: u32) {
37-
unsafe { inner::__delay(cycles) };
39+
// The loop will normally take 3 to 4 CPU cycles per iteration, but superscalar cores
40+
// (eg. Cortex-M7) can potentially do it in 2, so we use that as the lower bound, since delaying
41+
// for more cycles is okay.
42+
// Add 1 to prevent an integer underflow which would cause a long freeze
43+
let real_cyc = 1 + cycles / 2;
44+
unsafe {
45+
asm!(
46+
// The `bne` on some cores (eg Cortex-M4) will take a different number of instructions
47+
// depending on the alignment of the branch target. Set the alignment of the top of the
48+
// loop to prevent surprising timing changes when the alignment of the delay() changes.
49+
".p2align 3",
50+
// Use local labels to avoid R_ARM_THM_JUMP8 relocations which fail on thumbv6m.
51+
"2:", // not 1 or 0 because of https://github.com/llvm/llvm-project/issues/99547
52+
"subs {}, #1", // subtract 1 from real_cyc
53+
"bne 2b", // branch to 2 if result is non-zero
54+
inout(reg) real_cyc => _,
55+
options(nomem, nostack),
56+
)
57+
};
3858
}
3959

4060
/// A no-operation. Useful to prevent delay loops from being optimized away.
4161
#[inline]
4262
#[cortex_m_macros::asm_cfg(cortex_m)]
4363
pub fn nop() {
44-
unsafe { inner::__nop() };
64+
// NOTE: This is a `pure` asm block, but applying that option allows the compiler to eliminate
65+
// the nop entirely (or to collapse multiple subsequent ones). Since the user probably wants N
66+
// nops when they call `nop` N times, let's not add that option.
67+
unsafe { asm!("nop", options(nomem, nostack, preserves_flags)) };
4568
}
4669

4770
/// Generate an Undefined Instruction exception.
@@ -50,28 +73,28 @@ pub fn nop() {
5073
#[inline]
5174
#[cortex_m_macros::asm_cfg(cortex_m)]
5275
pub fn udf() -> ! {
53-
unsafe { inner::__udf() }
76+
unsafe { asm!("udf #0", options(noreturn, nomem, nostack, preserves_flags)) };
5477
}
5578

5679
/// Wait For Event
5780
#[inline]
5881
#[cortex_m_macros::asm_cfg(cortex_m)]
5982
pub fn wfe() {
60-
unsafe { inner::__wfe() }
83+
unsafe { asm!("wfe", options(nomem, nostack, preserves_flags)) };
6184
}
6285

6386
/// Wait For Interrupt
6487
#[inline]
6588
#[cortex_m_macros::asm_cfg(cortex_m)]
6689
pub fn wfi() {
67-
unsafe { inner::__wfi() }
90+
unsafe { asm!("wfi", options(nomem, nostack, preserves_flags)) };
6891
}
6992

7093
/// Send Event
7194
#[inline]
7295
#[cortex_m_macros::asm_cfg(cortex_m)]
7396
pub fn sev() {
74-
unsafe { inner::__sev() }
97+
unsafe { asm!("sev", options(nomem, nostack, preserves_flags)) };
7598
}
7699

77100
/// Instruction Synchronization Barrier
@@ -81,7 +104,9 @@ pub fn sev() {
81104
#[inline]
82105
#[cortex_m_macros::asm_cfg(cortex_m)]
83106
pub fn isb() {
84-
unsafe { inner::__isb() }
107+
compiler_fence(Ordering::SeqCst);
108+
unsafe { asm!("isb", options(nostack, preserves_flags)) };
109+
compiler_fence(Ordering::SeqCst);
85110
}
86111

87112
/// Data Synchronization Barrier
@@ -94,7 +119,9 @@ pub fn isb() {
94119
#[inline]
95120
#[cortex_m_macros::asm_cfg(cortex_m)]
96121
pub fn dsb() {
97-
unsafe { inner::__dsb() }
122+
compiler_fence(Ordering::SeqCst);
123+
unsafe { asm!("dsb", options(nostack, preserves_flags)) };
124+
compiler_fence(Ordering::SeqCst);
98125
}
99126

100127
/// Data Memory Barrier
@@ -105,7 +132,9 @@ pub fn dsb() {
105132
#[inline]
106133
#[cortex_m_macros::asm_cfg(cortex_m)]
107134
pub fn dmb() {
108-
unsafe { inner::__dmb() }
135+
compiler_fence(Ordering::SeqCst);
136+
unsafe { asm!("dmb", options(nostack, preserves_flags)) };
137+
compiler_fence(Ordering::SeqCst);
109138
}
110139

111140
/// Test Target
@@ -118,8 +147,15 @@ pub fn dmb() {
118147
// The __tt function does not dereference the pointer received.
119148
#[allow(clippy::not_unsafe_ptr_arg_deref)]
120149
pub fn tt(addr: *mut u32) -> u32 {
121-
let addr = addr as u32;
122-
unsafe { crate::asm::inner::__tt(addr) }
150+
let mut addr = addr as u32;
151+
unsafe {
152+
asm!(
153+
"tt {addr}, {addr}",
154+
addr = inout(reg) addr,
155+
options(nomem, nostack, preserves_flags),
156+
)
157+
};
158+
addr
123159
}
124160

125161
/// Test Target Unprivileged
@@ -133,8 +169,15 @@ pub fn tt(addr: *mut u32) -> u32 {
133169
// The __ttt function does not dereference the pointer received.
134170
#[allow(clippy::not_unsafe_ptr_arg_deref)]
135171
pub fn ttt(addr: *mut u32) -> u32 {
136-
let addr = addr as u32;
137-
unsafe { crate::asm::inner::__ttt(addr) }
172+
let mut addr = addr as u32;
173+
unsafe {
174+
asm!(
175+
"ttt {addr}, {addr}",
176+
addr = inout(reg)addr,
177+
options(nomem, nostack, preserves_flags),
178+
)
179+
};
180+
addr
138181
}
139182

140183
/// Test Target Alternate Domain
@@ -149,8 +192,15 @@ pub fn ttt(addr: *mut u32) -> u32 {
149192
// The __tta function does not dereference the pointer received.
150193
#[allow(clippy::not_unsafe_ptr_arg_deref)]
151194
pub fn tta(addr: *mut u32) -> u32 {
152-
let addr = addr as u32;
153-
unsafe { crate::asm::inner::__tta(addr) }
195+
let mut addr = addr as u32;
196+
unsafe {
197+
asm!(
198+
"tta {addr}, {addr}",
199+
addr = inout(reg) addr,
200+
options(nomem, nostack, preserves_flags),
201+
)
202+
};
203+
addr
154204
}
155205

156206
/// Test Target Alternate Domain Unprivileged
@@ -165,8 +215,15 @@ pub fn tta(addr: *mut u32) -> u32 {
165215
// The __ttat function does not dereference the pointer received.
166216
#[allow(clippy::not_unsafe_ptr_arg_deref)]
167217
pub fn ttat(addr: *mut u32) -> u32 {
168-
let addr = addr as u32;
169-
unsafe { crate::asm::inner::__ttat(addr) }
218+
let mut addr = addr as u32;
219+
unsafe {
220+
asm!(
221+
"ttat {addr}, {addr}",
222+
addr = inout(reg) addr,
223+
options(nomem, nostack, preserves_flags),
224+
)
225+
};
226+
addr
170227
}
171228

172229
/// Branch and Exchange Non-secure
@@ -176,7 +233,7 @@ pub fn ttat(addr: *mut u32) -> u32 {
176233
#[inline]
177234
#[cortex_m_macros::asm_cfg(armv8m)]
178235
pub unsafe fn bx_ns(addr: u32) {
179-
unsafe { crate::asm::inner::__bxns(addr) };
236+
unsafe { asm!("BXNS {}", in(reg) addr, options(nomem, nostack, preserves_flags)) };
180237
}
181238

182239
/// Semihosting syscall.
@@ -292,7 +349,23 @@ pub unsafe fn bootstrap(msp: *const u32, rv: *const u32) -> ! {
292349
// Ensure thumb mode is set.
293350
let rv = (rv as u32) | 1;
294351
let msp = msp as u32;
295-
unsafe { inner::__bootstrap(msp, rv) }
352+
unsafe {
353+
asm!(
354+
"mrs {tmp}, CONTROL",
355+
"bics {tmp}, {spsel}",
356+
"msr CONTROL, {tmp}",
357+
"isb",
358+
"msr MSP, {msp}",
359+
"bx {rv}",
360+
// `out(reg) _` is not permitted in a `noreturn` asm! call,
361+
// so instead use `in(reg) 0` and don't restore it afterwards.
362+
tmp = in(reg) 0,
363+
spsel = in(reg) 2,
364+
msp = in(reg) msp,
365+
rv = in(reg) rv,
366+
options(noreturn, nomem, nostack),
367+
)
368+
};
296369
}
297370

298371
/// Bootload.

0 commit comments

Comments
 (0)