diff options
Diffstat (limited to 'asm')
-rw-r--r-- | asm/inline.rs | 22 | ||||
-rw-r--r-- | asm/lib.rs | 5 |
2 files changed, 24 insertions, 3 deletions
diff --git a/asm/inline.rs b/asm/inline.rs index f6a3ebb..f2014f8 100644 --- a/asm/inline.rs +++ b/asm/inline.rs @@ -177,11 +177,31 @@ pub unsafe fn __wfi() { /// Semihosting syscall. #[inline(always)] -pub unsafe fn __syscall(mut nr: u32, arg: u32) -> u32 { +pub unsafe fn __sh_syscall(mut nr: u32, arg: u32) -> u32 { asm!("bkpt #0xab", inout("r0") nr, in("r1") arg); nr } +/// Set CONTROL.SPSEL to 0, write `msp` to MSP, branch to `rv`. +#[inline(always)] +pub unsafe fn __bootstrap(msp: u32, rv: u32) -> ! { + asm!( + "mrs {tmp}, CONTROL", + "bics {tmp}, {spsel}", + "msr CONTROL, {tmp}", + "isb", + "msr MSP, {msp}", + "bx {rv}", + // `out(reg) _` is not permitted in a `noreturn` asm! call, + // so instead use `in(reg) 0` and don't restore it afterwards. + tmp = in(reg) 0, + spsel = in(reg) 2, + msp = in(reg) msp, + rv = in(reg) rv, + options(noreturn), + ); +} + // v7m *AND* v8m.main, but *NOT* v8m.base #[cfg(any(armv7m, armv8m_main))] pub use self::v7m::*; @@ -69,10 +69,11 @@ shims! { fn __psp_r() -> u32; fn __psp_w(val: u32); fn __sev(); - fn __udf(); + fn __udf() -> !; fn __wfe(); fn __wfi(); - fn __syscall(nr: u32, arg: u32) -> u32; + fn __sh_syscall(nr: u32, arg: u32) -> u32; + fn __bootstrap(msp: u32, rv: u32) -> !; } // v7m *AND* v8m.main, but *NOT* v8m.base |