1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
6 #include <arch_features.h>
7 #include <assert.h>
8 #include <errno.h>
9 #include <host_utils.h>
10 #include <limits.h>
11 #include <ripas.h>
12 #include <s2tt.h>
13 #include <s2tt_pvt_defs.h>
14 #include <s2tt_test_helpers.h>
15 #include <stdbool.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <test_helpers.h>
19 #include <utils_def.h>
20 #include <xlat_defs.h>
21
22 static bool lpa2_enabled;
23
24 /*
25 * Helper function to perform any system register initialization
26 * needed for the tests.
27 */
s2tt_test_helpers_arch_init(bool lpa2_en)28 static void s2tt_test_helpers_arch_init(bool lpa2_en)
29 {
30 unsigned int retval __unused;
31 uint64_t id_aa64mmfr0_el0 = INPLACE(ID_AA64MMFR0_EL1_TGRAN4_2,
32 ID_AA64MMFR0_EL1_TGRAN4_2_TGRAN4);
33
34 /*
35 * Enable the platform. We don't need support for several CPUs
36 * on this testsuite, so keep it disabled for simplicity.
37 */
38 test_helpers_rmm_start(false);
39
40 /*
41 * Reset the sysreg state so that we can setup
42 * custom values for the tests
43 */
44 host_util_zero_sysregs_and_cbs();
45
46 /* Setup id_aa64mmfr0_el1 */
47 if (lpa2_en == true) {
48 id_aa64mmfr0_el0 |= INPLACE(ID_AA64MMFR0_EL1_PARANGE, 6UL) |
49 INPLACE(ID_AA64MMFR0_EL1_TGRAN4,
50 ID_AA64MMFR0_EL1_TGRAN4_LPA2);
51 } else {
52 id_aa64mmfr0_el0 |= INPLACE(ID_AA64MMFR0_EL1_PARANGE, 5UL) |
53 INPLACE(ID_AA64MMFR0_EL1_TGRAN4,
54 ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED);
55 }
56 lpa2_enabled = lpa2_en;
57
58 retval = host_util_set_default_sysreg_cb("id_aa64mmfr0_el1",
59 id_aa64mmfr0_el0);
60
61 assert(retval == 0);
62
63 /* Make sure current cpu id is 0 (primary processor) */
64 host_util_set_cpuid(0U);
65
66 test_helpers_expect_assert_fail(false);
67 }
68
s2tt_test_helpers_setup(bool lpa2)69 void s2tt_test_helpers_setup(bool lpa2)
70 {
71 test_helpers_init();
72 s2tt_test_helpers_arch_init(lpa2);
73 }
74
s2tt_test_helpers_lvl_mask(long level)75 unsigned long s2tt_test_helpers_lvl_mask(long level)
76 {
77 assert(level <= S2TT_TEST_HELPERS_MAX_LVL);
78
79 unsigned int levels = (unsigned int)(S2TT_TEST_HELPERS_MAX_LVL - level);
80 unsigned int lsb = GRANULE_SHIFT + (levels * S2TTE_STRIDE);
81 unsigned int msb = arch_feat_get_pa_width() - 1U;
82
83 return BIT_MASK_ULL(msb, lsb);
84 }
85
s2tt_test_helpers_s2tte_oa_mask(void)86 unsigned long s2tt_test_helpers_s2tte_oa_mask(void)
87 {
88 unsigned long mask = s2tt_test_helpers_lvl_mask(
89 S2TT_TEST_HELPERS_MAX_LVL);
90
91 if (is_feat_lpa2_4k_2_present() == true) {
92 mask |= MASK(S2TT_TEST_MSB);
93 mask &= ~MASK(S2TT_TEST_OA_MSB);
94 }
95
96 return mask;
97 }
98
s2tt_test_helpers_s2tte_to_pa(unsigned long s2tte,long level)99 unsigned long s2tt_test_helpers_s2tte_to_pa(unsigned long s2tte, long level)
100 {
101 unsigned long pa = s2tte & s2tt_test_helpers_lvl_mask(level);
102
103 if (is_feat_lpa2_4k_2_present() == true) {
104 pa &= ~MASK(S2TT_TEST_MSB);
105 pa |= INPLACE(S2TT_TEST_OA_MSB, EXTRACT(S2TT_TEST_MSB, s2tte));
106 }
107
108 return pa;
109 }
110
s2tt_test_helpers_pa_to_s2tte(unsigned long pa,long level)111 unsigned long s2tt_test_helpers_pa_to_s2tte(unsigned long pa, long level)
112 {
113 unsigned long s2tte;
114
115 pa &= s2tt_test_helpers_lvl_mask(level);
116
117 if (is_feat_lpa2_4k_2_present() == true) {
118 s2tte = pa | INPLACE(S2TT_TEST_MSB, EXTRACT(S2TT_TEST_OA_MSB, pa));
119 s2tte &= ~MASK(S2TT_TEST_OA_MSB);
120 } else {
121 s2tte = pa;
122 }
123
124 return s2tte;
125 }
126
s2tt_test_helpers_gen_addr(long level,bool aligned)127 unsigned long s2tt_test_helpers_gen_addr(long level, bool aligned)
128 {
129 unsigned int levels, lsb;
130 unsigned long addr;
131
132 /*
133 * We allow to get addresses aligned to one level below the minimum
134 * so we can use that address to create a table @level starting
135 * at such address.
136 */
137 assert(level >= s2tt_test_helpers_min_table_lvl() - 1);
138 assert(level <= S2TT_TEST_HELPERS_MAX_LVL);
139
140 levels = S2TT_TEST_HELPERS_MAX_LVL - level;
141 lsb = GRANULE_SHIFT + (levels * S2TTE_STRIDE);
142
143 do {
144 unsigned int shift = (level <= S2TT_TEST_HELPERS_MIN_LVL_LPA2) ?
145 LM1_XLAT_ADDRESS_SHIFT : L0_XLAT_ADDRESS_SHIFT;
146
147 addr = test_helpers_get_rand_in_range((1UL << lsb), ULONG_MAX);
148 addr &= ((1UL << shift) - 1UL);
149 } while (addr == 0UL);
150
151 return aligned ? (addr & s2tt_test_helpers_lvl_mask(level)) : addr;
152 }
153
s2tt_test_helpers_s2tte_to_attrs(unsigned long tte,bool ns)154 unsigned long s2tt_test_helpers_s2tte_to_attrs(unsigned long tte, bool ns)
155 {
156 unsigned long attrs_mask;
157
158 if (ns) {
159 attrs_mask = S2TTE_NS_ATTR_RMM | S2TT_DESC_TYPE_MASK | S2TTE_NS_ATTR_MASK;
160 if (!is_feat_lpa2_4k_2_present()) {
161 attrs_mask |= S2TTE_SH_MASK;
162 }
163 } else {
164 attrs_mask = ((is_feat_lpa2_4k_2_present() == true) ?
165 S2TTE_ATTRS_LPA2_MASK :
166 S2TTE_ATTRS_MASK) | S2TT_DESC_TYPE_MASK;
167 }
168
169 return tte & attrs_mask;
170 }
171
s2tt_test_helpers_gen_ns_attrs(bool host,bool reserved)172 unsigned long s2tt_test_helpers_gen_ns_attrs(bool host, bool reserved)
173 {
174 unsigned long attrs;
175 bool done;
176
177 if (host == true) {
178 /* Generate a random set of attributes coming from the host */
179 do {
180 bool inv_attrs;
181
182 attrs = test_helpers_get_rand_in_range(0UL, ULONG_MAX);
183 attrs &= S2TTE_NS_ATTR_MASK;
184
185 /* Find out if we are done or not */
186 inv_attrs = ((attrs & S2TTE_MEMATTR_MASK) ==
187 S2TTE_MEMATTR_FWB_RESERVED);
188 done = (reserved == inv_attrs);
189 } while (!done);
190 } else {
191 /* Setup the NS TTE attributes that don't come from the host */
192 attrs = S2TTE_NS_ATTR_RMM;
193 }
194
195 return attrs;
196 }
197
s2tt_test_helpers_gen_attrs(bool invalid,long level)198 unsigned long s2tt_test_helpers_gen_attrs(bool invalid, long level)
199 {
200 unsigned long attrs = (is_feat_lpa2_4k_2_present() == true) ?
201 S2TTE_ATTRS_LPA2 : S2TTE_ATTRS;
202
203 if (invalid == true) {
204 return attrs | S2TT_TEST_INVALID_DESC;
205 }
206
207 return ((level == S2TT_TEST_HELPERS_MAX_LVL) ?
208 S2TT_TEST_PAGE_DESC : S2TT_TEST_BLOCK_DESC) | attrs;
209 }
210
s2tt_test_helpers_min_table_lvl(void)211 long s2tt_test_helpers_min_table_lvl(void)
212 {
213 if (is_feat_lpa2_4k_2_present() == true) {
214 return S2TT_TEST_HELPERS_MIN_LVL_LPA2;
215 }
216
217 return S2TT_TEST_HELPERS_MIN_LVL;
218 }
219
s2tt_test_helpers_min_block_lvl(void)220 long s2tt_test_helpers_min_block_lvl(void)
221 {
222 return S2TT_MIN_BLOCK_LEVEL;
223 }
224
s2tt_test_helpers_min_dev_block_lvl(void)225 long s2tt_test_helpers_min_dev_block_lvl(void)
226 {
227 return S2TT_MIN_DEV_BLOCK_LEVEL;
228 }
229
s2tt_test_helpers_get_entry_va_space_size(long level)230 unsigned long s2tt_test_helpers_get_entry_va_space_size(long level)
231 {
232 assert(level >= s2tt_test_helpers_min_table_lvl());
233 assert(level <= S2TT_TEST_HELPERS_MAX_LVL);
234
235 unsigned long levels = S2TT_TEST_HELPERS_MAX_LVL - level;
236
237 return 1UL << (GRANULE_SHIFT + (S2TTE_STRIDE * levels));
238 }
239
s2tt_test_helpers_get_idx_from_addr(unsigned long addr,long level)240 unsigned long s2tt_test_helpers_get_idx_from_addr(unsigned long addr,
241 long level)
242 {
243 assert(level >= s2tt_test_helpers_min_table_lvl());
244 assert(level <= S2TT_TEST_HELPERS_MAX_LVL);
245 assert((addr & ~((1UL << arch_feat_get_pa_width()) - 1UL)) == 0UL);
246
247 unsigned int levels = (unsigned int)(S2TT_TEST_HELPERS_MAX_LVL - level);
248 unsigned int lsb = GRANULE_SHIFT + (levels * S2TTE_STRIDE);
249
250 return (addr >> lsb) & ((1UL << S2TTE_STRIDE) - 1UL);
251 }
252
s2tt_test_helpers_lpa2_enabled(void)253 bool s2tt_test_helpers_lpa2_enabled(void)
254 {
255 return lpa2_enabled;
256 }
257
s2tt_test_create_assigned(const struct s2tt_context * s2tt_ctx,unsigned long pa,long level,unsigned long ripas)258 unsigned long s2tt_test_create_assigned(const struct s2tt_context *s2tt_ctx,
259 unsigned long pa, long level,
260 unsigned long ripas)
261 {
262 if (ripas == S2TTE_INVALID_RIPAS_EMPTY) {
263 return s2tte_create_assigned_empty(s2tt_ctx, pa, level);
264 } else if (ripas == S2TTE_INVALID_RIPAS_DESTROYED) {
265 return s2tte_create_assigned_destroyed(s2tt_ctx, pa, level);
266 } else if (ripas == S2TTE_INVALID_RIPAS_RAM) {
267 return s2tte_create_assigned_ram(s2tt_ctx, pa, level);
268 }
269
270 return s2tte_create_assigned_ns(s2tt_ctx, pa, level);
271 }
272
s2tt_test_create_assigned_dev_dev(const struct s2tt_context * s2tt_ctx,unsigned long pa,long level)273 unsigned long s2tt_test_create_assigned_dev_dev(const struct s2tt_context *s2tt_ctx,
274 unsigned long pa, long level)
275 {
276 unsigned long attr = S2TTE_TEST_DEV_ATTRS;
277
278 /* Add Shareability bits if FEAT_LPA2 is not enabled */
279 if (!s2tt_ctx->enable_lpa2) {
280 attr |= S2TTE_TEST_DEV_SH;
281 }
282 return s2tte_create_assigned_dev_dev(s2tt_ctx, (pa | attr), level);
283 }
284
s2tt_test_create_assigned_dev(const struct s2tt_context * s2tt_ctx,unsigned long pa,long level,unsigned long ripas)285 unsigned long s2tt_test_create_assigned_dev(const struct s2tt_context *s2tt_ctx,
286 unsigned long pa, long level,
287 unsigned long ripas)
288 {
289 if (ripas == S2TTE_INVALID_RIPAS_EMPTY) {
290 return s2tte_create_assigned_dev_empty(s2tt_ctx, pa, level);
291 } else if (ripas == S2TTE_INVALID_RIPAS_DESTROYED) {
292 return s2tte_create_assigned_dev_destroyed(s2tt_ctx, pa, level);
293 } else if (ripas == S2TTE_INVALID_RIPAS_DEV) {
294 return s2tt_test_create_assigned_dev_dev(s2tt_ctx, pa, level);
295 }
296
297 assert(false);
298 return 0UL;
299 }
300
s2tt_test_init_assigned_dev_dev(const struct s2tt_context * s2tt_ctx,unsigned long * s2tt,unsigned long pa,long level)301 void s2tt_test_init_assigned_dev_dev(const struct s2tt_context *s2tt_ctx,
302 unsigned long *s2tt, unsigned long pa,
303 long level)
304 {
305 unsigned long attr = S2TTE_TEST_DEV_ATTRS;
306
307 /* Add Shareability bits if FEAT_LPA2 is not enabled */
308 if (!s2tt_ctx->enable_lpa2) {
309 attr |= S2TTE_TEST_DEV_SH;
310 }
311
312 s2tt_init_assigned_dev_dev(s2tt_ctx, s2tt, (attr | pa), pa, level);
313 }
314
s2tt_test_create_unassigned(const struct s2tt_context * s2tt_ctx,unsigned long ripas)315 unsigned long s2tt_test_create_unassigned(const struct s2tt_context *s2tt_ctx,
316 unsigned long ripas)
317 {
318 if (ripas == S2TTE_INVALID_RIPAS_EMPTY) {
319 return s2tte_create_unassigned_empty(s2tt_ctx);
320 } else if (ripas == S2TTE_INVALID_RIPAS_DESTROYED) {
321 return s2tte_create_unassigned_destroyed(s2tt_ctx);
322 } else if (ripas == S2TTE_INVALID_RIPAS_RAM) {
323 return s2tte_create_unassigned_ram(s2tt_ctx);
324 }
325
326 return s2tte_create_unassigned_ns(s2tt_ctx);
327 }
328