1 /*
2  * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "fpu_s_tests.h"
9 #include "../fpu_tests_common.h"
10 #include "tfm_psa_call_pack.h"
11 #include "utilities.h"
12 
13 /* Test FP context protection after psa calls. */
14 static void tfm_fpu_test_fp_protection_s_psa_call(struct test_result_t *ret);
15 
16 /* Test reliability of FP context protection after psa calls by loops. */
17 static void tfm_fpu_test_fp_protection_s_psa_call_loop(
18                                                     struct test_result_t *ret);
19 
20 /* Test FP caller and callee protection after secure interrupt. */
21 static void tfm_fpu_test_fp_protection_s_after_s_interrupt(
22                                                     struct test_result_t *ret);
23 
24 static struct test_t fpu_s_tests[] = {
25     {
26         &tfm_fpu_test_clear_client_fp_data, "TFM_S_FPU_TEST_1001",
27         "Clear FP registers in FPU client partition"
28     },
29     {
30         &tfm_fpu_test_fp_protection_s_psa_call_loop, "TFM_S_FPU_TEST_1002",
31         "Test reliability of FP context protection after psa calls"
32     },
33     {
34         &tfm_fpu_test_fp_protection_s_after_s_interrupt, "TFM_S_FPU_TEST_1003",
35         "Test FP context protection in S thread after S interrupt"
36     },
37 };
38 
register_testsuite_s_fpu_interface(struct test_suite_t * p_test_suite)39 void register_testsuite_s_fpu_interface(struct test_suite_t *p_test_suite)
40 {
41     uint32_t list_size;
42 
43     list_size = (sizeof(fpu_s_tests) / sizeof(fpu_s_tests[0]));
44 
45     set_testsuite("FPU secure interface test (TFM_S_FPU_TEST_1XXX)",
46                   fpu_s_tests, list_size, p_test_suite);
47 }
48 
49 /*
50  * Description: Directly jump to tfm_psa_call_pack from S side.
51  * Expectation: Return psa_status_t status code.
52  */
fpu_s_call(uintptr_t psa_call_param)53 __attribute__((naked)) static uint32_t fpu_s_call(uintptr_t psa_call_param)
54 {
55         __asm volatile(
56 #if !defined(__ICCARM__)
57         ".syntax unified                          \n"
58 #endif
59         "   push    {r4-r6, lr}                   \n"
60         "   mov     r4, r0                        \n"
61         /* Load params of tfm_psa_call_pack into r0~r3. */
62         "   ldr     r0, [r4], #4                  \n"  /* psa handle */
63         "   ldr     r1, [r4], #4                  \n"  /* ctrl_param */
64         "   ldr     r2, [r4], #4                  \n"  /* in_vec */
65         "   ldr     r3, [r4]                      \n"  /* out_vec */
66         "   ldr     r5, ="M2S(tfm_psa_call_pack)" \n"
67         "   blx     r5                            \n"
68         "   pop     {r4-r6, pc}                   \n"
69     );
70 }
71 
72 /*
73  * Description: Test FP context protection after psa calls. Change FP callee
74  * registers in FPU client/service partition separately, then check FP callee
75  * registers after psa calls.
76  * Expectation: FP callee registers in FPU client/service partition should be
77  * saved and restored correctly.
78  */
tfm_fpu_test_fp_protection_s_psa_call(struct test_result_t * ret)79 static void tfm_fpu_test_fp_protection_s_psa_call(struct test_result_t *ret)
80 {
81     psa_handle_t handle;
82     uint32_t param;
83     uint32_t psa_call_param[PSA_CALL_PARAM_LEN] = {0};
84     uint32_t fp_callee_buffer[NR_FP_CALLEE_REG] = {0};
85     const uint32_t expecting_callee_content[NR_FP_CALLEE_REG] = {
86         0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
87         0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF
88     };
89 
90     uintptr_t func_table[] = {
91         (uintptr_t)populate_callee_fp_regs, (uintptr_t)expecting_callee_content,
92         (uintptr_t)fpu_s_call, (uintptr_t)psa_call_param,
93         (uintptr_t)dump_fp_callee, (uintptr_t)fp_callee_buffer
94     };
95     uintptr_t func_return[ARRAY_SIZE(func_table)/2] = {0};
96 
97     ret->val = TEST_PASSED;
98 
99     handle = psa_connect(TFM_FPU_CHECK_FP_CALLEE_REGISTER_SID,
100                          TFM_FPU_CHECK_FP_CALLEE_REGISTER_VERSION);
101     if (!PSA_HANDLE_IS_VALID(handle)) {
102         TEST_FAIL("PSA Connect fail!");
103         return;
104     }
105 
106     param = PARAM_PACK(PSA_IPC_CALL, 0, 0);
107     psa_call_param[0] = (uint32_t)handle;
108     psa_call_param[1] = param;
109 
110     fp_func_jump_template(func_table, func_return, ARRAY_SIZE(func_table)/2);
111 
112     if ((psa_status_t)func_return[1] != PSA_SUCCESS) {
113         TEST_FAIL("FP callee registers check fail in service!");
114     }
115 
116     if (memcmp(fp_callee_buffer, expecting_callee_content,
117                FP_CALLEE_BUF_SIZE)) {
118         TEST_FAIL("FP callee registers are not correctly restored in client!");
119     }
120 
121     psa_close(handle);
122 }
123 
124 /*
125  * Description: Test reliability of FP context protection after psa calls by
126  * loops. Change FP callee registers in FPU client/service partition separately,
127  * then check FP callee registers after psa calls.
128  * Expectation: FP callee registers in FPU client/service partition should be
129  * saved and restored correctly.
130  */
tfm_fpu_test_fp_protection_s_psa_call_loop(struct test_result_t * ret)131 static void tfm_fpu_test_fp_protection_s_psa_call_loop(
132                                                     struct test_result_t *ret)
133 {
134     uint32_t itr;
135 
136     for (itr = 0; itr < LOOP_ITERATIONS; itr++) {
137         TEST_LOG("  > Iteration %d of %d\r", itr + 1, LOOP_ITERATIONS);
138 
139         tfm_fpu_test_fp_protection_s_psa_call(ret);
140     }
141 }
142 
143 /*
144  * Description: Secure client trigger a secure interrupt and check caller and
145  * callee registers.
146  * Expectation: FP register in secure client should be restored after S
147  * interrupt.
148  */
tfm_fpu_test_fp_protection_s_after_s_interrupt(struct test_result_t * ret)149 static void tfm_fpu_test_fp_protection_s_after_s_interrupt(
150                                                 struct test_result_t *ret)
151 {
152     uint32_t fp_caller_buffer[NR_FP_CALLER_REG] = {0};
153     uint32_t fp_callee_buffer[NR_FP_CALLEE_REG] = {0};
154     const uint32_t expecting_caller_content[NR_FP_CALLER_REG] = {
155         0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
156         0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF
157     };
158     const uint32_t expecting_callee_content[NR_FP_CALLEE_REG] = {
159         0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
160         0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF
161     };
162 
163     ret->val = TEST_PASSED;
164 
165     uintptr_t func_table[] = {
166         (uintptr_t)populate_caller_fp_regs, (uintptr_t)expecting_caller_content,
167         (uintptr_t)populate_callee_fp_regs, (uintptr_t)expecting_callee_content,
168         (uintptr_t)fpu_interrupt_trigger, (uintptr_t)TFM_FPU_S_TEST_IRQ,
169         (uintptr_t)dump_fp_caller, (uintptr_t)fp_caller_buffer,
170         (uintptr_t)dump_fp_callee, (uintptr_t)fp_callee_buffer
171     };
172     uintptr_t func_return[ARRAY_SIZE(func_table)/2] = {0};
173 
174     fp_func_jump_template(func_table, func_return, ARRAY_SIZE(func_table)/2);
175 
176     if (memcmp(fp_caller_buffer, expecting_caller_content,
177                FP_CALLER_BUF_SIZE)) {
178         TEST_FAIL("FP caller registers are not correctly retored in client!");
179     }
180 
181     if (memcmp(fp_callee_buffer, expecting_callee_content,
182                FP_CALLEE_BUF_SIZE)) {
183         TEST_FAIL("FP callee registers are not correctly retored in client!");
184     }
185 }
186