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