1
+ //@ revisions: hard soft
1
2
//@ 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
4
7
#![ crate_type = "lib" ]
5
8
#![ feature( abi_c_cmse_nonsecure_call, cmse_nonsecure_entry, no_core, lang_items) ]
6
9
#![ no_core]
@@ -10,14 +13,85 @@ pub trait Sized {}
10
13
pub trait Copy { }
11
14
12
15
// CHECK-LABEL: __acle_se_entry_point
13
- // CHECK: bxns
16
+ // CHECK: 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 r12, control
25
+ // hard: tst.w r12, #8
26
+ // hard: beq .LBB0_2
27
+ //
28
+ // * If touched clear all float registers (d0..=d7)
29
+ // hard: vmov d0, lr, lr
30
+ // hard: vmov d1, lr, lr
31
+ // hard: vmov d2, lr, lr
32
+ // hard: vmov d3, lr, lr
33
+ // hard: vmov d4, lr, lr
34
+ // hard: vmov d5, lr, lr
35
+ // hard: vmov d6, lr, lr
36
+ // hard: vmov d7, lr, lr
37
+ //
38
+ // * If touched clear FPU status register
39
+ // hard: vmrs r12, fpscr
40
+ // hard: bic r12, r12, #159
41
+ // hard: bic r12, r12, #4026531840
42
+ // hard: vmsr fpscr, r12
43
+ // hard: .LBB0_2:
44
+ //
45
+ // Clear all other registers that might have been used
46
+ // CHECK: mov r2, lr
47
+ // CHECK: mov r3, lr
48
+ // CHECK: mov r12, lr
49
+ //
50
+ // Clear the flags
51
+ // CHECK: msr apsr_nzcvq, lr
52
+ //
53
+ // Branch back to non-secure side
54
+ // CHECK: bxns lr
14
55
#[ no_mangle]
15
56
pub extern "C-cmse-nonsecure-entry" fn entry_point ( ) -> i64 {
16
57
0
17
58
}
18
59
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
+ //
19
69
// CHECK-LABEL: call_nonsecure
20
- // CHECK: blxns
70
+ // All arguments are written to (writes r0..=r3 and r12)
71
+ // CHECK: mov r12, r0
72
+ // CHECK: movs r0, #0
73
+ // CHECK: movs r1, #1
74
+ // CHECK: movs r2, #2
75
+ // CHECK: movs r3, #3
76
+ //
77
+ // Lowest bit gets cleared on callee address
78
+ // CHECK: bic r12, r12, #1
79
+ //
80
+ // Ununsed registers get cleared (r4..=r11)
81
+ // CHECK: mov r4, r12
82
+ // CHECK: mov r5, r12
83
+ // CHECK: mov r6, r12
84
+ // CHECK: mov r7, r12
85
+ // CHECK: mov r8, r12
86
+ // CHECK: mov r9, r12
87
+ // CHECK: mov r10, r12
88
+ // CHECK: mov r11, r12
89
+ //
90
+ // Flags get cleared
91
+ // CHECK: msr apsr_nzcvq, r12
92
+ //
93
+ // Call to non-secure
94
+ // CHECK: blxns r12
21
95
#[ no_mangle]
22
96
pub fn call_nonsecure (
23
97
f : unsafe extern "C-cmse-nonsecure-call" fn ( u32 , u32 , u32 , u32 ) -> u64 ,
0 commit comments