44
55#[ cfg( cortex_m) ]
66use core:: arch:: asm;
7+ #[ cfg( cortex_m) ]
8+ use core:: sync:: atomic:: { Ordering , compiler_fence} ;
79
810pub mod inner;
911
@@ -34,14 +36,35 @@ pub fn bkpt() {
3436#[ inline]
3537#[ cortex_m_macros:: asm_cfg( cortex_m) ]
3638pub 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) ]
4363pub 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) ]
5275pub 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) ]
5982pub 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) ]
6689pub 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) ]
7396pub 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) ]
83106pub 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) ]
96121pub 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) ]
107134pub 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) ]
120149pub 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) ]
135171pub 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) ]
151194pub 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) ]
167217pub 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) ]
178235pub 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