1//! Inline assembly implementing the routines exposed in `cortex_m::asm`.
2//!
3//! If the `inline-asm` feature is enabled, these functions will be directly called by the
4//! `cortex-m` wrappers. Otherwise, `cortex-m` links against them via prebuilt archives.
5//!
6//! All of these functions should be blanket-`unsafe`. `cortex-m` provides safe wrappers where
7//! applicable.
8
9use core::arch::asm;
10use core::sync::atomic::{compiler_fence, Ordering};
11
12#[inline(always)]
13pub unsafe fn __bkpt() {
14 asm!("bkpt", options(nomem, nostack, preserves_flags));
15}
16
17#[inline(always)]
18pub unsafe fn __control_r() -> u32 {
19 let r: u32;
20 asm!("mrs {}, CONTROL", out(reg) r, options(nomem, nostack, preserves_flags));
21 r
22}
23
24#[inline(always)]
25pub unsafe fn __control_w(w: u32) {
26 // ISB is required after writing to CONTROL,
27 // per ARM architectural requirements (see Application Note 321).
28 asm!(
29 "msr CONTROL, {}",
30 "isb",
31 in(reg) w,
32 options(nomem, nostack, preserves_flags),
33 );
34
35 // Ensure memory accesses are not reordered around the CONTROL update.
36 compiler_fence(order:Ordering::SeqCst);
37}
38
39#[inline(always)]
40pub unsafe fn __cpsid() {
41 asm!("cpsid i", options(nomem, nostack, preserves_flags));
42
43 // Ensure no subsequent memory accesses are reordered to before interrupts are disabled.
44 compiler_fence(order:Ordering::SeqCst);
45}
46
47#[inline(always)]
48pub unsafe fn __cpsie() {
49 // Ensure no preceeding memory accesses are reordered to after interrupts are enabled.
50 compiler_fence(order:Ordering::SeqCst);
51
52 asm!("cpsie i", options(nomem, nostack, preserves_flags));
53}
54
55#[inline(always)]
56pub unsafe fn __delay(cyc: u32) {
57 // The loop will normally take 3 to 4 CPU cycles per iteration, but superscalar cores
58 // (eg. Cortex-M7) can potentially do it in 2, so we use that as the lower bound, since delaying
59 // for more cycles is okay.
60 // Add 1 to prevent an integer underflow which would cause a long freeze
61 let real_cyc: u32 = 1 + cyc / 2;
62 asm!(
63 // Use local labels to avoid R_ARM_THM_JUMP8 relocations which fail on thumbv6m.
64 "1:",
65 "subs {}, #1",
66 "bne 1b",
67 inout(reg) real_cyc => _,
68 options(nomem, nostack),
69 );
70}
71
72#[inline(always)]
73pub unsafe fn __dmb() {
74 compiler_fence(order:Ordering::SeqCst);
75 asm!("dmb", options(nomem, nostack, preserves_flags));
76 compiler_fence(order:Ordering::SeqCst);
77}
78
79#[inline(always)]
80pub unsafe fn __dsb() {
81 compiler_fence(order:Ordering::SeqCst);
82 asm!("dsb", options(nomem, nostack, preserves_flags));
83 compiler_fence(order:Ordering::SeqCst);
84}
85
86#[inline(always)]
87pub unsafe fn __isb() {
88 compiler_fence(order:Ordering::SeqCst);
89 asm!("isb", options(nomem, nostack, preserves_flags));
90 compiler_fence(order:Ordering::SeqCst);
91}
92
93#[inline(always)]
94pub unsafe fn __msp_r() -> u32 {
95 let r: u32;
96 asm!("mrs {}, MSP", out(reg) r, options(nomem, nostack, preserves_flags));
97 r
98}
99
100#[inline(always)]
101pub unsafe fn __msp_w(val: u32) {
102 // Technically is writing to the stack pointer "not pushing any data to the stack"?
103 // In any event, if we don't set `nostack` here, this method is useless as the new
104 // stack value is immediately mutated by returning. Really this is just not a good
105 // method and its higher-level use is marked as deprecated in cortex-m.
106 asm!("msr MSP, {}", in(reg) val, options(nomem, nostack, preserves_flags));
107}
108
109// NOTE: No FFI shim, this requires inline asm.
110#[inline(always)]
111pub unsafe fn __apsr_r() -> u32 {
112 let r: u32;
113 asm!("mrs {}, APSR", out(reg) r, options(nomem, nostack, preserves_flags));
114 r
115}
116
117#[inline(always)]
118pub unsafe fn __nop() {
119 // NOTE: This is a `pure` asm block, but applying that option allows the compiler to eliminate
120 // the nop entirely (or to collapse multiple subsequent ones). Since the user probably wants N
121 // nops when they call `nop` N times, let's not add that option.
122 asm!("nop", options(nomem, nostack, preserves_flags));
123}
124
125// NOTE: No FFI shim, this requires inline asm.
126#[inline(always)]
127pub unsafe fn __pc_r() -> u32 {
128 let r: u32;
129 asm!("mov {}, pc", out(reg) r, options(nomem, nostack, preserves_flags));
130 r
131}
132
133// NOTE: No FFI shim, this requires inline asm.
134#[inline(always)]
135pub unsafe fn __pc_w(val: u32) {
136 asm!("mov pc, {}", in(reg) val, options(nomem, nostack, preserves_flags));
137}
138
139// NOTE: No FFI shim, this requires inline asm.
140#[inline(always)]
141pub unsafe fn __lr_r() -> u32 {
142 let r: u32;
143 asm!("mov {}, lr", out(reg) r, options(nomem, nostack, preserves_flags));
144 r
145}
146
147// NOTE: No FFI shim, this requires inline asm.
148#[inline(always)]
149pub unsafe fn __lr_w(val: u32) {
150 asm!("mov lr, {}", in(reg) val, options(nomem, nostack, preserves_flags));
151}
152
153#[inline(always)]
154pub unsafe fn __primask_r() -> u32 {
155 let r: u32;
156 asm!("mrs {}, PRIMASK", out(reg) r, options(nomem, nostack, preserves_flags));
157 r
158}
159
160#[inline(always)]
161pub unsafe fn __psp_r() -> u32 {
162 let r: u32;
163 asm!("mrs {}, PSP", out(reg) r, options(nomem, nostack, preserves_flags));
164 r
165}
166
167#[inline(always)]
168pub unsafe fn __psp_w(val: u32) {
169 // See comment on __msp_w. Unlike MSP, there are legitimate use-cases for modifying PSP
170 // if MSP is currently being used as the stack pointer.
171 asm!("msr PSP, {}", in(reg) val, options(nomem, nostack, preserves_flags));
172}
173
174#[inline(always)]
175pub unsafe fn __sev() {
176 asm!("sev", options(nomem, nostack, preserves_flags));
177}
178
179#[inline(always)]
180pub unsafe fn __udf() -> ! {
181 asm!("udf #0", options(noreturn, nomem, nostack, preserves_flags));
182}
183
184#[inline(always)]
185pub unsafe fn __wfe() {
186 asm!("wfe", options(nomem, nostack, preserves_flags));
187}
188
189#[inline(always)]
190pub unsafe fn __wfi() {
191 asm!("wfi", options(nomem, nostack, preserves_flags));
192}
193
194/// Semihosting syscall.
195#[inline(always)]
196pub unsafe fn __sh_syscall(mut nr: u32, arg: u32) -> u32 {
197 asm!("bkpt #0xab", inout("r0") nr, in("r1") arg, options(nomem, nostack, preserves_flags));
198 nr
199}
200
201/// Set CONTROL.SPSEL to 0, write `msp` to MSP, branch to `rv`.
202#[inline(always)]
203pub unsafe fn __bootstrap(msp: u32, rv: u32) -> ! {
204 asm!(
205 "mrs {tmp}, CONTROL",
206 "bics {tmp}, {spsel}",
207 "msr CONTROL, {tmp}",
208 "isb",
209 "msr MSP, {msp}",
210 "bx {rv}",
211 // `out(reg) _` is not permitted in a `noreturn` asm! call,
212 // so instead use `in(reg) 0` and don't restore it afterwards.
213 tmp = in(reg) 0,
214 spsel = in(reg) 2,
215 msp = in(reg) msp,
216 rv = in(reg) rv,
217 options(noreturn, nomem, nostack),
218 );
219}
220
221// v7m *AND* v8m.main, but *NOT* v8m.base
222#[cfg(any(armv7m, armv8m_main))]
223pub use self::v7m::*;
224#[cfg(any(armv7m, armv8m_main))]
225mod v7m {
226 use core::arch::asm;
227 use core::sync::atomic::{compiler_fence, Ordering};
228
229 #[inline(always)]
230 pub unsafe fn __basepri_max(val: u8) {
231 asm!("msr BASEPRI_MAX, {}", in(reg) val, options(nomem, nostack, preserves_flags));
232 }
233
234 #[inline(always)]
235 pub unsafe fn __basepri_r() -> u8 {
236 let r;
237 asm!("mrs {}, BASEPRI", out(reg) r, options(nomem, nostack, preserves_flags));
238 r
239 }
240
241 #[inline(always)]
242 pub unsafe fn __basepri_w(val: u8) {
243 asm!("msr BASEPRI, {}", in(reg) val, options(nomem, nostack, preserves_flags));
244 }
245
246 #[inline(always)]
247 pub unsafe fn __faultmask_r() -> u32 {
248 let r;
249 asm!("mrs {}, FAULTMASK", out(reg) r, options(nomem, nostack, preserves_flags));
250 r
251 }
252
253 #[inline(always)]
254 pub unsafe fn __enable_icache() {
255 asm!(
256 "ldr {0}, =0xE000ED14", // CCR
257 "mrs {2}, PRIMASK", // save critical nesting info
258 "cpsid i", // mask interrupts
259 "ldr {1}, [{0}]", // read CCR
260 "orr.w {1}, {1}, #(1 << 17)", // Set bit 17, IC
261 "str {1}, [{0}]", // write it back
262 "dsb", // ensure store completes
263 "isb", // synchronize pipeline
264 "msr PRIMASK, {2}", // unnest critical section
265 out(reg) _,
266 out(reg) _,
267 out(reg) _,
268 options(nostack),
269 );
270 compiler_fence(Ordering::SeqCst);
271 }
272
273 #[inline(always)]
274 pub unsafe fn __enable_dcache() {
275 asm!(
276 "ldr {0}, =0xE000ED14", // CCR
277 "mrs {2}, PRIMASK", // save critical nesting info
278 "cpsid i", // mask interrupts
279 "ldr {1}, [{0}]", // read CCR
280 "orr.w {1}, {1}, #(1 << 16)", // Set bit 16, DC
281 "str {1}, [{0}]", // write it back
282 "dsb", // ensure store completes
283 "isb", // synchronize pipeline
284 "msr PRIMASK, {2}", // unnest critical section
285 out(reg) _,
286 out(reg) _,
287 out(reg) _,
288 options(nostack),
289 );
290 compiler_fence(Ordering::SeqCst);
291 }
292}
293
294#[cfg(armv7em)]
295pub use self::v7em::*;
296#[cfg(armv7em)]
297mod v7em {
298 use core::arch::asm;
299
300 #[inline(always)]
301 pub unsafe fn __basepri_max_cm7_r0p1(val: u8) {
302 asm!(
303 "mrs {1}, PRIMASK",
304 "cpsid i",
305 "tst.w {1}, #1",
306 "msr BASEPRI_MAX, {0}",
307 "it ne",
308 "bxne lr",
309 "cpsie i",
310 in(reg) val,
311 out(reg) _,
312 options(nomem, nostack, preserves_flags),
313 );
314 }
315
316 #[inline(always)]
317 pub unsafe fn __basepri_w_cm7_r0p1(val: u8) {
318 asm!(
319 "mrs {1}, PRIMASK",
320 "cpsid i",
321 "tst.w {1}, #1",
322 "msr BASEPRI, {0}",
323 "it ne",
324 "bxne lr",
325 "cpsie i",
326 in(reg) val,
327 out(reg) _,
328 options(nomem, nostack, preserves_flags),
329 );
330 }
331}
332
333#[cfg(armv8m)]
334pub use self::v8m::*;
335/// Baseline and Mainline.
336#[cfg(armv8m)]
337mod v8m {
338 use core::arch::asm;
339
340 #[inline(always)]
341 pub unsafe fn __tt(mut target: u32) -> u32 {
342 asm!(
343 "tt {target}, {target}",
344 target = inout(reg) target,
345 options(nomem, nostack, preserves_flags),
346 );
347 target
348 }
349
350 #[inline(always)]
351 pub unsafe fn __ttt(mut target: u32) -> u32 {
352 asm!(
353 "ttt {target}, {target}",
354 target = inout(reg) target,
355 options(nomem, nostack, preserves_flags),
356 );
357 target
358 }
359
360 #[inline(always)]
361 pub unsafe fn __tta(mut target: u32) -> u32 {
362 asm!(
363 "tta {target}, {target}",
364 target = inout(reg) target,
365 options(nomem, nostack, preserves_flags),
366 );
367 target
368 }
369
370 #[inline(always)]
371 pub unsafe fn __ttat(mut target: u32) -> u32 {
372 asm!(
373 "ttat {target}, {target}",
374 target = inout(reg) target,
375 options(nomem, nostack, preserves_flags),
376 );
377 target
378 }
379
380 #[inline(always)]
381 pub unsafe fn __msp_ns_r() -> u32 {
382 let r;
383 asm!("mrs {}, MSP_NS", out(reg) r, options(nomem, nostack, preserves_flags));
384 r
385 }
386
387 #[inline(always)]
388 pub unsafe fn __msp_ns_w(val: u32) {
389 asm!("msr MSP_NS, {}", in(reg) val, options(nomem, nostack, preserves_flags));
390 }
391
392 #[inline(always)]
393 pub unsafe fn __bxns(val: u32) {
394 asm!("BXNS {}", in(reg) val, options(nomem, nostack, preserves_flags));
395 }
396}
397
398#[cfg(armv8m_main)]
399pub use self::v8m_main::*;
400/// Mainline only.
401#[cfg(armv8m_main)]
402mod v8m_main {
403 use core::arch::asm;
404
405 #[inline(always)]
406 pub unsafe fn __msplim_r() -> u32 {
407 let r;
408 asm!("mrs {}, MSPLIM", out(reg) r, options(nomem, nostack, preserves_flags));
409 r
410 }
411
412 #[inline(always)]
413 pub unsafe fn __msplim_w(val: u32) {
414 asm!("msr MSPLIM, {}", in(reg) val, options(nomem, nostack, preserves_flags));
415 }
416
417 #[inline(always)]
418 pub unsafe fn __psplim_r() -> u32 {
419 let r;
420 asm!("mrs {}, PSPLIM", out(reg) r, options(nomem, nostack, preserves_flags));
421 r
422 }
423
424 #[inline(always)]
425 pub unsafe fn __psplim_w(val: u32) {
426 asm!("msr PSPLIM, {}", in(reg) val, options(nomem, nostack, preserves_flags));
427 }
428}
429
430#[cfg(has_fpu)]
431pub use self::fpu::*;
432/// All targets with FPU.
433#[cfg(has_fpu)]
434mod fpu {
435 use core::arch::asm;
436
437 #[inline(always)]
438 pub unsafe fn __fpscr_r() -> u32 {
439 let r;
440 asm!("vmrs {}, fpscr", out(reg) r, options(nomem, nostack, preserves_flags));
441 r
442 }
443
444 #[inline(always)]
445 pub unsafe fn __fpscr_w(val: u32) {
446 asm!("vmsr fpscr, {}", in(reg) val, options(nomem, nostack));
447 }
448}
449

Provided by KDAB

Privacy Policy