1+ //@ revisions: hard soft
12//@ assembly-output: emit-asm
2- //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -Copt-level=1
3- //@ needs-llvm-components: arm
3+ //@ [hard] compile-flags: --target thumbv8m.main-none-eabihf --crate-type lib -Copt-level=1
4+ //@ [soft] compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -Copt-level=1
5+ //@ [hard] needs-llvm-components: arm
6+ //@ [soft] needs-llvm-components: arm
47#![ crate_type = "lib" ]
58#![ feature( abi_c_cmse_nonsecure_call, cmse_nonsecure_entry, no_core, lang_items) ]
69#![ no_core]
@@ -9,15 +12,88 @@ pub trait Sized {}
912#[ lang = "copy" ]
1013pub trait Copy { }
1114
12- // CHECK-LABEL: __acle_se_entry_point
13- // CHECK: bxns
15+ // CHECK-LABEL: __acle_se_entry_point:
16+ // CHECK-NEXT: entry_point:
17+ //
18+ // Write return argument (two registers since 64bit integer)
19+ // CHECK: movs r0, #0
20+ // CHECK: movs r1, #0
21+ //
22+ // If we are using hard-float:
23+ // * Check if the float registers were touched (bit 3 in CONTROL)
24+ // hard: mrs [[REG:r[0-9]+]], control
25+ // hard: tst.w [[REG]], #8
26+ // hard: beq [[LABEL:[\.a-zA-Z0-9_]+]]
27+ //
28+ // * If touched clear all float registers (d0..=d7)
29+ // hard: vmov d0,
30+ // hard: vmov d1,
31+ // hard: vmov d2,
32+ // hard: vmov d3,
33+ // hard: vmov d4,
34+ // hard: vmov d5,
35+ // hard: vmov d6,
36+ // hard: vmov d7,
37+ //
38+ // * If touched clear FPU status register
39+ // hard: vmrs [[REG:r[0-9]+]], fpscr
40+ // hard: bic [[REG]], [[REG]], #159
41+ // hard: bic [[REG]], [[REG]], #4026531840
42+ // hard: vmsr fpscr, [[REG]]
43+ // hard: [[LABEL]]:
44+ //
45+ // Clear all other registers that might have been used
46+ // CHECK: mov r2,
47+ // CHECK: mov r3,
48+ // CHECK: mov r12,
49+ //
50+ // Clear the flags
51+ // CHECK: msr apsr_nzcvq,
52+ //
53+ // Branch back to non-secure side
54+ // CHECK: bxns lr
1455#[ no_mangle]
1556pub extern "C-cmse-nonsecure-entry" fn entry_point ( ) -> i64 {
1657 0
1758}
1859
60+ // NOTE for future codegen changes:
61+ // The specific register assignment is not important, however:
62+ // * all registers must be cleared before `blxns` is executed
63+ // (either by writing arguments or any other value)
64+ // * the lowest bit on the address of the callee must be cleared
65+ // * the flags need to be overwritten
66+ // * `blxns` needs to be called with the callee address
67+ // (with the lowest bit cleared)
68+ //
1969// CHECK-LABEL: call_nonsecure
20- // CHECK: blxns
70+ // Save callee pointer
71+ // CHECK: mov r12, r0
72+ //
73+ // All arguments are written to (writes r0..=r3)
74+ // CHECK: movs r0, #0
75+ // CHECK: movs r1, #1
76+ // CHECK: movs r2, #2
77+ // CHECK: movs r3, #3
78+ //
79+ // Lowest bit gets cleared on callee address
80+ // CHECK: bic r12, r12, #1
81+ //
82+ // Ununsed registers get cleared (r4..=r11)
83+ // CHECK: mov r4,
84+ // CHECK: mov r5,
85+ // CHECK: mov r6,
86+ // CHECK: mov r7,
87+ // CHECK: mov r8,
88+ // CHECK: mov r9,
89+ // CHECK: mov r10,
90+ // CHECK: mov r11,
91+ //
92+ // Flags get cleared
93+ // CHECK: msr apsr_nzcvq,
94+ //
95+ // Call to non-secure
96+ // CHECK: blxns r12
2197#[ no_mangle]
2298pub fn call_nonsecure (
2399 f : unsafe extern "C-cmse-nonsecure-call" fn ( u32 , u32 , u32 , u32 ) -> u64 ,
0 commit comments