blob: defb843ece1070a89d084f80d7eb43cfdf9ca875 [file] [log] [blame]
Sandrine Bailleux3f556eb2018-11-16 14:00:40 +01001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <psci.h>
8#include <smccc.h>
9#include <std_svc.h>
Sandrine Bailleuxc5d315e2019-01-07 10:44:32 +010010#include <stdio.h>
Sandrine Bailleux3f556eb2018-11-16 14:00:40 +010011#include <string.h>
12#include <tftf_lib.h>
Sandrine Bailleuxc5d315e2019-01-07 10:44:32 +010013#include <trusted_os.h>
Sandrine Bailleux3f556eb2018-11-16 14:00:40 +010014#include <tsp.h>
15#include <utils_def.h>
16
17/* An invalid SMC function number. */
18#define INVALID_FN 0x666
19
20/* PSCI version returned by TF-A. */
21static const uint32_t psci_version = PSCI_VERSION(PSCI_MAJOR_VER,
22 PSCI_MINOR_VER);
23
24/* UUID of the standard service in TF-A. */
25static const smc_ret_values std_svc_uuid = {
26 0x108d905b, 0x47e8f863, 0xfbc02dae, 0xe2f64156
27};
28
29/*
30 * Build an SMC function ID given its type (fast/yielding), calling convention,
31 * owning entity number and function number.
32 */
33static inline uint32_t make_smc_fid(unsigned int type, unsigned int cc,
34 unsigned int oen, unsigned int func_num)
35{
36 return (type << FUNCID_TYPE_SHIFT) | (cc << FUNCID_CC_SHIFT)
37 | (oen << FUNCID_OEN_SHIFT) | (func_num << FUNCID_NUM_SHIFT);
38}
39
40/* Exit the test if the specified condition holds true. */
41#define FAIL_IF(_cond) \
42 do { \
43 if ((_cond)) { \
44 return TEST_RESULT_FAIL; \
45 } \
46 } while (0)
47
48/*
49 * Send an SMC with the specified arguments.
50 * Check that the values it returns match the expected ones. If not, write an
51 * error message in the test report.
52 */
53static bool smc_check_eq(const smc_args *args, const smc_ret_values *expect)
54{
55 smc_ret_values ret = tftf_smc(args);
56
57 if (memcmp(&ret, expect, sizeof(smc_ret_values)) == 0) {
58 return true;
59 } else {
60 tftf_testcase_printf(
61 "Got {0x%lx,0x%lx,0x%lx,0x%lx}, expected {0x%lx,0x%lx,0x%lx,0x%lx}.\n",
62 ret.ret0, ret.ret1, ret.ret2, ret.ret3,
63 expect->ret0, expect->ret1, expect->ret2, expect->ret3);
64 return false;
65 }
66}
67
Sandrine Bailleuxc5d315e2019-01-07 10:44:32 +010068/*
69 * Send an SMC with the specified arguments.
70 * Check that the values it returns match the expected ones. The do_check[]
71 * array indicates which ones should be checked and provides some flexibility
Imre Kis1c97f942019-09-23 16:44:03 +020072 * to ignore some of them. Also the allow_zeros[] array lets the values to be
73 * zeroes. allow_zeros[] is only evaluated if do_check[] is true for the given
74 * value.
75 * The two common solutions for preventing data leak from the TEE is to either
76 * preserve the register values or zero them out. Having an expected value and
77 * also allowing zeroes in this function comes handy in this previous case.
Sandrine Bailleuxc5d315e2019-01-07 10:44:32 +010078 * If the values do not match, write an error message in the test report.
79 */
80static bool smc_check_match(const smc_args *args, const smc_ret_values *expect,
Imre Kis1c97f942019-09-23 16:44:03 +020081 const bool do_check[4], const bool allow_zeros[4])
Sandrine Bailleuxc5d315e2019-01-07 10:44:32 +010082{
83 smc_ret_values ret = tftf_smc(args);
84
Imre Kis1c97f942019-09-23 16:44:03 +020085#define CHK_RET(ret, expect, allow_zeros) \
86 ((ret) != (expect) && !((allow_zeros) && (ret) == 0))
87
88 if ((do_check[0] && CHK_RET(ret.ret0, expect->ret0, allow_zeros[0])) ||
89 (do_check[1] && CHK_RET(ret.ret1, expect->ret1, allow_zeros[1])) ||
90 (do_check[2] && CHK_RET(ret.ret2, expect->ret2, allow_zeros[2])) ||
91 (do_check[3] && CHK_RET(ret.ret3, expect->ret3, allow_zeros[3]))) {
92
93#undef CHK_RET
Sandrine Bailleuxc5d315e2019-01-07 10:44:32 +010094 /*
95 * Build an error message where unchecked SMC return values are
96 * displayed as '*'.
97 */
Imre Kis1c97f942019-09-23 16:44:03 +020098 char expect_str[4][28];
99#define BUILD_STR(_buf, _buf_size, _do_check, _allow_zero, _expect) \
100 do { \
101 if (_do_check) { \
102 if (_allow_zero) { \
103 snprintf(_buf, _buf_size, \
104 "0x%lx or zero", \
105 _expect); \
106 } else { \
107 snprintf(_buf, _buf_size, \
108 "0x%lx", _expect); \
109 } \
110 } else { \
111 _buf[0] = '*'; \
112 _buf[1] = '\0'; \
113 } \
114 } while (0)
115 BUILD_STR(expect_str[0], sizeof(expect_str[0]),
116 do_check[0], allow_zeros[0], expect->ret0);
117 BUILD_STR(expect_str[1], sizeof(expect_str[1]),
118 do_check[1], allow_zeros[1], expect->ret1);
119 BUILD_STR(expect_str[2], sizeof(expect_str[2]),
120 do_check[2], allow_zeros[2], expect->ret2);
121 BUILD_STR(expect_str[3], sizeof(expect_str[3]),
122 do_check[3], allow_zeros[3], expect->ret3);
Sandrine Bailleuxc5d315e2019-01-07 10:44:32 +0100123#undef BUILD_STR
124 tftf_testcase_printf(
125 "Got {0x%lx,0x%lx,0x%lx,0x%lx}, expected {%s,%s,%s,%s}.\n",
126 ret.ret0, ret.ret1, ret.ret2, ret.ret3,
127 expect_str[0], expect_str[1], expect_str[2], expect_str[3]);
128
129 return false;
130 } else {
131 return true;
132 }
133}
134
Sandrine Bailleux3f556eb2018-11-16 14:00:40 +0100135/* Exercise SMC32 calling convention with fast SMC calls. */
136test_result_t smc32_fast(void)
137{
138 /* Valid Fast SMC32 using all 4 return values. */
139 const smc_args args1 = { .fid = SMC_STD_SVC_UID };
140 FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
141
142 /* Invalid Fast SMC32. */
143 const smc_args args2 = {
144 make_smc_fid(SMC_TYPE_FAST, SMC_32, OEN_ARM_START, INVALID_FN),
145 0x11111111, 0x22222222, 0x33333333 };
146 const smc_ret_values ret2
147 = { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
148 FAIL_IF(!smc_check_eq(&args2, &ret2));
149
150 /* Valid Fast SMC32 using 1 return value. */
151 const smc_args args3
152 = { SMC_PSCI_VERSION, 0x44444444, 0x55555555, 0x66666666 };
153 const smc_ret_values ret3
154 = { psci_version, 0x44444444, 0x55555555, 0x66666666 };
155 FAIL_IF(!smc_check_eq(&args3, &ret3));
156
157 return TEST_RESULT_SUCCESS;
158}
159
160/* Exercise SMC64 calling convention with yielding SMC calls. */
161test_result_t smc64_yielding(void)
162{
163 /* Valid Fast SMC32 using all 4 return values. */
164 const smc_args args1 = { .fid = SMC_STD_SVC_UID };
165 FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
166
167 /* Invalid function number, SMC64 Yielding. */
168 const smc_args args2 = {
169 make_smc_fid(SMC_TYPE_STD, SMC_64, OEN_ARM_START, INVALID_FN),
170 0x11111111, 0x22222222, 0x33333333 };
171 const smc_ret_values ret2
172 = { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
173 FAIL_IF(!smc_check_eq(&args2, &ret2));
174
175 /*
176 * Valid[1] yielding SMC64 using 1 return value.
177 *
178 * [1] Valid from the point of view of the generic SMC handler if the
179 * TSPd is present. In this case, the SMC request gets passed to the
180 * TSPd handler code. The fact that it then gets rejected by the TSPd is
181 * irrelevant here, as we are not trying to test the TSPd nor the TSP.
182 *
183 * In other cases (i.e. AArch64 BL31 with no TSPd support or AArch32
184 * SP_MIN) this test should still fail in the same way, although it
185 * doesn't exercise the same code path in TF-A.
186 */
187 const smc_args args3 = {
188 make_smc_fid(SMC_TYPE_STD, SMC_64, OEN_TOS_START, INVALID_FN),
189 0x44444444, 0x55555555, 0x66666666 };
Sandrine Bailleuxc5d315e2019-01-07 10:44:32 +0100190
191 if (is_trusted_os_present(NULL)) {
192 /*
193 * The Trusted OS is free to return any error code in x0 but it
Imre Kis1c97f942019-09-23 16:44:03 +0200194 * should at least preserve or fill by zeroes the values of
195 * x1-x3.
Sandrine Bailleuxc5d315e2019-01-07 10:44:32 +0100196 */
197 const smc_ret_values ret3 = { 0, 0x44444444, 0x55555555, 0x66666666 };
198 const bool check[4] = { false, true, true, true };
Imre Kis1c97f942019-09-23 16:44:03 +0200199 const bool allow_zeros[4] = { false, true, true, true };
200
201 FAIL_IF(!smc_check_match(&args3, &ret3, check, allow_zeros));
Sandrine Bailleuxc5d315e2019-01-07 10:44:32 +0100202 } else {
203 const smc_ret_values ret3
204 = { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666 };
205 FAIL_IF(!smc_check_eq(&args3, &ret3));
206 }
Sandrine Bailleux3f556eb2018-11-16 14:00:40 +0100207
208 return TEST_RESULT_SUCCESS;
209}
210
211#ifdef AARCH32
212static test_result_t smc64_fast_caller32(void)
213{
214 /* Valid Fast SMC32 using all 4 return values. */
215 smc_args args1 = { .fid = SMC_STD_SVC_UID };
216 FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
217
218 /* Invalid SMC function number, Fast SMC64. */
219 const smc_args args2 = {
220 make_smc_fid(SMC_TYPE_FAST, SMC_64, OEN_ARM_START, INVALID_FN),
221 0x11111111, 0x22222222, 0x33333333 };
222 const smc_ret_values ret2
223 = { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
224 FAIL_IF(!smc_check_eq(&args2, &ret2));
225
226 /*
227 * Valid SMC function number, Fast SMC64. However, 32-bit callers are
228 * forbidden to use the SMC64 calling convention.
229 */
230 const smc_args args3 = { SMC_PSCI_AFFINITY_INFO_AARCH64,
231 0x44444444, 0x55555555, 0x66666666 };
232 const smc_ret_values ret3
233 = { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666 };
234 FAIL_IF(!smc_check_eq(&args3, &ret3));
235
236 return TEST_RESULT_SUCCESS;
237}
238#else
239static test_result_t smc64_fast_caller64(void)
240{
241 /* Valid Fast SMC32 using all 4 return values. */
242 smc_args args1 = { .fid = SMC_STD_SVC_UID };
243 FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
244
245 /* Invalid function number, Fast SMC64. */
246 const smc_args args2 = {
247 make_smc_fid(SMC_TYPE_FAST, SMC_64, OEN_ARM_START, INVALID_FN),
248 0x11111111, 0x22222222, 0x33333333 };
249 const smc_ret_values ret2
250 = { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
251 FAIL_IF(!smc_check_eq(&args2, &ret2));
252
253 /* Valid Fast SMC64 using 1 return value. */
254 const smc_args args3 = { SMC_PSCI_AFFINITY_INFO_AARCH64,
255 0x44444444, 0x55555555, 0x66666666 };
256 const smc_ret_values ret3
257 = { PSCI_E_INVALID_PARAMS, 0x44444444, 0x55555555, 0x66666666 };
258 FAIL_IF(!smc_check_eq(&args3, &ret3));
259
260 return TEST_RESULT_SUCCESS;
261}
262#endif /* AARCH32 */
263
264/* Exercise SMC64 calling convention with fast SMC calls. */
265test_result_t smc64_fast(void)
266{
267#ifdef AARCH32
268 return smc64_fast_caller32();
269#else
270 return smc64_fast_caller64();
271#endif
272}
273
274/* Exercise SMC32 calling convention with yielding SMC calls. */
275test_result_t smc32_yielding(void)
276{
277 /* Valid Fast SMC32 using all 4 return values. */
278 const smc_args args1 = { .fid = SMC_STD_SVC_UID };
279 FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
280
281 /* Invalid function number, SMC32 Yielding. */
282 const smc_args args2 = {
283 make_smc_fid(SMC_TYPE_STD, SMC_32, OEN_ARM_START, INVALID_FN),
284 0x11111111, 0x22222222, 0x33333333 };
285 const smc_ret_values ret2
286 = { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
287 FAIL_IF(!smc_check_eq(&args2, &ret2));
288
289 /*
290 * Valid[1] yielding SMC32 using 1 return value.
291 *
292 * [1] Valid from the point of view of the generic SMC handler if a
293 * secure payload dispatcher handling this SMC range is present. In this
294 * case, the SMC request gets passed to the dispatcher handler code. The
295 * fact that it then gets rejected by the dispatcher is irrelevant here,
296 * as we are not trying to test the dispatcher nor the secure payload.
297 *
298 * In BL31 has no SPD support, this test should still fail in the same
299 * way, although it doesn't exercise the same code path in TF-A.
300 */
301 const smc_args args3 = {
302 make_smc_fid(SMC_TYPE_STD, SMC_32, OEN_TOS_START, INVALID_FN),
303 0x44444444, 0x55555555, 0x66666666 };
Sandrine Bailleuxc5d315e2019-01-07 10:44:32 +0100304
305 if (is_trusted_os_present(NULL)) {
306 /*
307 * The Trusted OS is free to return any error code in x0 but it
Imre Kis1c97f942019-09-23 16:44:03 +0200308 * should at least preserve or fill by zeroes the values of
309 * x1-x3.
Sandrine Bailleuxc5d315e2019-01-07 10:44:32 +0100310 */
311 const smc_ret_values ret3 = { 0, 0x44444444, 0x55555555, 0x66666666 };
312 const bool check[4] = { false, true, true, true };
Imre Kis1c97f942019-09-23 16:44:03 +0200313 const bool allow_zeros[4] = { false, true, true, true };
314
315 FAIL_IF(!smc_check_match(&args3, &ret3, check, allow_zeros));
Sandrine Bailleuxc5d315e2019-01-07 10:44:32 +0100316 } else {
317 const smc_ret_values ret3
318 = { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666 };
319 FAIL_IF(!smc_check_eq(&args3, &ret3));
320 }
Sandrine Bailleux3f556eb2018-11-16 14:00:40 +0100321
322 return TEST_RESULT_SUCCESS;
323}
324