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