blob: 3ba0e13d3259603c86c2597b78b59c83db1b8cec [file] [log] [blame]
Soby Mathewb4c6df42022-11-09 11:13:29 +00001/*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
6#include <arch_helpers.h>
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00007#include <assert.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +00008#include <bitmap.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +00009#include <granule.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000010#include <ripas.h>
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010011#include <s2tt.h>
12#include <s2tt_pvt_defs.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000013#include <smc.h>
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +000014#include <stdbool.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000015#include <stddef.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000016
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +000017/*
18 * Return a mask for the IPA field on a S2TTE
19 */
20static unsigned long s2tte_lvl_mask(long level, bool lpa2)
21{
22 assert(level <= S2TT_PAGE_LEVEL);
23 assert(level >= S2TT_MIN_STARTING_LEVEL_LPA2);
24
25 unsigned long mask;
26 unsigned long levels = (unsigned long)(S2TT_PAGE_LEVEL - level);
27 unsigned long lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
28
29 mask = BIT_MASK_ULL((S2TTE_OA_BITS - 1U), lsb);
30
31 if (lpa2 == true) {
32 mask |= (MASK(LPA2_S2TTE_51_50) | MASK(LPA2_OA_49_48));
33 }
34
35 return mask;
36}
37
38/*
39 * Extracts the PA mapped by an S2TTE, aligned to a given level.
40 */
41static unsigned long s2tte_to_pa(unsigned long s2tte, long level, bool lpa2)
42{
43 unsigned long pa = s2tte & s2tte_lvl_mask(level, lpa2);
44
45 if (lpa2 == true) {
46 pa &= ~MASK(LPA2_S2TTE_51_50);
47 pa |= INPLACE(LPA2_OA_51_50, EXTRACT(LPA2_S2TTE_51_50, s2tte));
48 }
49
50 return pa;
51}
Soby Mathewb4c6df42022-11-09 11:13:29 +000052
53/*
54 * Invalidates S2 TLB entries from [ipa, ipa + size] region tagged with `vmid`.
55 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +000056static void stage2_tlbi_ipa(const struct s2tt_context *s2_ctx,
Soby Mathewb4c6df42022-11-09 11:13:29 +000057 unsigned long ipa,
58 unsigned long size)
59{
60 /*
61 * Notes:
62 *
63 * - This follows the description provided in the Arm ARM on
64 * "Invalidation of TLB entries from stage 2 translations".
65 *
66 * - @TODO: Provide additional information to this primitive so that
67 * we can utilize:
68 * - The TTL level hint, see FEAT_TTL,
69 * - Final level lookup only invalidation,
70 * - Address range invalidation.
71 */
72
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010073 assert(s2_ctx != NULL);
74
Soby Mathewb4c6df42022-11-09 11:13:29 +000075 /*
76 * Save the current content of vttb_el2.
77 */
78 unsigned long old_vttbr_el2 = read_vttbr_el2();
79
80 /*
81 * Make 'vmid' the `current vmid`. Note that the tlbi instructions
82 * bellow target the TLB entries that match the `current vmid`.
83 */
84 write_vttbr_el2(INPLACE(VTTBR_EL2_VMID, s2_ctx->vmid));
85 isb();
86
87 /*
88 * Invalidate entries in S2 TLB caches that
89 * match both `ipa` & the `current vmid`.
90 */
91 while (size != 0UL) {
92 tlbiipas2e1is(ipa >> 12);
93 size -= GRANULE_SIZE;
94 ipa += GRANULE_SIZE;
95 }
96 dsb(ish);
97
98 /*
99 * The architecture does not require TLB invalidation by IPA to affect
100 * combined Stage-1 + Stage-2 TLBs. Therefore we must invalidate all of
101 * Stage-1 (tagged with the `current vmid`) after invalidating Stage-2.
102 */
103 tlbivmalle1is();
104 dsb(ish);
105 isb();
106
107 /*
108 * Restore the old content of vttb_el2.
109 */
110 write_vttbr_el2(old_vttbr_el2);
111 isb();
112}
113
114/*
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000115 * Returns true if s2tte has 'output address' field, namely, if it is one of:
116 * - assigned_empty
117 * - assigned_ram
118 * - assigned_ns
119 * - assigned_destroyed
120 * - table
121 */
122static bool s2tte_has_pa(const struct s2tt_context *s2_ctx,
123 unsigned long s2tte, long level)
124{
125 unsigned long desc_type = s2tte & S2TT_DESC_TYPE_MASK;
126
127 return ((desc_type != S2TTE_INVALID) || /* block, page or table */
128 s2tte_is_assigned_empty(s2_ctx, s2tte, level) ||
129 s2tte_is_assigned_destroyed(s2_ctx, s2tte, level));
130}
131
132/*
133 * Creates a TTE containing only the PA.
134 * This function expects 'pa' to be aligned and bounded.
135 */
136static unsigned long pa_to_s2tte(unsigned long pa, bool lpa2)
137{
138 unsigned long tte = pa;
139
140 if (lpa2 == true) {
141 tte &= ~MASK(LPA2_OA_51_50);
142 tte |= INPLACE(LPA2_S2TTE_51_50, EXTRACT(LPA2_OA_51_50, pa));
143 }
144
145 return tte;
146}
147
148/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000149 * Invalidate S2 TLB entries with "addr" IPA.
150 * Call this function after:
151 * 1. A L3 page desc has been removed.
152 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000153void s2tt_invalidate_page(const struct s2tt_context *s2_ctx, unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000154{
155 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
156}
157
158/*
159 * Invalidate S2 TLB entries with "addr" IPA.
160 * Call this function after:
161 * 1. A L2 block desc has been removed, or
162 * 2a. A L2 table desc has been removed, where
163 * 2b. All S2TTEs in L3 table that the L2 table desc was pointed to were invalid.
164 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000165void s2tt_invalidate_block(const struct s2tt_context *s2_ctx, unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000166{
167 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
168}
169
170/*
171 * Invalidate S2 TLB entries with "addr" IPA.
172 * Call this function after:
173 * 1a. A L2 table desc has been removed, where
174 * 1b. Some S2TTEs in the table that the L2 table desc was pointed to were valid.
175 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000176void s2tt_invalidate_pages_in_block(const struct s2tt_context *s2_ctx,
177 unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000178{
179 stage2_tlbi_ipa(s2_ctx, addr, BLOCK_L2_SIZE);
180}
181
182/*
183 * Return the index of the entry describing @addr in the translation table at
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000184 * level @level. This only works for non-concatenated page tables, so should
Soby Mathewb4c6df42022-11-09 11:13:29 +0000185 * not be called to get the index for the starting level.
186 *
187 * See the library pseudocode
188 * aarch64/translation/vmsa_addrcalc/AArch64.TTEntryAddress on which this is
189 * modeled.
190 */
191static unsigned long s2_addr_to_idx(unsigned long addr, long level)
192{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100193 unsigned int levels, lsb;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000194 unsigned int s2tte_stride = (level < S2TT_MIN_STARTING_LEVEL) ?
195 S2TTE_STRIDE_LM1 : S2TTE_STRIDE;
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100196
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100197 levels = (unsigned int)(S2TT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100198 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000199
200 addr >>= lsb;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000201 addr &= (1UL << s2tte_stride) - 1UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000202 return addr;
203}
204
205/*
206 * Return the index of the entry describing @addr in the translation table
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000207 * starting level. This may return an index >= S2TTES_PER_S2TT when the
Soby Mathewb4c6df42022-11-09 11:13:29 +0000208 * combination of @start_level and @ipa_bits implies concatenated
209 * stage 2 tables.
210 *
211 * See the library pseudocode
212 * aarch64/translation/vmsa_addrcalc/AArch64.S2SLTTEntryAddress on which
213 * this is modeled.
214 */
215static unsigned long s2_sl_addr_to_idx(unsigned long addr, int start_level,
216 unsigned long ipa_bits)
217{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100218 unsigned int levels, lsb;
219
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100220 levels = (unsigned int)(S2TT_PAGE_LEVEL - start_level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100221 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000222
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000223 addr &= ((1UL << ipa_bits) - 1UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000224 addr >>= lsb;
225 return addr;
226}
227
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000228static bool entry_is_table(unsigned long entry)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000229{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100230 return ((entry & S2TT_DESC_TYPE_MASK) == S2TTE_L012_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000231}
232
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000233static unsigned long table_get_entry(const struct s2tt_context *s2_ctx,
234 struct granule *g_tbl,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100235 unsigned long idx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000236{
237 unsigned long *table, entry;
238
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000239 (void)s2_ctx;
240
Soby Mathewb4c6df42022-11-09 11:13:29 +0000241 table = granule_map(g_tbl, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100242 assert(table != NULL);
243
Soby Mathewb4c6df42022-11-09 11:13:29 +0000244 entry = s2tte_read(&table[idx]);
245 buffer_unmap(table);
246
247 return entry;
248}
249
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000250#define table_entry_to_phys(tte, lpa2) \
251 s2tte_to_pa(tte, S2TT_PAGE_LEVEL, lpa2)
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100252
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000253static struct granule *find_next_level_idx(const struct s2tt_context *s2_ctx,
254 struct granule *g_tbl,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100255 unsigned long idx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000256{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000257 assert(s2_ctx != NULL);
258
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000259 const unsigned long entry = table_get_entry(s2_ctx, g_tbl, idx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000260
261 if (!entry_is_table(entry)) {
262 return NULL;
263 }
264
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000265 return addr_to_granule(table_entry_to_phys(entry, s2_ctx->enable_lpa2));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000266}
267
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000268static struct granule *find_lock_next_level(const struct s2tt_context *s2_ctx,
269 struct granule *g_tbl,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100270 unsigned long map_addr,
271 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000272{
273 const unsigned long idx = s2_addr_to_idx(map_addr, level);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000274 struct granule *g = find_next_level_idx(s2_ctx, g_tbl, idx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000275
276 if (g != NULL) {
277 granule_lock(g, GRANULE_STATE_RTT);
278 }
279
280 return g;
281}
282
283/*
284 * Walk an RTT until level @level using @map_addr.
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000285 * @g_root is the root (level 0/-1) table and must be locked before the call.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000286 * @start_level is the initial lookup level used for the stage 2 translation
287 * tables which may depend on the configuration of the realm, factoring in the
288 * IPA size of the realm and the desired starting level (within the limits
289 * defined by the Armv8 VMSA including options for stage 2 table concatenation).
290 * The function uses hand-over-hand locking to avoid race conditions and allow
291 * concurrent access to RTT tree which is not part of the current walk; when a
292 * next level table is reached it is locked before releasing previously locked
293 * table.
294 * The walk stops when either:
295 * - The entry found is a leaf entry (not an RTT Table entry), or
296 * - Level @level is reached.
297 *
298 * On return:
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100299 * - s2tt_walk::last_level is the last level that has been reached by the walk.
300 * - s2tt_walk.g_llt points to the TABLE granule at level @s2tt_walk::level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000301 * The granule is locked.
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000302 * - s2tt_walk::index is the entry index at s2tt_walk.g_llt for @map_addr.i
303 *
304 * NOTE: This function expects that the root table on the s2 context is
305 * already locked.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000306 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000307void s2tt_walk_lock_unlock(const struct s2tt_context *s2_ctx,
308 unsigned long map_addr,
309 long level,
310 struct s2tt_walk *wi)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000311{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000312 struct granule *g_tbls[NR_RTT_LEVELS_LPA2] = { (struct granule *)NULL };
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000313 struct granule *g_root;
314 unsigned long sl_idx, ipa_bits;
315 int i, start_level, last_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000316
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000317 assert(s2_ctx != NULL);
318
319 start_level = s2_ctx->s2_starting_level;
320 ipa_bits = s2_ctx->ipa_bits;
321
Soby Mathewb4c6df42022-11-09 11:13:29 +0000322 assert(level >= start_level);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100323 assert(level <= S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000324 assert(map_addr < (1UL << ipa_bits));
325 assert(wi != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000326
327 g_root = s2_ctx->g_rtt;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000328
329 /* Handle concatenated starting level (SL) tables */
330 sl_idx = s2_sl_addr_to_idx(map_addr, start_level, ipa_bits);
331 if (sl_idx >= S2TTES_PER_S2TT) {
AlexeiFedorov4faab852023-08-30 15:06:49 +0100332 unsigned int tt_num = (unsigned int)(sl_idx >> S2TTE_STRIDE);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100333 struct granule *g_concat_root;
334
335 assert(tt_num < S2TTE_MAX_CONCAT_TABLES);
336
337 g_concat_root = (struct granule *)((uintptr_t)g_root +
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000338 (tt_num * sizeof(struct granule)));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000339
340 granule_lock(g_concat_root, GRANULE_STATE_RTT);
341 granule_unlock(g_root);
342 g_root = g_concat_root;
343 }
344
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000345 /* 'start_level' can be '-1', so add 1 when used as an index */
346 g_tbls[start_level + 1] = g_root;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000347 for (i = start_level; i < level; i++) {
348 /*
349 * Lock next RTT level. Correct locking order is guaranteed
350 * because reference is obtained from a locked granule
351 * (previous level). Also, hand-over-hand locking/unlocking is
352 * used to avoid race conditions.
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000353 *
354 * Note that as 'start_level' can be -1, we add '1' to the
355 * index 'i' to compensate for the negative value when we
356 * use it to index then 'g_tbls' list.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000357 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000358 g_tbls[i + 1 + 1] = find_lock_next_level(s2_ctx, g_tbls[i + 1],
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000359 map_addr, i);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000360 if (g_tbls[i + 1 + 1] == NULL) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000361 last_level = i;
362 goto out;
363 }
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000364 granule_unlock(g_tbls[i + 1]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000365 }
366
AlexeiFedorov4faab852023-08-30 15:06:49 +0100367 last_level = (int)level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000368out:
369 wi->last_level = last_level;
AlexeiFedorove956db32024-04-04 14:36:21 +0100370 /* coverity[deref_overflow:SUPPRESS] */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000371 wi->g_llt = g_tbls[last_level + 1];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000372 wi->index = s2_addr_to_idx(map_addr, last_level);
373}
374
375/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100376 * Creates an unassigned_empty s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000377 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000378unsigned long s2tte_create_unassigned_empty(const struct s2tt_context *s2_ctx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000379{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000380 (void)s2_ctx;
381
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100382 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100383}
384
385/*
386 * Creates an unassigned_ram s2tte.
387 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000388unsigned long s2tte_create_unassigned_ram(const struct s2tt_context *s2_ctx)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100389{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000390 (void)s2_ctx;
391
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100392 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000393}
394
395/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100396 * Creates an unassigned_destroyed s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000397 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000398unsigned long s2tte_create_unassigned_destroyed(const struct s2tt_context *s2_ctx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000399{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000400 (void)s2_ctx;
401
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100402 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
403}
404
405/*
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100406 * Creates an unassigned_ns s2tte.
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100407 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000408unsigned long s2tte_create_unassigned_ns(const struct s2tt_context *s2_ctx)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100409{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000410 (void)s2_ctx;
411
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100412 return (S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED |
413 S2TTE_INVALID_UNPROTECTED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000414}
415
416/*
417 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100418 * RIPAS=@s2tte_ripas, at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000419 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000420static unsigned long s2tte_create_assigned(const struct s2tt_context *s2_ctx,
421 unsigned long pa, long level,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100422 unsigned long s2tte_ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000423{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100424 assert(level >= S2TT_MIN_BLOCK_LEVEL);
425 assert(level <= S2TT_PAGE_LEVEL);
426 assert(s2tte_ripas <= S2TTE_INVALID_RIPAS_DESTROYED);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000427 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000428 assert(s2_ctx != NULL);
429
430 unsigned long tte = pa_to_s2tte(pa, s2_ctx->enable_lpa2);
431 unsigned long s2tte_page, s2tte_block;
432
433 if (s2_ctx->enable_lpa2 == true) {
434 s2tte_page = S2TTE_PAGE_LPA2;
435 s2tte_block = S2TTE_BLOCK_LPA2;
436 } else {
437 s2tte_page = S2TTE_PAGE;
438 s2tte_block = S2TTE_BLOCK;
439 }
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100440
441 if (s2tte_ripas == S2TTE_INVALID_RIPAS_RAM) {
442 if (level == S2TT_PAGE_LEVEL) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000443 return (tte | s2tte_page);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100444 }
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000445 return (tte | s2tte_block);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100446 }
447
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000448 return (tte | S2TTE_INVALID_HIPAS_ASSIGNED | s2tte_ripas);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100449}
450
451/*
452 * Creates and invalid s2tte with output address @pa, HIPAS=ASSIGNED and
453 * RIPAS=DESTROYED at level @level.
454 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000455unsigned long s2tte_create_assigned_destroyed(const struct s2tt_context *s2_ctx,
456 unsigned long pa, long level)
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100457{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000458 return s2tte_create_assigned(s2_ctx, pa, level,
459 S2TTE_INVALID_RIPAS_DESTROYED);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100460}
461
462/*
463 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
464 * RIPAS=EMPTY at level @level.
465 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000466unsigned long s2tte_create_assigned_empty(const struct s2tt_context *s2_ctx,
467 unsigned long pa, long level)
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100468{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000469 return s2tte_create_assigned(s2_ctx, pa, level,
470 S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000471}
472
473/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100474 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000475 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000476unsigned long s2tte_create_assigned_ram(const struct s2tt_context *s2_ctx,
477 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000478{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000479 return s2tte_create_assigned(s2_ctx, pa, level,
480 S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000481}
482
483/*
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100484 * Creates an assigned s2tte with output address @pa and the same
485 * RIPAS as passed on @s2tte.
486 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000487unsigned long s2tte_create_assigned_unchanged(const struct s2tt_context *s2_ctx,
488 unsigned long s2tte,
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100489 unsigned long pa,
490 long level)
491{
492 unsigned long current_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
493
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000494 return s2tte_create_assigned(s2_ctx, pa, level, current_ripas);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000495}
496
497/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100498 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000499 *
500 * The following S2 TTE fields are provided through @s2tte argument:
501 * - The physical address
502 * - MemAttr
503 * - S2AP
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000504 * - Shareability (when FEAT_LPA2 is disabled)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000505 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000506unsigned long s2tte_create_assigned_ns(const struct s2tt_context *s2_ctx,
507 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000508{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000509 /*
510 * We just mask out the DESC_TYPE below. The Shareability bits
511 * without FEAT_LPA2 are at the same position as OA bits [51:50]
512 * with FEAT_LPA2 enabled, so we don't need to cater for that
513 * separately.
514 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100515 unsigned long new_s2tte = s2tte & ~S2TT_DESC_TYPE_MASK;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100516
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000517 (void)s2_ctx;
518
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100519 assert(level >= S2TT_MIN_BLOCK_LEVEL);
520 assert(level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100521
522 if (level == S2TT_PAGE_LEVEL) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100523 return (new_s2tte | S2TTE_PAGE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000524 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100525 return (new_s2tte | S2TTE_BLOCK_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000526}
527
528/*
529 * Validate the portion of NS S2TTE that is provided by the host.
530 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000531bool host_ns_s2tte_is_valid(const struct s2tt_context *s2_ctx,
532 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000533{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100534
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000535 bool lpa2;
536 unsigned long mask;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100537
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000538 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100539 assert(level >= S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000540
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000541 lpa2 = s2_ctx->enable_lpa2;
542
543 mask = s2tte_lvl_mask(level, lpa2);
544 if (lpa2 == true) {
545 mask |= S2TTE_NS_ATTR_LPA2_MASK;
546 } else {
547 mask |= S2TTE_NS_ATTR_MASK;
548
549 /* Only SH_IS is allowed */
550 if ((s2tte & S2TTE_SH_MASK) != S2TTE_SH_IS) {
551 return false;
552 }
553 }
554
Soby Mathewb4c6df42022-11-09 11:13:29 +0000555 /*
556 * Test that all fields that are not controlled by the host are zero
557 * and that the output address is correctly aligned. Note that
558 * the host is permitted to map any physical address outside PAR.
559 */
560 if ((s2tte & ~mask) != 0UL) {
561 return false;
562 }
563
564 /*
565 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
566 */
567 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
568 return false;
569 }
570
571 /*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000572 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
573 */
574 return true;
575}
576
577/*
578 * Returns the portion of NS S2TTE that is set by the host.
579 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000580unsigned long host_ns_s2tte(const struct s2tt_context *s2_ctx,
581 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000582{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000583 assert(s2_ctx != NULL);
584
585 unsigned long mask = s2tte_lvl_mask(level, s2_ctx->enable_lpa2);
586
587 mask |= (s2_ctx->enable_lpa2 == true) ? S2TTE_NS_ATTR_LPA2_MASK :
588 S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000589
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100590 assert(level >= S2TT_MIN_BLOCK_LEVEL);
591
Soby Mathewb4c6df42022-11-09 11:13:29 +0000592 return (s2tte & mask);
593}
594
595/*
596 * Creates a table s2tte at level @level with output address @pa.
597 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000598unsigned long s2tte_create_table(const struct s2tt_context *s2_ctx,
599 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000600{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000601 __unused int min_starting_level;
602
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100603 (void)level;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000604
605 assert(s2_ctx != NULL);
606 min_starting_level = (s2_ctx->enable_lpa2 == true) ?
607 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100608
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100609 assert(level < S2TT_PAGE_LEVEL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000610 assert(level >= min_starting_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000611 assert(GRANULE_ALIGNED(pa));
612
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000613 return (pa_to_s2tte(pa, s2_ctx->enable_lpa2) | S2TTE_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000614}
615
616/*
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100617 * Returns true if s2tte has defined ripas value, namely if it is one of:
618 * - unassigned_empty
619 * - unassigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100620 * - unassigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100621 * - assigned_empty
622 * - assigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100623 * - assigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100624 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000625bool s2tte_has_ripas(const struct s2tt_context *s2_ctx,
626 unsigned long s2tte, long level)
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100627{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000628 return (((s2tte & S2TTE_NS) == 0UL) && !s2tte_is_table(s2_ctx,
629 s2tte, level));
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100630}
631
632/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000633 * Returns true if @s2tte has HIPAS=@hipas.
634 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100635static inline bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000636{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100637 unsigned long desc_type = s2tte & S2TT_DESC_TYPE_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000638 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
639
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100640 return ((desc_type == S2TTE_INVALID) && (invalid_desc_hipas == hipas));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000641}
642
643/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100644 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000645 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100646static inline bool s2tte_has_unassigned_ripas(unsigned long s2tte,
647 unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000648{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100649 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
650 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
651}
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100652
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100653/*
654 * Returns true if @s2tte has HIPAS=ASSIGNED and RIPAS=@ripas.
655 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100656static inline bool s2tte_has_assigned_ripas(unsigned long s2tte,
657 unsigned long ripas)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100658{
659 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
660 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100661}
662
663/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100664 * Returns true if @s2tte has HIPAS=UNASSIGNED.
665 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000666bool s2tte_is_unassigned(const struct s2tt_context *s2_ctx, unsigned long s2tte)
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100667{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000668 (void)s2_ctx;
669
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100670 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED);
671}
672
673/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100674 * Returns true if @s2tte is an unassigned_empty.
675 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000676bool s2tte_is_unassigned_empty(const struct s2tt_context *s2_ctx,
677 unsigned long s2tte)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100678{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000679 (void)s2_ctx;
680
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100681 return (((s2tte & S2TTE_NS) == 0UL) &&
682 s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100683}
684
685/*
686 * Returns true if @s2tte is an unassigned_ram.
687 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000688bool s2tte_is_unassigned_ram(const struct s2tt_context *s2_ctx,
689 unsigned long s2tte)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100690{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000691 (void)s2_ctx;
692
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100693 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
694}
695
696/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100697 * Returns true if @s2tte is unassigned_ns.
698 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000699bool s2tte_is_unassigned_ns(const struct s2tt_context *s2_ctx,
700 unsigned long s2tte)
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100701{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000702 (void)s2_ctx;
703
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100704 return (((s2tte & S2TTE_NS) != 0UL) &&
705 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000706}
707
708/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100709 * Returns true if @s2tte has RIPAS=DESTROYED.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000710 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000711bool s2tte_is_unassigned_destroyed(const struct s2tt_context *s2_ctx,
712 unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000713{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000714 (void)s2_ctx;
715
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100716 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
717}
718
719/*
720 * Returns true if @s2tte is an assigned_destroyed.
721 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000722bool s2tte_is_assigned_destroyed(const struct s2tt_context *s2_ctx,
723 unsigned long s2tte, long level)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100724{
725 (void)level;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000726 (void)s2_ctx;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100727
728 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000729}
730
731/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100732 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000733 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000734bool s2tte_is_assigned_empty(const struct s2tt_context *s2_ctx,
735 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000736{
737 (void)level;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000738 (void)s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000739
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100740 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000741}
742
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000743static bool s2tte_check(const struct s2tt_context *s2_ctx, unsigned long s2tte,
744 long level, unsigned long ns)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000745{
746 unsigned long desc_type;
747
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000748 (void)s2_ctx;
749
Soby Mathewb4c6df42022-11-09 11:13:29 +0000750 if ((s2tte & S2TTE_NS) != ns) {
751 return false;
752 }
753
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100754 desc_type = s2tte & S2TT_DESC_TYPE_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000755
Shruti Gupta3105c3f2024-02-26 14:06:11 +0000756 /* Only pages at L3 and valid blocks at L2 and L1 allowed */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100757 if (((level == S2TT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
Shruti Gupta3105c3f2024-02-26 14:06:11 +0000758 ((level >= S2TT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK))) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000759 return true;
760 }
761
762 return false;
763}
764
765/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100766 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000767 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000768bool s2tte_is_assigned_ram(const struct s2tt_context *s2_ctx,
769 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000770{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000771 return s2tte_check(s2_ctx, s2tte, level, 0UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000772}
773
774/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100775 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000776 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000777bool s2tte_is_assigned_ns(const struct s2tt_context *s2_ctx,
778 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000779{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000780 return s2tte_check(s2_ctx, s2tte, level, S2TTE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000781}
782
783/*
784 * Returns true if @s2tte is a table at level @level.
785 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000786bool s2tte_is_table(const struct s2tt_context *s2_ctx, unsigned long s2tte,
787 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000788{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000789 (void)s2_ctx;
790
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100791 return ((level < S2TT_PAGE_LEVEL) &&
792 ((s2tte & S2TT_DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000793}
794
795/*
796 * Returns RIPAS of @s2tte.
797 *
798 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100799 * The s2tte, if valid, should correspond to RIPAS_RAM.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000800 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000801enum ripas s2tte_get_ripas(const struct s2tt_context *s2_ctx, unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000802{
803 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
804
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000805 (void)s2_ctx;
806
Soby Mathewb4c6df42022-11-09 11:13:29 +0000807 /*
808 * If valid s2tte descriptor is passed, then ensure S2AP[0]
809 * bit is 1 (S2AP is set to RW for lower EL), which corresponds
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100810 * to RIPAS_RAM (bits[6:5] = b01) on a valid descriptor.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000811 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100812 assert(((s2tte & S2TT_DESC_TYPE_MASK) == S2TTE_INVALID) ||
813 (desc_ripas == S2TTE_INVALID_RIPAS_RAM));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000814
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100815 assert(EXTRACT(S2TTE_INVALID_HIPAS, s2tte) <=
816 EXTRACT(S2TTE_INVALID_HIPAS, S2TTE_INVALID_HIPAS_ASSIGNED));
817
818 desc_ripas = desc_ripas >> S2TTE_INVALID_RIPAS_SHIFT;
819
820 assert(desc_ripas <= (unsigned int)RIPAS_DESTROYED);
821
822 return (enum ripas)desc_ripas;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000823}
824
825/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100826 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000827 *
828 * The granule is populated before it is made a table,
829 * hence, don't use s2tte_write for access.
830 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000831void s2tt_init_unassigned_empty(const struct s2tt_context *s2_ctx,
832 unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000833{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100834 assert(s2tt != NULL);
835
836 unsigned long s2tte =
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000837 s2tte_create_unassigned_empty(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100838
Soby Mathewb4c6df42022-11-09 11:13:29 +0000839 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100840 s2tt[i] = s2tte;
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100841 }
842
843 dsb(ish);
844}
845
846/*
847 * Populates @s2tt with unassigned_ram s2ttes.
848 *
849 * The granule is populated before it is made a table,
850 * hence, don't use s2tte_write for access.
851 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000852void s2tt_init_unassigned_ram(const struct s2tt_context *s2_ctx,
853 unsigned long *s2tt)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100854{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100855 assert(s2tt != NULL);
856
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000857 unsigned long s2tte = s2tte_create_unassigned_ram(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100858
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100859 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100860 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000861 }
862
863 dsb(ish);
864}
865
866/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100867 * Populates @s2tt with unassigned_ns s2ttes.
868 *
869 * The granule is populated before it is made a table,
870 * hence, don't use s2tte_write for access.
871 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000872void s2tt_init_unassigned_ns(const struct s2tt_context *s2_ctx,
873 unsigned long *s2tt)
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100874{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100875 assert(s2tt != NULL);
876
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000877 unsigned long s2tte = s2tte_create_unassigned_ns(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100878
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100879 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100880 s2tt[i] = s2tte;
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100881 }
882
883 dsb(ish);
884}
885
886/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000887 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
888 *
889 * The granule is populated before it is made a table,
890 * hence, don't use s2tte_write for access.
891 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000892void s2tt_init_unassigned_destroyed(const struct s2tt_context *s2_ctx,
893 unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000894{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100895 assert(s2tt != NULL);
896
897 unsigned long s2tte =
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000898 s2tte_create_unassigned_destroyed(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100899
Soby Mathewb4c6df42022-11-09 11:13:29 +0000900 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100901 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000902 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100903 dsb(ish);
904}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000905
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100906/*
907 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
908 * contiguous memory block starting at @pa, and mapped at level @level.
909 *
910 * The granule is populated before it is made a table,
911 * hence, don't use s2tte_write for access.
912 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000913void s2tt_init_assigned_destroyed(const struct s2tt_context *s2_ctx,
914 unsigned long *s2tt, unsigned long pa,
915 long level)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100916{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000917 assert(s2tt != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100918 assert(level >= S2TT_MIN_BLOCK_LEVEL);
919 assert(level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000920 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100921
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100922 const unsigned long map_size = s2tte_map_size(level);
923
924 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000925 s2tt[i] = s2tte_create_assigned_destroyed(s2_ctx, pa, level);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100926 pa += map_size;
927 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000928 dsb(ish);
929}
930
Soby Mathewb4c6df42022-11-09 11:13:29 +0000931/*
932 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
933 * contiguous memory block starting at @pa, and mapped at level @level.
934 *
935 * The granule is populated before it is made a table,
936 * hence, don't use s2tte_write for access.
937 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000938void s2tt_init_assigned_empty(const struct s2tt_context *s2_ctx,
939 unsigned long *s2tt, unsigned long pa,
940 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000941{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100942 assert(level >= S2TT_MIN_BLOCK_LEVEL);
943 assert(level <= S2TT_PAGE_LEVEL);
944 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000945 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100946
Soby Mathewb4c6df42022-11-09 11:13:29 +0000947 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000948
AlexeiFedorov3a739332023-04-13 13:54:04 +0100949 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000950 s2tt[i] = s2tte_create_assigned_empty(s2_ctx, pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000951 pa += map_size;
952 }
953 dsb(ish);
954}
955
956/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100957 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000958 * contiguous memory block starting at @pa, and mapped at level @level.
959 *
960 * The granule is populated before it is made a table,
961 * hence, don't use s2tte_write for access.
962 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000963void s2tt_init_assigned_ram(const struct s2tt_context *s2_ctx,
964 unsigned long *s2tt, unsigned long pa,
965 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000966{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100967 assert(level >= S2TT_MIN_BLOCK_LEVEL);
968 assert(level <= S2TT_PAGE_LEVEL);
969 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000970 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100971
Soby Mathewb4c6df42022-11-09 11:13:29 +0000972 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000973
AlexeiFedorov3a739332023-04-13 13:54:04 +0100974 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000975 s2tt[i] = s2tte_create_assigned_ram(s2_ctx, pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000976 pa += map_size;
977 }
978 dsb(ish);
979}
980
981/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100982 * Populates @s2tt with NS attributes @attrs that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000983 * contiguous memory block starting at @pa, and mapped at level @level.
984 *
985 * The granule is populated before it is made a table,
986 * hence, don't use s2tte_write for access.
987 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000988void s2tt_init_assigned_ns(const struct s2tt_context *s2_ctx,
989 unsigned long *s2tt, unsigned long attrs,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100990 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000991{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100992 assert(level >= S2TT_MIN_BLOCK_LEVEL);
993 assert(level <= S2TT_PAGE_LEVEL);
994 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000995 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100996
Soby Mathewb4c6df42022-11-09 11:13:29 +0000997 const unsigned long map_size = s2tte_map_size(level);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000998 unsigned long ns_attr_host_mask = (s2_ctx->enable_lpa2 == true) ?
999 S2TTE_NS_ATTR_LPA2_MASK : S2TTE_NS_ATTR_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001000
AlexeiFedorov3a739332023-04-13 13:54:04 +01001001 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001002 unsigned long s2tte = attrs & ns_attr_host_mask;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001003
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001004 s2tt[i] = s2tte_create_assigned_ns(s2_ctx,
1005 s2tte | pa_to_s2tte(pa, s2_ctx->enable_lpa2),
1006 level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001007 pa += map_size;
1008 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001009
Soby Mathewb4c6df42022-11-09 11:13:29 +00001010 dsb(ish);
1011}
1012
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001013/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001014 * Returns true if s2tte is a live RTTE entry. i.e.,
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001015 * HIPAS is ASSIGNED.
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001016 *
1017 * NOTE: For now, only the RTTE with PA are live.
1018 * This could change with EXPORT/IMPORT support.
1019 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001020static bool s2tte_is_live(const struct s2tt_context *s2_ctx,
1021 unsigned long s2tte, long level)
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001022{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001023 return s2tte_has_pa(s2_ctx, s2tte, level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001024}
1025
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001026/* Returns physical address of a S2TTE */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001027unsigned long s2tte_pa(const struct s2tt_context *s2_ctx, unsigned long s2tte,
1028 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001029{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001030 bool lpa2;
1031 unsigned long pa;
1032 __unused long min_starting_level;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001033
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001034 assert(s2_ctx != NULL);
1035
1036 min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1037 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1038 assert(level >= min_starting_level);
1039 assert(level <= S2TT_PAGE_LEVEL);
1040 assert(s2tte_has_pa(s2_ctx, s2tte, level));
1041
1042 lpa2 = s2_ctx->enable_lpa2;
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001043
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001044 if (s2tte_is_table(s2_ctx, s2tte, level)) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001045 pa = table_entry_to_phys(s2tte, lpa2);
1046 } else {
1047 pa = s2tte_to_pa(s2tte, level, lpa2);
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001048 }
1049
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001050 return pa;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001051}
1052
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001053bool s2tte_is_addr_lvl_aligned(const struct s2tt_context *s2_ctx,
1054 unsigned long addr, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001055{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001056 assert(s2_ctx != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001057
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001058 __unused long min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1059 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1060 unsigned long levels = (unsigned long)(S2TT_PAGE_LEVEL - level);
1061 unsigned long lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
1062 unsigned long s2tte_oa_bits = (s2_ctx->enable_lpa2 == true) ?
1063 S2TTE_OA_BITS_LPA2 : S2TTE_OA_BITS;
1064
1065 assert(level <= S2TT_PAGE_LEVEL);
1066 assert(level >= min_starting_level);
1067
1068 return (addr == (addr & BIT_MASK_ULL((s2tte_oa_bits - 1U), lsb)));
Soby Mathewb4c6df42022-11-09 11:13:29 +00001069}
1070
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001071typedef bool (*s2tte_type_checker)(const struct s2tt_context *s2_ctx,
1072 unsigned long s2tte);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001073
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001074static bool table_is_uniform_block(const struct s2tt_context *s2_ctx,
1075 unsigned long *table,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001076 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001077{
AlexeiFedorov377d81f2023-04-14 16:29:12 +01001078 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
1079 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001080
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001081 if (!s2tte_is_x(s2_ctx, s2tte)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001082 return false;
1083 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001084 }
1085
1086 return true;
1087}
1088
1089/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001090 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001091 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001092bool s2tt_is_unassigned_empty_block(const struct s2tt_context *s2_ctx,
1093 unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001094{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001095 assert(table != NULL);
1096
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001097 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001098}
1099
1100/*
1101 * Returns true if all s2ttes in @table are unassigned_ram.
1102 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001103bool s2tt_is_unassigned_ram_block(const struct s2tt_context *s2_ctx,
1104 unsigned long *table)
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001105{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001106 assert(table != NULL);
1107
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001108 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001109}
1110
1111/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001112 * Returns true if all s2ttes in @table are unassigned_ns
1113 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001114bool s2tt_is_unassigned_ns_block(const struct s2tt_context *s2_ctx,
1115 unsigned long *table)
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001116{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001117 assert(table != NULL);
1118
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001119 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001120}
1121
1122/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001123 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +00001124 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001125bool s2tt_is_unassigned_destroyed_block(const struct s2tt_context *s2_ctx,
1126 unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001127{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001128 assert(table != NULL);
1129
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001130 return table_is_uniform_block(s2_ctx, table,
1131 s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001132}
1133
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001134typedef bool (*s2tte_type_level_checker)(const struct s2tt_context *s2_ctx,
1135 unsigned long s2tte, long level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001136
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001137static bool table_maps_block(const struct s2tt_context *s2_ctx,
1138 unsigned long *table,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001139 long level,
1140 s2tte_type_level_checker s2tte_is_x,
1141 bool check_ns_attrs)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001142{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001143 assert(table != NULL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001144 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001145
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001146 unsigned long base_pa, ns_attr_host_mask;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001147 unsigned long map_size = s2tte_map_size(level);
1148 unsigned long s2tte = s2tte_read(&table[0]);
Javier Almansa Sobrino8865ec32024-04-18 10:50:03 +01001149 unsigned long s2tt_ns_attrs;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001150 unsigned int i;
1151
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001152 if (!s2tte_is_x(s2_ctx, s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001153 return false;
1154 }
1155
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001156 base_pa = s2tte_pa(s2_ctx, s2tte, level);
1157 if (!s2tte_is_addr_lvl_aligned(s2_ctx, base_pa, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001158 return false;
1159 }
1160
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001161 ns_attr_host_mask = (s2_ctx->enable_lpa2 == true) ?
1162 S2TTE_NS_ATTR_LPA2_MASK : S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrino8865ec32024-04-18 10:50:03 +01001163 s2tt_ns_attrs = s2tte & ns_attr_host_mask;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001164
Soby Mathewb4c6df42022-11-09 11:13:29 +00001165 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
1166 unsigned long expected_pa = base_pa + (i * map_size);
1167
1168 s2tte = s2tte_read(&table[i]);
1169
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001170 if (!s2tte_is_x(s2_ctx, s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001171 return false;
1172 }
1173
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001174 if (s2tte_pa(s2_ctx, s2tte, level) != expected_pa) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001175 return false;
1176 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001177
1178 if (check_ns_attrs) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001179 unsigned long ns_attrs =
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001180 s2tte & ns_attr_host_mask;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001181
1182 /*
1183 * We match all the attributes in the S2TTE
1184 * except for the AF bit.
1185 */
Javier Almansa Sobrino8865ec32024-04-18 10:50:03 +01001186 if (s2tt_ns_attrs != ns_attrs) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001187 return false;
1188 }
1189 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001190 }
1191
1192 return true;
1193}
1194
1195/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001196 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +00001197 * and refer to a contiguous block of granules aligned to @level - 1.
1198 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001199bool s2tt_maps_assigned_empty_block(const struct s2tt_context *s2_ctx,
1200 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001201{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001202 return table_maps_block(s2_ctx, table, level,
1203 s2tte_is_assigned_empty, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001204}
1205
1206/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001207 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001208 * refer to a contiguous block of granules aligned to @level - 1.
1209 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001210bool s2tt_maps_assigned_ram_block(const struct s2tt_context *s2_ctx,
1211 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001212{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001213 return table_maps_block(s2_ctx, table, level,
1214 s2tte_is_assigned_ram, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001215}
1216
1217/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001218 * Returns true if
1219 * - all s2ttes in @table are assigned_ns s2ttes and
1220 * - they refer to a contiguous block of granules aligned to @level - 1 and
1221 * - all the s2tte attributes in @table controlled by the host are identical
AlexeiFedorov3a739332023-04-13 13:54:04 +01001222 *
1223 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001224 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001225bool s2tt_maps_assigned_ns_block(const struct s2tt_context *s2_ctx,
1226 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001227{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001228 return table_maps_block(s2_ctx, table, level,
1229 s2tte_is_assigned_ns, true);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001230}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001231
1232/*
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001233 * Returns true if all s2ttes are assigned_destroyed and
1234 * refer to a contiguous block of granules aligned to @level - 1.
1235 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001236bool s2tt_maps_assigned_destroyed_block(const struct s2tt_context *s2_ctx,
1237 unsigned long *table, long level)
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001238{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001239 return table_maps_block(s2_ctx, table, level,
1240 s2tte_is_assigned_destroyed, false);
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001241}
1242
1243/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001244 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001245 * skip the non-live entries (i.e., HIPAS=UNASSIGNED).
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001246 * In other words, the scanning stops when a live RTTE is encountered or we
1247 * reach the end of this RTT.
1248 *
1249 * For now an RTTE can be considered non-live if it doesn't have a PA.
1250 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1251 * in the RTTE.
1252 *
1253 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1254 * with RMI_ERROR_RTT).
1255 *
1256 * Returns:
1257 * - If the entry @wi.index is live, returns @addr.
1258 * - If none of the entries in the @s2tt are "live", returns the address of the
1259 * first entry in the next table.
1260 * - Otherwise, the address of the first live entry in @s2tt
1261 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001262unsigned long s2tt_skip_non_live_entries(const struct s2tt_context *s2_ctx,
1263 unsigned long addr,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001264 unsigned long *table,
1265 const struct s2tt_walk *wi)
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001266{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001267 assert(table != NULL);
1268 assert(wi != NULL);
1269 assert(wi->index <= S2TTES_PER_S2TT);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001270 assert(wi->last_level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001271 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001272
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001273 unsigned long i, index = wi->index;
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001274 long level = wi->last_level;
1275 unsigned long map_size;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001276 __unused long min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1277 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1278
1279 assert(wi->last_level >= min_starting_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001280
1281 /*
1282 * If the entry for the map_addr is live,
1283 * return @addr.
1284 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001285 if (s2tte_is_live(s2_ctx, s2tte_read(&table[index]), level)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001286 return addr;
1287 }
1288
1289 /*
1290 * Align the address DOWN to the map_size, as expected for the @level,
1291 * so that we can compute the correct address by using the index.
1292 */
1293 map_size = s2tte_map_size(level);
1294 addr &= ~(map_size - 1UL);
1295
1296 /* Skip the "index" */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001297 for (i = index + 1UL; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001298 unsigned long s2tte = s2tte_read(&table[i]);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001299
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001300 if (s2tte_is_live(s2_ctx, s2tte, level)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001301 break;
1302 }
1303 }
1304
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001305 return (addr + ((i - index) * map_size));
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001306}