blob: 901b4481211bfce99f1c59eb5c2b2e46f165c49d [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>
10#include <string.h>
11#include <tftf_lib.h>
12#include <tsp.h>
13#include <utils_def.h>
14
15/* An invalid SMC function number. */
16#define INVALID_FN 0x666
17
18/* PSCI version returned by TF-A. */
19static const uint32_t psci_version = PSCI_VERSION(PSCI_MAJOR_VER,
20 PSCI_MINOR_VER);
21
22/* UUID of the standard service in TF-A. */
23static const smc_ret_values std_svc_uuid = {
24 0x108d905b, 0x47e8f863, 0xfbc02dae, 0xe2f64156
25};
26
27/*
28 * Build an SMC function ID given its type (fast/yielding), calling convention,
29 * owning entity number and function number.
30 */
31static inline uint32_t make_smc_fid(unsigned int type, unsigned int cc,
32 unsigned int oen, unsigned int func_num)
33{
34 return (type << FUNCID_TYPE_SHIFT) | (cc << FUNCID_CC_SHIFT)
35 | (oen << FUNCID_OEN_SHIFT) | (func_num << FUNCID_NUM_SHIFT);
36}
37
38/* Exit the test if the specified condition holds true. */
39#define FAIL_IF(_cond) \
40 do { \
41 if ((_cond)) { \
42 return TEST_RESULT_FAIL; \
43 } \
44 } while (0)
45
46/*
47 * Send an SMC with the specified arguments.
48 * Check that the values it returns match the expected ones. If not, write an
49 * error message in the test report.
50 */
51static bool smc_check_eq(const smc_args *args, const smc_ret_values *expect)
52{
53 smc_ret_values ret = tftf_smc(args);
54
55 if (memcmp(&ret, expect, sizeof(smc_ret_values)) == 0) {
56 return true;
57 } else {
58 tftf_testcase_printf(
59 "Got {0x%lx,0x%lx,0x%lx,0x%lx}, expected {0x%lx,0x%lx,0x%lx,0x%lx}.\n",
60 ret.ret0, ret.ret1, ret.ret2, ret.ret3,
61 expect->ret0, expect->ret1, expect->ret2, expect->ret3);
62 return false;
63 }
64}
65
66/* Exercise SMC32 calling convention with fast SMC calls. */
67test_result_t smc32_fast(void)
68{
69 /* Valid Fast SMC32 using all 4 return values. */
70 const smc_args args1 = { .fid = SMC_STD_SVC_UID };
71 FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
72
73 /* Invalid Fast SMC32. */
74 const smc_args args2 = {
75 make_smc_fid(SMC_TYPE_FAST, SMC_32, OEN_ARM_START, INVALID_FN),
76 0x11111111, 0x22222222, 0x33333333 };
77 const smc_ret_values ret2
78 = { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
79 FAIL_IF(!smc_check_eq(&args2, &ret2));
80
81 /* Valid Fast SMC32 using 1 return value. */
82 const smc_args args3
83 = { SMC_PSCI_VERSION, 0x44444444, 0x55555555, 0x66666666 };
84 const smc_ret_values ret3
85 = { psci_version, 0x44444444, 0x55555555, 0x66666666 };
86 FAIL_IF(!smc_check_eq(&args3, &ret3));
87
88 return TEST_RESULT_SUCCESS;
89}
90
91/* Exercise SMC64 calling convention with yielding SMC calls. */
92test_result_t smc64_yielding(void)
93{
94 /* Valid Fast SMC32 using all 4 return values. */
95 const smc_args args1 = { .fid = SMC_STD_SVC_UID };
96 FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
97
98 /* Invalid function number, SMC64 Yielding. */
99 const smc_args args2 = {
100 make_smc_fid(SMC_TYPE_STD, SMC_64, OEN_ARM_START, INVALID_FN),
101 0x11111111, 0x22222222, 0x33333333 };
102 const smc_ret_values ret2
103 = { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
104 FAIL_IF(!smc_check_eq(&args2, &ret2));
105
106 /*
107 * Valid[1] yielding SMC64 using 1 return value.
108 *
109 * [1] Valid from the point of view of the generic SMC handler if the
110 * TSPd is present. In this case, the SMC request gets passed to the
111 * TSPd handler code. The fact that it then gets rejected by the TSPd is
112 * irrelevant here, as we are not trying to test the TSPd nor the TSP.
113 *
114 * In other cases (i.e. AArch64 BL31 with no TSPd support or AArch32
115 * SP_MIN) this test should still fail in the same way, although it
116 * doesn't exercise the same code path in TF-A.
117 */
118 const smc_args args3 = {
119 make_smc_fid(SMC_TYPE_STD, SMC_64, OEN_TOS_START, INVALID_FN),
120 0x44444444, 0x55555555, 0x66666666 };
121 const smc_ret_values ret3
122 = { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666 };
123 FAIL_IF(!smc_check_eq(&args3, &ret3));
124
125 return TEST_RESULT_SUCCESS;
126}
127
128#ifdef AARCH32
129static test_result_t smc64_fast_caller32(void)
130{
131 /* Valid Fast SMC32 using all 4 return values. */
132 smc_args args1 = { .fid = SMC_STD_SVC_UID };
133 FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
134
135 /* Invalid SMC function number, Fast SMC64. */
136 const smc_args args2 = {
137 make_smc_fid(SMC_TYPE_FAST, SMC_64, OEN_ARM_START, INVALID_FN),
138 0x11111111, 0x22222222, 0x33333333 };
139 const smc_ret_values ret2
140 = { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
141 FAIL_IF(!smc_check_eq(&args2, &ret2));
142
143 /*
144 * Valid SMC function number, Fast SMC64. However, 32-bit callers are
145 * forbidden to use the SMC64 calling convention.
146 */
147 const smc_args args3 = { SMC_PSCI_AFFINITY_INFO_AARCH64,
148 0x44444444, 0x55555555, 0x66666666 };
149 const smc_ret_values ret3
150 = { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666 };
151 FAIL_IF(!smc_check_eq(&args3, &ret3));
152
153 return TEST_RESULT_SUCCESS;
154}
155#else
156static test_result_t smc64_fast_caller64(void)
157{
158 /* Valid Fast SMC32 using all 4 return values. */
159 smc_args args1 = { .fid = SMC_STD_SVC_UID };
160 FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
161
162 /* Invalid function number, Fast SMC64. */
163 const smc_args args2 = {
164 make_smc_fid(SMC_TYPE_FAST, SMC_64, OEN_ARM_START, INVALID_FN),
165 0x11111111, 0x22222222, 0x33333333 };
166 const smc_ret_values ret2
167 = { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
168 FAIL_IF(!smc_check_eq(&args2, &ret2));
169
170 /* Valid Fast SMC64 using 1 return value. */
171 const smc_args args3 = { SMC_PSCI_AFFINITY_INFO_AARCH64,
172 0x44444444, 0x55555555, 0x66666666 };
173 const smc_ret_values ret3
174 = { PSCI_E_INVALID_PARAMS, 0x44444444, 0x55555555, 0x66666666 };
175 FAIL_IF(!smc_check_eq(&args3, &ret3));
176
177 return TEST_RESULT_SUCCESS;
178}
179#endif /* AARCH32 */
180
181/* Exercise SMC64 calling convention with fast SMC calls. */
182test_result_t smc64_fast(void)
183{
184#ifdef AARCH32
185 return smc64_fast_caller32();
186#else
187 return smc64_fast_caller64();
188#endif
189}
190
191/* Exercise SMC32 calling convention with yielding SMC calls. */
192test_result_t smc32_yielding(void)
193{
194 /* Valid Fast SMC32 using all 4 return values. */
195 const smc_args args1 = { .fid = SMC_STD_SVC_UID };
196 FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
197
198 /* Invalid function number, SMC32 Yielding. */
199 const smc_args args2 = {
200 make_smc_fid(SMC_TYPE_STD, SMC_32, OEN_ARM_START, INVALID_FN),
201 0x11111111, 0x22222222, 0x33333333 };
202 const smc_ret_values ret2
203 = { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
204 FAIL_IF(!smc_check_eq(&args2, &ret2));
205
206 /*
207 * Valid[1] yielding SMC32 using 1 return value.
208 *
209 * [1] Valid from the point of view of the generic SMC handler if a
210 * secure payload dispatcher handling this SMC range is present. In this
211 * case, the SMC request gets passed to the dispatcher handler code. The
212 * fact that it then gets rejected by the dispatcher is irrelevant here,
213 * as we are not trying to test the dispatcher nor the secure payload.
214 *
215 * In BL31 has no SPD support, this test should still fail in the same
216 * way, although it doesn't exercise the same code path in TF-A.
217 */
218 const smc_args args3 = {
219 make_smc_fid(SMC_TYPE_STD, SMC_32, OEN_TOS_START, INVALID_FN),
220 0x44444444, 0x55555555, 0x66666666 };
221 const smc_ret_values ret3
222 = { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666 };
223 FAIL_IF(!smc_check_eq(&args3, &ret3));
224
225 return TEST_RESULT_SUCCESS;
226}
227