//@ revisions: hard soft //@ assembly-output: emit-asm //@ [hard] compile-flags: --target thumbv8m.main-none-eabihf --crate-type lib -Copt-level=1 //@ [soft] compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -Copt-level=1 //@ [hard] needs-llvm-components: arm //@ [soft] needs-llvm-components: arm #![crate_type = "lib"] #![feature(abi_c_cmse_nonsecure_call, cmse_nonsecure_entry, no_core, lang_items)] #![no_core] #[lang = "sized"] pub trait Sized {} #[lang = "copy"] pub trait Copy {} // CHECK-LABEL: __acle_se_entry_point: // CHECK-NEXT: entry_point: // // Write return argument (two registers since 64bit integer) // CHECK: movs r0, #0 // CHECK: movs r1, #0 // // If we are using hard-float: // * Check if the float registers were touched (bit 3 in CONTROL) // hard: mrs [[REG:r[0-9]+]], control // hard: tst.w [[REG]], #8 // hard: beq [[LABEL:[\.a-zA-Z0-9_]+]] // // * If touched clear all float registers (d0..=d7) // hard: vmov d0, // hard: vmov d1, // hard: vmov d2, // hard: vmov d3, // hard: vmov d4, // hard: vmov d5, // hard: vmov d6, // hard: vmov d7, // // * If touched clear FPU status register // hard: vmrs [[REG:r[0-9]+]], fpscr // hard: bic [[REG]], [[REG]], #159 // hard: bic [[REG]], [[REG]], #4026531840 // hard: vmsr fpscr, [[REG]] // hard: [[LABEL]]: // // Clear all other registers that might have been used // CHECK: mov r2, // CHECK: mov r3, // CHECK: mov r12, // // Clear the flags // CHECK: msr apsr_nzcvq, // // Branch back to non-secure side // CHECK: bxns lr #[no_mangle] pub extern "C-cmse-nonsecure-entry" fn entry_point() -> i64 { 0 } // NOTE for future codegen changes: // The specific register assignment is not important, however: // * all registers must be cleared before `blxns` is executed // (either by writing arguments or any other value) // * the lowest bit on the address of the callee must be cleared // * the flags need to be overwritten // * `blxns` needs to be called with the callee address // (with the lowest bit cleared) // // CHECK-LABEL: call_nonsecure // Save callee pointer // CHECK: mov r12, r0 // // All arguments are written to (writes r0..=r3) // CHECK: movs r0, #0 // CHECK: movs r1, #1 // CHECK: movs r2, #2 // CHECK: movs r3, #3 // // Lowest bit gets cleared on callee address // CHECK: bic r12, r12, #1 // // Ununsed registers get cleared (r4..=r11) // CHECK: mov r4, // CHECK: mov r5, // CHECK: mov r6, // CHECK: mov r7, // CHECK: mov r8, // CHECK: mov r9, // CHECK: mov r10, // CHECK: mov r11, // // Flags get cleared // CHECK: msr apsr_nzcvq, // // Call to non-secure // CHECK: blxns r12 #[no_mangle] pub fn call_nonsecure( f: unsafe extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32) -> u64, ) -> u64 { unsafe { f(0, 1, 2, 3) } }