blob: c5fda16582fcd7cbaba4162400b11860ac701be0 [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>
Soby Mathewb4c6df42022-11-09 11:13:29 +00007#include <bitmap.h>
8#include <buffer.h>
9#include <gic.h>
10#include <granule.h>
11#include <memory_alloc.h>
12#include <realm.h>
13#include <ripas.h>
14#include <smc.h>
15#include <status.h>
16#include <stddef.h>
17#include <string.h>
18#include <table.h>
19
20/*
21 * For prototyping we assume 4K pages
22 */
23#define BLOCK_L2_SIZE (GRANULE_SIZE * S2TTES_PER_S2TT)
24
25/*
26 * The maximum number of bits supported by the RMM for a stage 2 translation
27 * output address (including stage 2 table entries).
28 */
29#define S2TTE_OA_BITS 48
30
AlexeiFedorovc53b1f72023-07-04 15:37:03 +010031#define DESC_TYPE_MASK 3UL
32#define S2TTE_Lx_INVALID 0UL
33#define S2TTE_L012_BLOCK 1UL
34#define S2TTE_L012_TABLE 3UL
35#define S2TTE_L3_PAGE 3UL
Soby Mathewb4c6df42022-11-09 11:13:29 +000036
37/*
38 * The following constants for the mapping attributes (S2_TTE_MEMATTR_*)
39 * assume that HCR_EL2.FWB is set.
40 */
41#define S2TTE_MEMATTR_SHIFT 2
42#define S2TTE_MEMATTR_MASK (0x7UL << S2TTE_MEMATTR_SHIFT)
43#define S2TTE_MEMATTR_FWB_NORMAL_WB ((1UL << 4) | (2UL << 2))
44#define S2TTE_MEMATTR_FWB_RESERVED ((1UL << 4) | (0UL << 2))
45
46#define S2TTE_AP_SHIFT 6
47#define S2TTE_AP_MASK (3UL << S2TTE_AP_SHIFT)
48#define S2TTE_AP_RW (3UL << S2TTE_AP_SHIFT)
49
50#define S2TTE_SH_SHIFT 8
51#define S2TTE_SH_MASK (3UL << S2TTE_SH_SHIFT)
52#define S2TTE_SH_NS (0UL << S2TTE_SH_SHIFT)
53#define S2TTE_SH_RESERVED (1UL << S2TTE_SH_SHIFT)
54#define S2TTE_SH_OS (2UL << S2TTE_SH_SHIFT)
55#define S2TTE_SH_IS (3UL << S2TTE_SH_SHIFT) /* Inner Shareable */
56
57/*
58 * We set HCR_EL2.FWB So we set bit[4] to 1 and bits[3:2] to 2 and force
59 * everyting to be Normal Write-Back
60 */
61#define S2TTE_MEMATTR_FWB_NORMAL_WB ((1UL << 4) | (2UL << 2))
62#define S2TTE_AF (1UL << 10)
63#define S2TTE_XN (2UL << 53)
64#define S2TTE_NS (1UL << 55)
65
66#define S2TTE_ATTRS (S2TTE_MEMATTR_FWB_NORMAL_WB | S2TTE_AP_RW | \
67 S2TTE_SH_IS | S2TTE_AF)
68
69#define S2TTE_TABLE S2TTE_L012_TABLE
70#define S2TTE_BLOCK (S2TTE_ATTRS | S2TTE_L012_BLOCK)
71#define S2TTE_PAGE (S2TTE_ATTRS | S2TTE_L3_PAGE)
72#define S2TTE_BLOCK_NS (S2TTE_NS | S2TTE_XN | S2TTE_AF | S2TTE_L012_BLOCK)
73#define S2TTE_PAGE_NS (S2TTE_NS | S2TTE_XN | S2TTE_AF | S2TTE_L3_PAGE)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +010074#define S2TTE_INVALID S2TTE_Lx_INVALID
Soby Mathewb4c6df42022-11-09 11:13:29 +000075
76/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +010077 * The type of stage 2 translation table entry (s2tte) is defined by:
78 * 1. Table level where it resides
79 * 2. DESC_TYPE field[1:0]
AlexeiFedorovc53b1f72023-07-04 15:37:03 +010080 * 4. HIPAS field [4:2]
81 * 4. RIPAS field [6:5]
AlexeiFedorov5ceff352023-04-12 16:17:00 +010082 * 5. NS field [55]
Soby Mathewb4c6df42022-11-09 11:13:29 +000083 *
AlexeiFedorov63614ea2023-07-14 17:07:20 +010084 * ======================================================================================
85 * s2tte type level DESC_TYPE[1:0] HIPAS[4:2] RIPAS[6:5] NS OA alignment
86 * ======================================================================================
87 * unassigned_empty any invalid[0] unassigned[0] empty[0] 0 n/a
88 * --------------------------------------------------------------------------------------
89 * unassigned_ram any invalid[0] unassigned[0] ram[1] 0 n/a
90 * --------------------------------------------------------------------------------------
91 * unassigned_destroyed any invalid[0] unassigned[0] destroyed[2] 0 n/a
92 * --------------------------------------------------------------------------------------
93 * assigned_empty 2,3 invalid[0] assigned[1] empty[0] 0 to level
94 * --------------------------------------------------------------------------------------
95 * assigned_ram 3 page[3] n/a n/a 0 to level
96 * 2 block[1] n/a n/a 0 to level
97 * --------------------------------------------------------------------------------------
98 * assigned_destroyed any invalid[0] assigned[1] destroyed[2] 0 n/a
99 * ======================================================================================
100 * unassigned_ns any invalid[0] unassigned[0] n/a 1 n/a
101 * --------------------------------------------------------------------------------------
102 * assigned_ns 3 page[3] n/a n/a 1 to level
103 * 2 block[1] n/a n/a 1 to level
104 * ======================================================================================
105 * table <=2 table[3] n/a n/a n/a to 4K
106 * ======================================================================================
Soby Mathewb4c6df42022-11-09 11:13:29 +0000107 */
108
109#define S2TTE_INVALID_HIPAS_SHIFT 2
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100110#define S2TTE_INVALID_HIPAS_WIDTH 3
Soby Mathewb4c6df42022-11-09 11:13:29 +0000111#define S2TTE_INVALID_HIPAS_MASK MASK(S2TTE_INVALID_HIPAS)
112
113#define S2TTE_INVALID_HIPAS_UNASSIGNED (INPLACE(S2TTE_INVALID_HIPAS, 0))
114#define S2TTE_INVALID_HIPAS_ASSIGNED (INPLACE(S2TTE_INVALID_HIPAS, 1))
Soby Mathewb4c6df42022-11-09 11:13:29 +0000115
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100116#define S2TTE_INVALID_RIPAS_SHIFT 5
117#define S2TTE_INVALID_RIPAS_WIDTH 2
Soby Mathewb4c6df42022-11-09 11:13:29 +0000118#define S2TTE_INVALID_RIPAS_MASK MASK(S2TTE_INVALID_RIPAS)
119
120#define S2TTE_INVALID_RIPAS_EMPTY (INPLACE(S2TTE_INVALID_RIPAS, 0))
121#define S2TTE_INVALID_RIPAS_RAM (INPLACE(S2TTE_INVALID_RIPAS, 1))
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100122#define S2TTE_INVALID_RIPAS_DESTROYED (INPLACE(S2TTE_INVALID_RIPAS, 2))
Soby Mathewb4c6df42022-11-09 11:13:29 +0000123
Soby Mathewb4c6df42022-11-09 11:13:29 +0000124#define S2TTE_INVALID_UNPROTECTED 0x0UL
125
126#define NR_RTT_LEVELS 4
127
128/*
129 * Invalidates S2 TLB entries from [ipa, ipa + size] region tagged with `vmid`.
130 */
131static void stage2_tlbi_ipa(const struct realm_s2_context *s2_ctx,
132 unsigned long ipa,
133 unsigned long size)
134{
135 /*
136 * Notes:
137 *
138 * - This follows the description provided in the Arm ARM on
139 * "Invalidation of TLB entries from stage 2 translations".
140 *
141 * - @TODO: Provide additional information to this primitive so that
142 * we can utilize:
143 * - The TTL level hint, see FEAT_TTL,
144 * - Final level lookup only invalidation,
145 * - Address range invalidation.
146 */
147
148 /*
149 * Save the current content of vttb_el2.
150 */
151 unsigned long old_vttbr_el2 = read_vttbr_el2();
152
153 /*
154 * Make 'vmid' the `current vmid`. Note that the tlbi instructions
155 * bellow target the TLB entries that match the `current vmid`.
156 */
157 write_vttbr_el2(INPLACE(VTTBR_EL2_VMID, s2_ctx->vmid));
158 isb();
159
160 /*
161 * Invalidate entries in S2 TLB caches that
162 * match both `ipa` & the `current vmid`.
163 */
164 while (size != 0UL) {
165 tlbiipas2e1is(ipa >> 12);
166 size -= GRANULE_SIZE;
167 ipa += GRANULE_SIZE;
168 }
169 dsb(ish);
170
171 /*
172 * The architecture does not require TLB invalidation by IPA to affect
173 * combined Stage-1 + Stage-2 TLBs. Therefore we must invalidate all of
174 * Stage-1 (tagged with the `current vmid`) after invalidating Stage-2.
175 */
176 tlbivmalle1is();
177 dsb(ish);
178 isb();
179
180 /*
181 * Restore the old content of vttb_el2.
182 */
183 write_vttbr_el2(old_vttbr_el2);
184 isb();
185}
186
187/*
188 * Invalidate S2 TLB entries with "addr" IPA.
189 * Call this function after:
190 * 1. A L3 page desc has been removed.
191 */
192void invalidate_page(const struct realm_s2_context *s2_ctx, unsigned long addr)
193{
194 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
195}
196
197/*
198 * Invalidate S2 TLB entries with "addr" IPA.
199 * Call this function after:
200 * 1. A L2 block desc has been removed, or
201 * 2a. A L2 table desc has been removed, where
202 * 2b. All S2TTEs in L3 table that the L2 table desc was pointed to were invalid.
203 */
204void invalidate_block(const struct realm_s2_context *s2_ctx, unsigned long addr)
205{
206 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
207}
208
209/*
210 * Invalidate S2 TLB entries with "addr" IPA.
211 * Call this function after:
212 * 1a. A L2 table desc has been removed, where
213 * 1b. Some S2TTEs in the table that the L2 table desc was pointed to were valid.
214 */
215void invalidate_pages_in_block(const struct realm_s2_context *s2_ctx, unsigned long addr)
216{
217 stage2_tlbi_ipa(s2_ctx, addr, BLOCK_L2_SIZE);
218}
219
220/*
221 * Return the index of the entry describing @addr in the translation table at
222 * level @level. This only works for non-concatenated page tables, so should
223 * not be called to get the index for the starting level.
224 *
225 * See the library pseudocode
226 * aarch64/translation/vmsa_addrcalc/AArch64.TTEntryAddress on which this is
227 * modeled.
228 */
229static unsigned long s2_addr_to_idx(unsigned long addr, long level)
230{
231 int levels = RTT_PAGE_LEVEL - level;
232 int lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
233
234 addr >>= lsb;
235 addr &= (1UL << S2TTE_STRIDE) - 1;
236 return addr;
237}
238
239/*
240 * Return the index of the entry describing @addr in the translation table
241 * starting level. This may return an index >= S2TTES_PER_S2TT when the
242 * combination of @start_level and @ipa_bits implies concatenated
243 * stage 2 tables.
244 *
245 * See the library pseudocode
246 * aarch64/translation/vmsa_addrcalc/AArch64.S2SLTTEntryAddress on which
247 * this is modeled.
248 */
249static unsigned long s2_sl_addr_to_idx(unsigned long addr, int start_level,
250 unsigned long ipa_bits)
251{
252 int levels = RTT_PAGE_LEVEL - start_level;
253 int lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
254
255 addr &= (1UL << ipa_bits) - 1UL;
256 addr >>= lsb;
257 return addr;
258}
259
AlexeiFedorov14d47ae2023-07-19 15:26:50 +0100260unsigned long addr_level_mask(unsigned long addr, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000261{
262 int levels = RTT_PAGE_LEVEL - level;
263 unsigned int lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
264 unsigned int msb = S2TTE_OA_BITS - 1;
265
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100266 return (addr & BIT_MASK_ULL(msb, lsb));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000267}
268
269static inline unsigned long table_entry_to_phys(unsigned long entry)
270{
271 return addr_level_mask(entry, RTT_PAGE_LEVEL);
272}
273
274static inline bool entry_is_table(unsigned long entry)
275{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100276 return ((entry & DESC_TYPE_MASK) == S2TTE_L012_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000277}
278
279static unsigned long __table_get_entry(struct granule *g_tbl,
280 unsigned long idx)
281{
282 unsigned long *table, entry;
283
284 table = granule_map(g_tbl, SLOT_RTT);
285 entry = s2tte_read(&table[idx]);
286 buffer_unmap(table);
287
288 return entry;
289}
290
291static struct granule *__find_next_level_idx(struct granule *g_tbl,
292 unsigned long idx)
293{
294 const unsigned long entry = __table_get_entry(g_tbl, idx);
295
296 if (!entry_is_table(entry)) {
297 return NULL;
298 }
299
300 return addr_to_granule(table_entry_to_phys(entry));
301}
302
303static struct granule *__find_lock_next_level(struct granule *g_tbl,
304 unsigned long map_addr,
305 long level)
306{
307 const unsigned long idx = s2_addr_to_idx(map_addr, level);
308 struct granule *g = __find_next_level_idx(g_tbl, idx);
309
310 if (g != NULL) {
311 granule_lock(g, GRANULE_STATE_RTT);
312 }
313
314 return g;
315}
316
317/*
318 * Walk an RTT until level @level using @map_addr.
319 * @g_root is the root (level 0) table and must be locked before the call.
320 * @start_level is the initial lookup level used for the stage 2 translation
321 * tables which may depend on the configuration of the realm, factoring in the
322 * IPA size of the realm and the desired starting level (within the limits
323 * defined by the Armv8 VMSA including options for stage 2 table concatenation).
324 * The function uses hand-over-hand locking to avoid race conditions and allow
325 * concurrent access to RTT tree which is not part of the current walk; when a
326 * next level table is reached it is locked before releasing previously locked
327 * table.
328 * The walk stops when either:
329 * - The entry found is a leaf entry (not an RTT Table entry), or
330 * - Level @level is reached.
331 *
332 * On return:
333 * - rtt_walk::last_level is the last level that has been reached by the walk.
334 * - rtt_walk.g_llt points to the TABLE granule at level @rtt_walk::level.
335 * The granule is locked.
336 * - rtt_walk::index is the entry index at rtt_walk.g_llt for @map_addr.
337 */
338void rtt_walk_lock_unlock(struct granule *g_root,
339 int start_level,
340 unsigned long ipa_bits,
341 unsigned long map_addr,
342 long level,
343 struct rtt_walk *wi)
344{
345 struct granule *g_tbls[NR_RTT_LEVELS] = { NULL };
346 unsigned long sl_idx;
347 int i, last_level;
348
349 assert(start_level >= MIN_STARTING_LEVEL);
350 assert(level >= start_level);
351 assert(map_addr < (1UL << ipa_bits));
352 assert(wi != NULL);
353
354 /* Handle concatenated starting level (SL) tables */
355 sl_idx = s2_sl_addr_to_idx(map_addr, start_level, ipa_bits);
356 if (sl_idx >= S2TTES_PER_S2TT) {
357 unsigned int tt_num = (sl_idx >> S2TTE_STRIDE);
358 struct granule *g_concat_root = g_root + tt_num;
359
360 granule_lock(g_concat_root, GRANULE_STATE_RTT);
361 granule_unlock(g_root);
362 g_root = g_concat_root;
363 }
364
365 g_tbls[start_level] = g_root;
366 for (i = start_level; i < level; i++) {
367 /*
368 * Lock next RTT level. Correct locking order is guaranteed
369 * because reference is obtained from a locked granule
370 * (previous level). Also, hand-over-hand locking/unlocking is
371 * used to avoid race conditions.
372 */
373 g_tbls[i + 1] = __find_lock_next_level(g_tbls[i], map_addr, i);
374 if (g_tbls[i + 1] == NULL) {
375 last_level = i;
376 goto out;
377 }
378 granule_unlock(g_tbls[i]);
379 }
380
381 last_level = level;
382out:
383 wi->last_level = last_level;
384 wi->g_llt = g_tbls[last_level];
385 wi->index = s2_addr_to_idx(map_addr, last_level);
386}
387
388/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100389 * Creates an unassigned_empty s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000390 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100391unsigned long s2tte_create_unassigned_empty(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000392{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100393 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100394}
395
396/*
397 * Creates an unassigned_ram s2tte.
398 */
399unsigned long s2tte_create_unassigned_ram(void)
400{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100401 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000402}
403
404/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100405 * Creates an unassigned_destroyed s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000406 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100407unsigned long s2tte_create_unassigned_destroyed(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000408{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100409 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
410}
411
412/*
413 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
414 * RIPAS=DESTROYED, at level @level.
415 */
416unsigned long s2tte_create_assigned_destroyed(unsigned long pa, long level)
417{
418 assert(level >= RTT_MIN_BLOCK_LEVEL);
419 assert(addr_is_level_aligned(pa, level));
420 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000421}
422
423/*
424 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
425 * RIPAS=EMPTY, at level @level.
426 */
427unsigned long s2tte_create_assigned_empty(unsigned long pa, long level)
428{
429 assert(level >= RTT_MIN_BLOCK_LEVEL);
430 assert(addr_is_level_aligned(pa, level));
431 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
432}
433
434/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100435 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000436 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100437unsigned long s2tte_create_assigned_ram(unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000438{
439 assert(level >= RTT_MIN_BLOCK_LEVEL);
440 assert(addr_is_level_aligned(pa, level));
441 if (level == RTT_PAGE_LEVEL) {
442 return (pa | S2TTE_PAGE);
443 }
444 return (pa | S2TTE_BLOCK);
445}
446
447/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100448 * Creates an unassigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000449 */
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100450unsigned long s2tte_create_unassigned_ns(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000451{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100452 return (S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED |
453 S2TTE_INVALID_UNPROTECTED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000454}
455
456/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100457 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000458 *
459 * The following S2 TTE fields are provided through @s2tte argument:
460 * - The physical address
461 * - MemAttr
462 * - S2AP
463 * - Shareability
464 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100465unsigned long s2tte_create_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000466{
467 assert(level >= RTT_MIN_BLOCK_LEVEL);
468 if (level == RTT_PAGE_LEVEL) {
469 return (s2tte | S2TTE_PAGE_NS);
470 }
471 return (s2tte | S2TTE_BLOCK_NS);
472}
473
474/*
475 * Validate the portion of NS S2TTE that is provided by the host.
476 */
477bool host_ns_s2tte_is_valid(unsigned long s2tte, long level)
478{
479 unsigned long mask = addr_level_mask(~0UL, level) |
480 S2TTE_MEMATTR_MASK |
481 S2TTE_AP_MASK |
482 S2TTE_SH_MASK;
483
484 /*
485 * Test that all fields that are not controlled by the host are zero
486 * and that the output address is correctly aligned. Note that
487 * the host is permitted to map any physical address outside PAR.
488 */
489 if ((s2tte & ~mask) != 0UL) {
490 return false;
491 }
492
493 /*
494 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
495 */
496 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
497 return false;
498 }
499
500 /*
501 * Only one value masked by S2TTE_SH_MASK is invalid/reserved.
502 */
503 if ((s2tte & S2TTE_SH_MASK) == S2TTE_SH_RESERVED) {
504 return false;
505 }
506
507 /*
508 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
509 */
510 return true;
511}
512
513/*
514 * Returns the portion of NS S2TTE that is set by the host.
515 */
516unsigned long host_ns_s2tte(unsigned long s2tte, long level)
517{
518 unsigned long mask = addr_level_mask(~0UL, level) |
519 S2TTE_MEMATTR_MASK |
520 S2TTE_AP_MASK |
521 S2TTE_SH_MASK;
522 return (s2tte & mask);
523}
524
525/*
526 * Creates a table s2tte at level @level with output address @pa.
527 */
528unsigned long s2tte_create_table(unsigned long pa, long level)
529{
530 assert(level < RTT_PAGE_LEVEL);
531 assert(GRANULE_ALIGNED(pa));
532
533 return (pa | S2TTE_TABLE);
534}
535
536/*
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100537 * Returns true if s2tte has defined ripas value, namely if it is one of:
538 * - unassigned_empty
539 * - unassigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100540 * - unassigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100541 * - assigned_empty
542 * - assigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100543 * - assigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100544 */
545bool s2tte_has_ripas(unsigned long s2tte, long level)
546{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100547 return (((s2tte & S2TTE_NS) == 0UL) && !s2tte_is_table(s2tte, level));
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100548}
549
550/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000551 * Returns true if @s2tte has HIPAS=@hipas.
552 */
553static bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
554{
555 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
556 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
557
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100558 return ((desc_type == S2TTE_INVALID) && (invalid_desc_hipas == hipas));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000559}
560
561/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100562 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000563 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100564static bool s2tte_has_unassigned_ripas(unsigned long s2tte, unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000565{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100566 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
567 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
568}
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100569
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100570/*
571 * Returns true if @s2tte has HIPAS=ASSIGNED and RIPAS=@ripas.
572 */
573static bool s2tte_has_assigned_ripas(unsigned long s2tte, unsigned long ripas)
574{
575 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
576 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100577}
578
579/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100580 * Returns true if @s2tte has HIPAS=UNASSIGNED.
581 */
582bool s2tte_is_unassigned(unsigned long s2tte)
583{
584 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED);
585}
586
587/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100588 * Returns true if @s2tte is an unassigned_empty.
589 */
590bool s2tte_is_unassigned_empty(unsigned long s2tte)
591{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100592 return (((s2tte & S2TTE_NS) == 0UL) &&
593 s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100594}
595
596/*
597 * Returns true if @s2tte is an unassigned_ram.
598 */
599bool s2tte_is_unassigned_ram(unsigned long s2tte)
600{
601 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
602}
603
604/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100605 * Returns true if @s2tte is unassigned_ns.
606 */
607bool s2tte_is_unassigned_ns(unsigned long s2tte)
608{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100609 return (((s2tte & S2TTE_NS) != 0UL) &&
610 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000611}
612
613/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100614 * Returns true if @s2tte has RIPAS=DESTROYED.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000615 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100616bool s2tte_is_unassigned_destroyed(unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000617{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100618 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
619}
620
621/*
622 * Returns true if @s2tte is an assigned_destroyed.
623 */
624bool s2tte_is_assigned_destroyed(unsigned long s2tte, long level)
625{
626 (void)level;
627
628 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000629}
630
631/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100632 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000633 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100634bool s2tte_is_assigned_empty(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000635{
636 (void)level;
637
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100638 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000639}
640
641static bool s2tte_check(unsigned long s2tte, long level, unsigned long ns)
642{
643 unsigned long desc_type;
644
645 if ((s2tte & S2TTE_NS) != ns) {
646 return false;
647 }
648
649 desc_type = s2tte & DESC_TYPE_MASK;
650
651 /* Only pages at L3 and valid blocks at L2 allowed */
652 if (((level == RTT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000653 ((level == RTT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK))) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000654 return true;
655 }
656
657 return false;
658}
659
660/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100661 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000662 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100663bool s2tte_is_assigned_ram(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000664{
665 return s2tte_check(s2tte, level, 0UL);
666}
667
668/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100669 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000670 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100671bool s2tte_is_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000672{
673 return s2tte_check(s2tte, level, S2TTE_NS);
674}
675
676/*
677 * Returns true if @s2tte is a table at level @level.
678 */
679bool s2tte_is_table(unsigned long s2tte, long level)
680{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100681 return ((level < RTT_PAGE_LEVEL) &&
682 ((s2tte & DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000683}
684
685/*
686 * Returns RIPAS of @s2tte.
687 *
688 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
689 * The s2tte must be not valid/invalid descriptor.
690 */
691enum ripas s2tte_get_ripas(unsigned long s2tte)
692{
693 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
694
695 /*
696 * If valid s2tte descriptor is passed, then ensure S2AP[0]
697 * bit is 1 (S2AP is set to RW for lower EL), which corresponds
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100698 * to RIPAS_RAM (bits[6:5] = b01) on a valid descriptor.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000699 */
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100700 if (((s2tte & DESC_TYPE_MASK) != S2TTE_INVALID) &&
Soby Mathewb4c6df42022-11-09 11:13:29 +0000701 (desc_ripas != S2TTE_INVALID_RIPAS_RAM)) {
702 assert(false);
703 }
704
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100705 switch (desc_ripas) {
706 case S2TTE_INVALID_RIPAS_EMPTY:
Yousuf A62808152022-10-31 10:35:42 +0000707 return RIPAS_EMPTY;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100708 case S2TTE_INVALID_RIPAS_RAM:
709 return RIPAS_RAM;
710 default:
711 assert(desc_ripas == S2TTE_INVALID_RIPAS_DESTROYED);
712 return RIPAS_DESTROYED;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000713 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000714}
715
716/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100717 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000718 *
719 * The granule is populated before it is made a table,
720 * hence, don't use s2tte_write for access.
721 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100722void s2tt_init_unassigned_empty(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000723{
724 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100725 s2tt[i] = s2tte_create_unassigned_empty();
726 }
727
728 dsb(ish);
729}
730
731/*
732 * Populates @s2tt with unassigned_ram s2ttes.
733 *
734 * The granule is populated before it is made a table,
735 * hence, don't use s2tte_write for access.
736 */
737void s2tt_init_unassigned_ram(unsigned long *s2tt)
738{
739 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
740 s2tt[i] = s2tte_create_unassigned_ram();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000741 }
742
743 dsb(ish);
744}
745
746/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100747 * Populates @s2tt with unassigned_ns s2ttes.
748 *
749 * The granule is populated before it is made a table,
750 * hence, don't use s2tte_write for access.
751 */
752void s2tt_init_unassigned_ns(unsigned long *s2tt)
753{
754 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
755 s2tt[i] = s2tte_create_unassigned_ns();
756 }
757
758 dsb(ish);
759}
760
761/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000762 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
763 *
764 * The granule is populated before it is made a table,
765 * hence, don't use s2tte_write for access.
766 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100767void s2tt_init_unassigned_destroyed(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000768{
769 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100770 s2tt[i] = s2tte_create_unassigned_destroyed();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000771 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100772 dsb(ish);
773}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000774
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100775/*
776 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
777 * contiguous memory block starting at @pa, and mapped at level @level.
778 *
779 * The granule is populated before it is made a table,
780 * hence, don't use s2tte_write for access.
781 */
782void s2tt_init_assigned_destroyed(unsigned long *s2tt, unsigned long pa, long level)
783{
784 const unsigned long map_size = s2tte_map_size(level);
785
786 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
787 s2tt[i] = s2tte_create_assigned_destroyed(pa, level);
788 pa += map_size;
789 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000790 dsb(ish);
791}
792
793unsigned long s2tte_map_size(int level)
794{
795 int levels, lsb;
796
797 assert(level <= RTT_PAGE_LEVEL);
798
799 levels = RTT_PAGE_LEVEL - level;
800 lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100801 return (1UL << lsb);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000802}
803
804/*
805 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
806 * contiguous memory block starting at @pa, and mapped at level @level.
807 *
808 * The granule is populated before it is made a table,
809 * hence, don't use s2tte_write for access.
810 */
811void s2tt_init_assigned_empty(unsigned long *s2tt, unsigned long pa, long level)
812{
813 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000814
AlexeiFedorov3a739332023-04-13 13:54:04 +0100815 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000816 s2tt[i] = s2tte_create_assigned_empty(pa, level);
817 pa += map_size;
818 }
819 dsb(ish);
820}
821
822/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100823 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000824 * contiguous memory block starting at @pa, and mapped at level @level.
825 *
826 * The granule is populated before it is made a table,
827 * hence, don't use s2tte_write for access.
828 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100829void s2tt_init_assigned_ram(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000830{
831 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000832
AlexeiFedorov3a739332023-04-13 13:54:04 +0100833 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
834 s2tt[i] = s2tte_create_assigned_ram(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000835 pa += map_size;
836 }
837 dsb(ish);
838}
839
840/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100841 * Populates @s2tt with assigned_ns s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000842 * contiguous memory block starting at @pa, and mapped at level @level.
843 *
844 * The granule is populated before it is made a table,
845 * hence, don't use s2tte_write for access.
846 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100847void s2tt_init_assigned_ns(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000848{
849 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000850
AlexeiFedorov3a739332023-04-13 13:54:04 +0100851 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
852 s2tt[i] = s2tte_create_assigned_ns(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000853 pa += map_size;
854 }
855 dsb(ish);
856}
857
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100858/*
859 * Returns true if s2tte has 'output address' field, namely, if it is one of:
860 * - assigned_empty
861 * - assigned_ram
862 * - assigned_ns
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100863 * - assigned_destroyed
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100864 * - table
865 */
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100866bool s2tte_has_pa(unsigned long s2tte, long level)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100867{
868 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
869
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100870 return ((desc_type != S2TTE_INVALID) || /* block, page or table */
871 s2tte_is_assigned_empty(s2tte, level) ||
872 s2tte_is_assigned_destroyed(s2tte, level));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100873}
874
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100875/*
876 * Returns true if s2tte is a live RTTE entry. i.e.,
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100877 * HIPAS is ASSIGNED.
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100878 *
879 * NOTE: For now, only the RTTE with PA are live.
880 * This could change with EXPORT/IMPORT support.
881 */
882bool s2tte_is_live(unsigned long s2tte, long level)
883{
884 return s2tte_has_pa(s2tte, level);
885}
886
Soby Mathewb4c6df42022-11-09 11:13:29 +0000887/* Returns physical address of a page entry or block */
888unsigned long s2tte_pa(unsigned long s2tte, long level)
889{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100890 if (!s2tte_has_pa(s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000891 assert(false);
892 }
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100893
894 if (s2tte_is_table(s2tte, level)) {
895 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
896 }
897
Soby Mathewb4c6df42022-11-09 11:13:29 +0000898 return addr_level_mask(s2tte, level);
899}
900
901/* Returns physical address of a table entry */
902unsigned long s2tte_pa_table(unsigned long s2tte, long level)
903{
904 assert(s2tte_is_table(s2tte, level));
905 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
906}
907
908bool addr_is_level_aligned(unsigned long addr, long level)
909{
910 return (addr == addr_level_mask(addr, level));
911}
912
913typedef bool (*s2tte_type_checker)(unsigned long s2tte);
914
915static bool __table_is_uniform_block(unsigned long *table,
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100916 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000917{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100918 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
919 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000920
921 if (!s2tte_is_x(s2tte)) {
922 return false;
923 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000924 }
925
926 return true;
927}
928
929/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100930 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000931 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100932bool table_is_unassigned_empty_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000933{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100934 return __table_is_uniform_block(table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100935}
936
937/*
938 * Returns true if all s2ttes in @table are unassigned_ram.
939 */
940bool table_is_unassigned_ram_block(unsigned long *table)
941{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100942 return __table_is_uniform_block(table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000943}
944
945/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100946 * Returns true if all s2ttes in @table are unassigned_ns
947 */
948bool table_is_unassigned_ns_block(unsigned long *table)
949{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100950 return __table_is_uniform_block(table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100951}
952
953/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100954 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +0000955 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100956bool table_is_unassigned_destroyed_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000957{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100958 return __table_is_uniform_block(table, s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000959}
960
961typedef bool (*s2tte_type_level_checker)(unsigned long s2tte, long level);
962
963static bool __table_maps_block(unsigned long *table,
964 long level,
965 s2tte_type_level_checker s2tte_is_x)
966{
967 unsigned long base_pa;
968 unsigned long map_size = s2tte_map_size(level);
969 unsigned long s2tte = s2tte_read(&table[0]);
970 unsigned int i;
971
972 if (!s2tte_is_x(s2tte, level)) {
973 return false;
974 }
975
976 base_pa = s2tte_pa(s2tte, level);
977 if (!addr_is_level_aligned(base_pa, level - 1L)) {
978 return false;
979 }
980
981 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
982 unsigned long expected_pa = base_pa + (i * map_size);
983
984 s2tte = s2tte_read(&table[i]);
985
986 if (!s2tte_is_x(s2tte, level)) {
987 return false;
988 }
989
990 if (s2tte_pa(s2tte, level) != expected_pa) {
991 return false;
992 }
993 }
994
995 return true;
996}
997
998/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100999 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +00001000 * and refer to a contiguous block of granules aligned to @level - 1.
1001 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001002bool table_maps_assigned_empty_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001003{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001004 return __table_maps_block(table, level, s2tte_is_assigned_empty);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001005}
1006
1007/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001008 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001009 * refer to a contiguous block of granules aligned to @level - 1.
1010 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001011bool table_maps_assigned_ram_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001012{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001013 return __table_maps_block(table, level, s2tte_is_assigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001014}
1015
1016/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001017 * Returns true if all s2ttes in @table are assigned_ns s2ttes and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001018 * refer to a contiguous block of granules aligned to @level - 1.
AlexeiFedorov3a739332023-04-13 13:54:04 +01001019 *
1020 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001021 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001022bool table_maps_assigned_ns_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001023{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001024 return __table_maps_block(table, level, s2tte_is_assigned_ns);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001025}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001026
1027/*
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001028 * Returns true if all s2ttes are assigned_destroyed and
1029 * refer to a contiguous block of granules aligned to @level - 1.
1030 */
1031bool table_maps_assigned_destroyed_block(unsigned long *table, long level)
1032{
1033 return __table_maps_block(table, level, s2tte_is_assigned_destroyed);
1034}
1035
1036/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001037 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001038 * skip the non-live entries (i.e., HIPAS=UNASSIGNED).
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001039 * In other words, the scanning stops when a live RTTE is encountered or we
1040 * reach the end of this RTT.
1041 *
1042 * For now an RTTE can be considered non-live if it doesn't have a PA.
1043 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1044 * in the RTTE.
1045 *
1046 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1047 * with RMI_ERROR_RTT).
1048 *
1049 * Returns:
1050 * - If the entry @wi.index is live, returns @addr.
1051 * - If none of the entries in the @s2tt are "live", returns the address of the
1052 * first entry in the next table.
1053 * - Otherwise, the address of the first live entry in @s2tt
1054 */
1055unsigned long skip_non_live_entries(unsigned long addr,
1056 unsigned long *s2tt,
1057 const struct rtt_walk *wi)
1058{
1059 unsigned int i, index = wi->index;
1060 long level = wi->last_level;
1061 unsigned long map_size;
1062
1063 /*
1064 * If the entry for the map_addr is live,
1065 * return @addr.
1066 */
1067 if (s2tte_is_live(s2tte_read(&s2tt[index]), level)) {
1068 return addr;
1069 }
1070
1071 /*
1072 * Align the address DOWN to the map_size, as expected for the @level,
1073 * so that we can compute the correct address by using the index.
1074 */
1075 map_size = s2tte_map_size(level);
1076 addr &= ~(map_size - 1UL);
1077
1078 /* Skip the "index" */
1079 for (i = index + 1U; i < S2TTES_PER_S2TT; i++) {
1080 unsigned long s2tte = s2tte_read(&s2tt[i]);
1081
1082 if (s2tte_is_live(s2tte, level)) {
1083 break;
1084 }
1085 }
1086
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001087 return (addr + (i - index) * map_size);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001088}