blob: 9538fabf206b66cb962990bdd320c01d3fc8477a [file] [log] [blame]
Javier Almansa Sobrino4389c342024-04-10 12:12:13 +01001/*
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
21static bool lpa2_enabled;
22
23/*
24 * Helper function to perform any system register initialization
25 * needed for the tests.
26 */
27static void s2tt_test_helpers_arch_init(bool lpa2_en)
28{
29 unsigned int retval __unused;
30 uint64_t id_aa64mmfr0_el0 = INPLACE(ID_AA64MMFR0_EL1_TGRAN4_2,
31 ID_AA64MMFR0_EL1_TGRAN4_2_TGRAN4);
32
33 /*
34 * Enable the platform. We don't need support for several CPUs
35 * on this testsuite, so keep it disabled for simplicity.
36 */
37 test_helpers_rmm_start(false);
38
39 /*
40 * Reset the sysreg state so that we can setup
41 * custom values for the tests
42 */
43 host_util_zero_sysregs_and_cbs();
44
45 /* Setup id_aa64mmfr0_el1 */
46 if (lpa2_en == true) {
47 id_aa64mmfr0_el0 |= INPLACE(ID_AA64MMFR0_EL1_PARANGE, 6UL) |
48 INPLACE(ID_AA64MMFR0_EL1_TGRAN4,
49 ID_AA64MMFR0_EL1_TGRAN4_LPA2);
50 } else {
51 id_aa64mmfr0_el0 |= INPLACE(ID_AA64MMFR0_EL1_PARANGE, 5UL) |
52 INPLACE(ID_AA64MMFR0_EL1_TGRAN4,
53 ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED);
54 }
55 lpa2_enabled = lpa2_en;
56
57 retval = host_util_set_default_sysreg_cb("id_aa64mmfr0_el1",
58 id_aa64mmfr0_el0);
59
60 assert(retval == 0);
61
62 /* Make sure current cpu id is 0 (primary processor) */
63 host_util_set_cpuid(0U);
64
65 test_helpers_expect_assert_fail(false);
66}
67
68void s2tt_test_helpers_setup(bool lpa2)
69{
70 test_helpers_init();
71 s2tt_test_helpers_arch_init(lpa2);
72}
73
74unsigned long s2tt_test_helpers_oa_mask(long level)
75{
76 assert(level >= s2tt_test_helpers_min_table_lvl());
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
86unsigned long s2tt_test_helpers_s2tte_oa_mask(void)
87{
88 unsigned long mask = s2tt_test_helpers_oa_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
99unsigned long s2tt_test_helpers_s2tte_to_pa(unsigned long s2tte, long level)
100{
101 unsigned long pa = s2tte & s2tt_test_helpers_oa_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
111unsigned long s2tt_test_helpers_pa_to_s2tte(unsigned long pa, long level)
112{
113 unsigned long s2tte;
114
115 pa &= s2tt_test_helpers_oa_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
127unsigned long s2tt_test_helpers_gen_pa(long level, bool aligned)
128{
129 unsigned int levels, effective_lvl, lsb;
130 unsigned long pa;
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() - 1L);
138 assert(level <= S2TT_TEST_HELPERS_MAX_LVL);
139
140 /*
141 * There is a corner case If 'level' < s2tt_test_helpers_min_table_lvl()
142 * (e.g. we want to use the generated address to add a table at the
143 * minimum possible level). In this case, set the MSB bits of the
144 * address, corresponding to the first level table index to '0', as
145 * we can only have a table at the minimum level.
146 *
147 * In order to do that, force 'level' to
148 * s2tt_test_helpers_min_table_lvl()
149 */
150
151 effective_lvl = (level < s2tt_test_helpers_min_table_lvl()) ?
152 (unsigned int)s2tt_test_helpers_min_table_lvl() :
153 (unsigned int)level;
154
155 levels = S2TT_TEST_HELPERS_MAX_LVL - effective_lvl;
156 lsb = GRANULE_SHIFT + (levels * S2TTE_STRIDE);
157
158 do {
159 pa = test_helpers_get_rand_in_range((1UL << lsb), ULONG_MAX);
160 } while (pa == 0UL);
161
162 if (aligned == true) {
163 /*
164 * There is a corner case If 'level' < s2tt_test_helpers_min_table_lvl()
165 * for an aligned address (e.g. we want to use the generated
166 * address to add a table at the minimum possible level).
167 * In this case, just return address 0.
168 */
169 if (level < s2tt_test_helpers_min_table_lvl()) {
170 pa = 0UL;
171 } else {
172 pa &= s2tt_test_helpers_oa_mask(level);
173 }
174 }
175
176 return pa;
177}
178
179unsigned long s2tt_test_helpers_s2tte_to_attrs(unsigned long tte, bool ns)
180{
181 unsigned long attrs_mask;
182
183 if (ns == true) {
184 attrs_mask = S2TTE_NS_ATTR_RMM | S2TT_DESC_TYPE_MASK;
185 attrs_mask |= (is_feat_lpa2_4k_2_present() == true) ?
186 S2TTE_NS_ATTR_LPA2_MASK :
187 S2TTE_NS_ATTR_MASK;
188 } else {
189 attrs_mask = ((is_feat_lpa2_4k_2_present() == true) ?
190 S2TTE_ATTRS_LPA2_MASK :
191 S2TTE_ATTRS_MASK) | S2TT_DESC_TYPE_MASK;
192 }
193
194 return tte & attrs_mask;
195}
196
197unsigned long s2tt_test_helpers_gen_ns_attrs(bool host, bool reserved)
198{
199 unsigned long attrs;
200 bool done;
201
202 if (host == true) {
203 /* Generate a random set of attributes coming from the host */
204 do {
205 bool inv_attrs;
206
207 attrs = test_helpers_get_rand_in_range(0UL, ULONG_MAX);
208
209 attrs &= (is_feat_lpa2_4k_2_present() == true) ?
210 S2TTE_NS_ATTR_LPA2_MASK :
211 S2TTE_NS_ATTR_MASK;
212
213 /* Find out if we are done or not */
214 inv_attrs = ((attrs & S2TTE_MEMATTR_MASK) ==
215 S2TTE_MEMATTR_FWB_RESERVED);
216
217 if (is_feat_lpa2_4k_2_present() == false) {
218 inv_attrs |= ((attrs & S2TTE_SH_MASK) !=
219 S2TTE_SH_IS);
220 }
221 done = (reserved == inv_attrs);
222 } while (!done);
223 } else {
224 /* Setup the NS TTE attributes that don't come from the host */
225 attrs = S2TTE_NS_ATTR_RMM;
226 }
227
228 return attrs;
229}
230
231unsigned long s2tt_test_helpers_gen_attrs(bool invalid, long level)
232{
233 unsigned long attrs = (is_feat_lpa2_4k_2_present() == true) ?
234 S2TTE_ATTRS_LPA2 : S2TTE_ATTRS;
235
236 if (invalid == true) {
237 return attrs | S2TT_TEST_INVALID_DESC;
238 }
239
240 return ((level == S2TT_TEST_HELPERS_MAX_LVL) ?
241 S2TT_TEST_PAGE_DESC : S2TT_TEST_BLOCK_DESC) | attrs;
242}
243
244long s2tt_test_helpers_min_table_lvl(void)
245{
246 if (is_feat_lpa2_4k_2_present() == true) {
247 return S2TT_TEST_HELPERS_MIN_LVL_LPA2;
248 }
249
250 return S2TT_TEST_HELPERS_MIN_LVL;
251}
252
253long s2tt_test_helpers_min_block_lvl(void)
254{
255 return S2TT_MIN_BLOCK_LEVEL;
256}
257
258unsigned long s2tt_test_helpers_get_entry_va_space_size(long level)
259{
260 assert(level >= s2tt_test_helpers_min_table_lvl());
261 assert(level <= S2TT_TEST_HELPERS_MAX_LVL);
262
263 unsigned long levels = S2TT_TEST_HELPERS_MAX_LVL - level;
264
265 return 1UL << (GRANULE_SHIFT + (S2TTE_STRIDE * levels));
266}
267
268unsigned long s2tt_test_helpers_get_idx_from_addr(unsigned long addr,
269 long level)
270{
271 assert(level >= s2tt_test_helpers_min_table_lvl());
272 assert(level <= S2TT_TEST_HELPERS_MAX_LVL);
273 assert((addr & ~((1UL << arch_feat_get_pa_width()) - 1UL)) == 0UL);
274
275 unsigned int levels = (unsigned int)(S2TT_TEST_HELPERS_MAX_LVL - level);
276 unsigned int lsb = GRANULE_SHIFT + (levels * S2TTE_STRIDE);
277
278 return (addr >> lsb) & ((1UL << S2TTE_STRIDE) - 1UL);
279}
280
281bool s2tt_test_helpers_lpa2_enabled(void)
282{
283 return lpa2_enabled;
284}
285
286unsigned long s2tt_test_create_assigned(const struct s2tt_context *s2tt_ctx,
287 unsigned long pa, long level,
288 unsigned long ripas)
289{
290 if (ripas == S2TTE_INVALID_RIPAS_EMPTY) {
291 return s2tte_create_assigned_empty(s2tt_ctx, pa, level);
292 } else if (ripas == S2TTE_INVALID_RIPAS_DESTROYED) {
293 return s2tte_create_assigned_destroyed(s2tt_ctx, pa, level);
294 } else if (ripas == S2TTE_INVALID_RIPAS_RAM) {
295 return s2tte_create_assigned_ram(s2tt_ctx, pa, level);
296 }
297
298 return s2tte_create_assigned_ns(s2tt_ctx, pa, level);
299}
300
301unsigned long s2tt_test_create_unassigned(const struct s2tt_context *s2tt_ctx,
302 unsigned long ripas)
303{
304 if (ripas == S2TTE_INVALID_RIPAS_EMPTY) {
305 return s2tte_create_unassigned_empty(s2tt_ctx);
306 } else if (ripas == S2TTE_INVALID_RIPAS_DESTROYED) {
307 return s2tte_create_unassigned_destroyed(s2tt_ctx);
308 } else if (ripas == S2TTE_INVALID_RIPAS_RAM) {
309 return s2tte_create_unassigned_ram(s2tt_ctx);
310 }
311
312 return s2tte_create_unassigned_ns(s2tt_ctx);
313}