| //@ 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) } |
| } |