blob: 3b2fda7d16db378bc94bdf371f3690fbaf96d775 [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>
AlexeiFedorov3a739332023-04-13 13:54:04 +01007#include <attestation_token.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +00008#include <bitmap.h>
9#include <buffer.h>
10#include <gic.h>
11#include <granule.h>
12#include <memory_alloc.h>
13#include <realm.h>
14#include <ripas.h>
15#include <smc.h>
16#include <status.h>
17#include <stddef.h>
18#include <string.h>
19#include <table.h>
20
21/*
22 * For prototyping we assume 4K pages
23 */
24#define BLOCK_L2_SIZE (GRANULE_SIZE * S2TTES_PER_S2TT)
25
26/*
27 * The maximum number of bits supported by the RMM for a stage 2 translation
28 * output address (including stage 2 table entries).
29 */
30#define S2TTE_OA_BITS 48
31
AlexeiFedorovc53b1f72023-07-04 15:37:03 +010032#define DESC_TYPE_MASK 3UL
33#define S2TTE_Lx_INVALID 0UL
34#define S2TTE_L012_BLOCK 1UL
35#define S2TTE_L012_TABLE 3UL
36#define S2TTE_L3_PAGE 3UL
Soby Mathewb4c6df42022-11-09 11:13:29 +000037
38/*
39 * The following constants for the mapping attributes (S2_TTE_MEMATTR_*)
40 * assume that HCR_EL2.FWB is set.
41 */
42#define S2TTE_MEMATTR_SHIFT 2
43#define S2TTE_MEMATTR_MASK (0x7UL << S2TTE_MEMATTR_SHIFT)
44#define S2TTE_MEMATTR_FWB_NORMAL_WB ((1UL << 4) | (2UL << 2))
45#define S2TTE_MEMATTR_FWB_RESERVED ((1UL << 4) | (0UL << 2))
46
47#define S2TTE_AP_SHIFT 6
48#define S2TTE_AP_MASK (3UL << S2TTE_AP_SHIFT)
49#define S2TTE_AP_RW (3UL << S2TTE_AP_SHIFT)
50
51#define S2TTE_SH_SHIFT 8
52#define S2TTE_SH_MASK (3UL << S2TTE_SH_SHIFT)
53#define S2TTE_SH_NS (0UL << S2TTE_SH_SHIFT)
54#define S2TTE_SH_RESERVED (1UL << S2TTE_SH_SHIFT)
55#define S2TTE_SH_OS (2UL << S2TTE_SH_SHIFT)
56#define S2TTE_SH_IS (3UL << S2TTE_SH_SHIFT) /* Inner Shareable */
57
58/*
59 * We set HCR_EL2.FWB So we set bit[4] to 1 and bits[3:2] to 2 and force
60 * everyting to be Normal Write-Back
61 */
62#define S2TTE_MEMATTR_FWB_NORMAL_WB ((1UL << 4) | (2UL << 2))
63#define S2TTE_AF (1UL << 10)
64#define S2TTE_XN (2UL << 53)
65#define S2TTE_NS (1UL << 55)
66
67#define S2TTE_ATTRS (S2TTE_MEMATTR_FWB_NORMAL_WB | S2TTE_AP_RW | \
68 S2TTE_SH_IS | S2TTE_AF)
69
70#define S2TTE_TABLE S2TTE_L012_TABLE
71#define S2TTE_BLOCK (S2TTE_ATTRS | S2TTE_L012_BLOCK)
72#define S2TTE_PAGE (S2TTE_ATTRS | S2TTE_L3_PAGE)
73#define S2TTE_BLOCK_NS (S2TTE_NS | S2TTE_XN | S2TTE_AF | S2TTE_L012_BLOCK)
74#define S2TTE_PAGE_NS (S2TTE_NS | S2TTE_XN | S2TTE_AF | S2TTE_L3_PAGE)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +010075#define S2TTE_INVALID S2TTE_Lx_INVALID
Soby Mathewb4c6df42022-11-09 11:13:29 +000076
77/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +010078 * The type of stage 2 translation table entry (s2tte) is defined by:
79 * 1. Table level where it resides
80 * 2. DESC_TYPE field[1:0]
AlexeiFedorovc53b1f72023-07-04 15:37:03 +010081 * 4. HIPAS field [4:2]
82 * 4. RIPAS field [6:5]
AlexeiFedorov5ceff352023-04-12 16:17:00 +010083 * 5. NS field [55]
Soby Mathewb4c6df42022-11-09 11:13:29 +000084 *
AlexeiFedorov5ceff352023-04-12 16:17:00 +010085 * s2tte type level DESC_TYPE[1:0] HIPAS[5:2] RIPAS[6] 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 * assigned_empty 2,3 invalid[0] assigned[1] empty[0] 0 to level
92 * -----------------------------------------------------------------------------
93 * assigned_ram 3 page[1] n/a n/a 0 to level
94 * 2 block[3] n/a n/a 0 to level
95 * -----------------------------------------------------------------------------
96 * destroyed any invalid[0] destroyed[2] n/a 0 n/a
97 * =============================================================================
98 * unassigned_ns any invalid[0] unassigned[0] n/a 1 n/a
99 * -----------------------------------------------------------------------------
100 * assigned_ns 3 page[1] n/a n/a 1 to level
101 * 2 block[3] n/a n/a 1 to level
102 * =============================================================================
103 * table <=2 table[1] n/a n/a n/a to 4K
Soby Mathewb4c6df42022-11-09 11:13:29 +0000104 */
105
106#define S2TTE_INVALID_HIPAS_SHIFT 2
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100107#define S2TTE_INVALID_HIPAS_WIDTH 3
Soby Mathewb4c6df42022-11-09 11:13:29 +0000108#define S2TTE_INVALID_HIPAS_MASK MASK(S2TTE_INVALID_HIPAS)
109
110#define S2TTE_INVALID_HIPAS_UNASSIGNED (INPLACE(S2TTE_INVALID_HIPAS, 0))
111#define S2TTE_INVALID_HIPAS_ASSIGNED (INPLACE(S2TTE_INVALID_HIPAS, 1))
Soby Mathewb4c6df42022-11-09 11:13:29 +0000112
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100113#define S2TTE_INVALID_RIPAS_SHIFT 5
114#define S2TTE_INVALID_RIPAS_WIDTH 2
Soby Mathewb4c6df42022-11-09 11:13:29 +0000115#define S2TTE_INVALID_RIPAS_MASK MASK(S2TTE_INVALID_RIPAS)
116
117#define S2TTE_INVALID_RIPAS_EMPTY (INPLACE(S2TTE_INVALID_RIPAS, 0))
118#define S2TTE_INVALID_RIPAS_RAM (INPLACE(S2TTE_INVALID_RIPAS, 1))
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100119#define S2TTE_INVALID_RIPAS_DESTROYED (INPLACE(S2TTE_INVALID_RIPAS, 2))
Soby Mathewb4c6df42022-11-09 11:13:29 +0000120
Soby Mathewb4c6df42022-11-09 11:13:29 +0000121#define S2TTE_INVALID_UNPROTECTED 0x0UL
122
123#define NR_RTT_LEVELS 4
124
125/*
126 * Invalidates S2 TLB entries from [ipa, ipa + size] region tagged with `vmid`.
127 */
128static void stage2_tlbi_ipa(const struct realm_s2_context *s2_ctx,
129 unsigned long ipa,
130 unsigned long size)
131{
132 /*
133 * Notes:
134 *
135 * - This follows the description provided in the Arm ARM on
136 * "Invalidation of TLB entries from stage 2 translations".
137 *
138 * - @TODO: Provide additional information to this primitive so that
139 * we can utilize:
140 * - The TTL level hint, see FEAT_TTL,
141 * - Final level lookup only invalidation,
142 * - Address range invalidation.
143 */
144
145 /*
146 * Save the current content of vttb_el2.
147 */
148 unsigned long old_vttbr_el2 = read_vttbr_el2();
149
150 /*
151 * Make 'vmid' the `current vmid`. Note that the tlbi instructions
152 * bellow target the TLB entries that match the `current vmid`.
153 */
154 write_vttbr_el2(INPLACE(VTTBR_EL2_VMID, s2_ctx->vmid));
155 isb();
156
157 /*
158 * Invalidate entries in S2 TLB caches that
159 * match both `ipa` & the `current vmid`.
160 */
161 while (size != 0UL) {
162 tlbiipas2e1is(ipa >> 12);
163 size -= GRANULE_SIZE;
164 ipa += GRANULE_SIZE;
165 }
166 dsb(ish);
167
168 /*
169 * The architecture does not require TLB invalidation by IPA to affect
170 * combined Stage-1 + Stage-2 TLBs. Therefore we must invalidate all of
171 * Stage-1 (tagged with the `current vmid`) after invalidating Stage-2.
172 */
173 tlbivmalle1is();
174 dsb(ish);
175 isb();
176
177 /*
178 * Restore the old content of vttb_el2.
179 */
180 write_vttbr_el2(old_vttbr_el2);
181 isb();
182}
183
184/*
185 * Invalidate S2 TLB entries with "addr" IPA.
186 * Call this function after:
187 * 1. A L3 page desc has been removed.
188 */
189void invalidate_page(const struct realm_s2_context *s2_ctx, unsigned long addr)
190{
191 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
192}
193
194/*
195 * Invalidate S2 TLB entries with "addr" IPA.
196 * Call this function after:
197 * 1. A L2 block desc has been removed, or
198 * 2a. A L2 table desc has been removed, where
199 * 2b. All S2TTEs in L3 table that the L2 table desc was pointed to were invalid.
200 */
201void invalidate_block(const struct realm_s2_context *s2_ctx, unsigned long addr)
202{
203 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
204}
205
206/*
207 * Invalidate S2 TLB entries with "addr" IPA.
208 * Call this function after:
209 * 1a. A L2 table desc has been removed, where
210 * 1b. Some S2TTEs in the table that the L2 table desc was pointed to were valid.
211 */
212void invalidate_pages_in_block(const struct realm_s2_context *s2_ctx, unsigned long addr)
213{
214 stage2_tlbi_ipa(s2_ctx, addr, BLOCK_L2_SIZE);
215}
216
217/*
218 * Return the index of the entry describing @addr in the translation table at
219 * level @level. This only works for non-concatenated page tables, so should
220 * not be called to get the index for the starting level.
221 *
222 * See the library pseudocode
223 * aarch64/translation/vmsa_addrcalc/AArch64.TTEntryAddress on which this is
224 * modeled.
225 */
226static unsigned long s2_addr_to_idx(unsigned long addr, long level)
227{
228 int levels = RTT_PAGE_LEVEL - level;
229 int lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
230
231 addr >>= lsb;
232 addr &= (1UL << S2TTE_STRIDE) - 1;
233 return addr;
234}
235
236/*
237 * Return the index of the entry describing @addr in the translation table
238 * starting level. This may return an index >= S2TTES_PER_S2TT when the
239 * combination of @start_level and @ipa_bits implies concatenated
240 * stage 2 tables.
241 *
242 * See the library pseudocode
243 * aarch64/translation/vmsa_addrcalc/AArch64.S2SLTTEntryAddress on which
244 * this is modeled.
245 */
246static unsigned long s2_sl_addr_to_idx(unsigned long addr, int start_level,
247 unsigned long ipa_bits)
248{
249 int levels = RTT_PAGE_LEVEL - start_level;
250 int lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
251
252 addr &= (1UL << ipa_bits) - 1UL;
253 addr >>= lsb;
254 return addr;
255}
256
257static unsigned long addr_level_mask(unsigned long addr, long level)
258{
259 int levels = RTT_PAGE_LEVEL - level;
260 unsigned int lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
261 unsigned int msb = S2TTE_OA_BITS - 1;
262
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100263 return (addr & BIT_MASK_ULL(msb, lsb));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000264}
265
266static inline unsigned long table_entry_to_phys(unsigned long entry)
267{
268 return addr_level_mask(entry, RTT_PAGE_LEVEL);
269}
270
271static inline bool entry_is_table(unsigned long entry)
272{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100273 return ((entry & DESC_TYPE_MASK) == S2TTE_L012_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000274}
275
276static unsigned long __table_get_entry(struct granule *g_tbl,
277 unsigned long idx)
278{
279 unsigned long *table, entry;
280
281 table = granule_map(g_tbl, SLOT_RTT);
282 entry = s2tte_read(&table[idx]);
283 buffer_unmap(table);
284
285 return entry;
286}
287
288static struct granule *__find_next_level_idx(struct granule *g_tbl,
289 unsigned long idx)
290{
291 const unsigned long entry = __table_get_entry(g_tbl, idx);
292
293 if (!entry_is_table(entry)) {
294 return NULL;
295 }
296
297 return addr_to_granule(table_entry_to_phys(entry));
298}
299
300static struct granule *__find_lock_next_level(struct granule *g_tbl,
301 unsigned long map_addr,
302 long level)
303{
304 const unsigned long idx = s2_addr_to_idx(map_addr, level);
305 struct granule *g = __find_next_level_idx(g_tbl, idx);
306
307 if (g != NULL) {
308 granule_lock(g, GRANULE_STATE_RTT);
309 }
310
311 return g;
312}
313
314/*
315 * Walk an RTT until level @level using @map_addr.
316 * @g_root is the root (level 0) table and must be locked before the call.
317 * @start_level is the initial lookup level used for the stage 2 translation
318 * tables which may depend on the configuration of the realm, factoring in the
319 * IPA size of the realm and the desired starting level (within the limits
320 * defined by the Armv8 VMSA including options for stage 2 table concatenation).
321 * The function uses hand-over-hand locking to avoid race conditions and allow
322 * concurrent access to RTT tree which is not part of the current walk; when a
323 * next level table is reached it is locked before releasing previously locked
324 * table.
325 * The walk stops when either:
326 * - The entry found is a leaf entry (not an RTT Table entry), or
327 * - Level @level is reached.
328 *
329 * On return:
330 * - rtt_walk::last_level is the last level that has been reached by the walk.
331 * - rtt_walk.g_llt points to the TABLE granule at level @rtt_walk::level.
332 * The granule is locked.
333 * - rtt_walk::index is the entry index at rtt_walk.g_llt for @map_addr.
334 */
335void rtt_walk_lock_unlock(struct granule *g_root,
336 int start_level,
337 unsigned long ipa_bits,
338 unsigned long map_addr,
339 long level,
340 struct rtt_walk *wi)
341{
342 struct granule *g_tbls[NR_RTT_LEVELS] = { NULL };
343 unsigned long sl_idx;
344 int i, last_level;
345
346 assert(start_level >= MIN_STARTING_LEVEL);
347 assert(level >= start_level);
348 assert(map_addr < (1UL << ipa_bits));
349 assert(wi != NULL);
350
351 /* Handle concatenated starting level (SL) tables */
352 sl_idx = s2_sl_addr_to_idx(map_addr, start_level, ipa_bits);
353 if (sl_idx >= S2TTES_PER_S2TT) {
354 unsigned int tt_num = (sl_idx >> S2TTE_STRIDE);
355 struct granule *g_concat_root = g_root + tt_num;
356
357 granule_lock(g_concat_root, GRANULE_STATE_RTT);
358 granule_unlock(g_root);
359 g_root = g_concat_root;
360 }
361
362 g_tbls[start_level] = g_root;
363 for (i = start_level; i < level; i++) {
364 /*
365 * Lock next RTT level. Correct locking order is guaranteed
366 * because reference is obtained from a locked granule
367 * (previous level). Also, hand-over-hand locking/unlocking is
368 * used to avoid race conditions.
369 */
370 g_tbls[i + 1] = __find_lock_next_level(g_tbls[i], map_addr, i);
371 if (g_tbls[i + 1] == NULL) {
372 last_level = i;
373 goto out;
374 }
375 granule_unlock(g_tbls[i]);
376 }
377
378 last_level = level;
379out:
380 wi->last_level = last_level;
381 wi->g_llt = g_tbls[last_level];
382 wi->index = s2_addr_to_idx(map_addr, last_level);
383}
384
385/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100386 * Creates an unassigned_empty s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000387 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100388unsigned long s2tte_create_unassigned_empty(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000389{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100390 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100391}
392
393/*
394 * Creates an unassigned_ram s2tte.
395 */
396unsigned long s2tte_create_unassigned_ram(void)
397{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100398 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000399}
400
401/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100402 * Creates an unassigned_destroyed s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000403 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100404unsigned long s2tte_create_unassigned_destroyed(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000405{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100406 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
407}
408
409/*
410 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
411 * RIPAS=DESTROYED, at level @level.
412 */
413unsigned long s2tte_create_assigned_destroyed(unsigned long pa, long level)
414{
415 assert(level >= RTT_MIN_BLOCK_LEVEL);
416 assert(addr_is_level_aligned(pa, level));
417 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000418}
419
420/*
421 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
422 * RIPAS=EMPTY, at level @level.
423 */
424unsigned long s2tte_create_assigned_empty(unsigned long pa, long level)
425{
426 assert(level >= RTT_MIN_BLOCK_LEVEL);
427 assert(addr_is_level_aligned(pa, level));
428 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
429}
430
431/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100432 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000433 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100434unsigned long s2tte_create_assigned_ram(unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000435{
436 assert(level >= RTT_MIN_BLOCK_LEVEL);
437 assert(addr_is_level_aligned(pa, level));
438 if (level == RTT_PAGE_LEVEL) {
439 return (pa | S2TTE_PAGE);
440 }
441 return (pa | S2TTE_BLOCK);
442}
443
444/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100445 * Creates an unassigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000446 */
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100447unsigned long s2tte_create_unassigned_ns(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000448{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100449 return (S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED |
450 S2TTE_INVALID_UNPROTECTED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000451}
452
453/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100454 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000455 *
456 * The following S2 TTE fields are provided through @s2tte argument:
457 * - The physical address
458 * - MemAttr
459 * - S2AP
460 * - Shareability
461 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100462unsigned long s2tte_create_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000463{
464 assert(level >= RTT_MIN_BLOCK_LEVEL);
465 if (level == RTT_PAGE_LEVEL) {
466 return (s2tte | S2TTE_PAGE_NS);
467 }
468 return (s2tte | S2TTE_BLOCK_NS);
469}
470
471/*
472 * Validate the portion of NS S2TTE that is provided by the host.
473 */
474bool host_ns_s2tte_is_valid(unsigned long s2tte, long level)
475{
476 unsigned long mask = addr_level_mask(~0UL, level) |
477 S2TTE_MEMATTR_MASK |
478 S2TTE_AP_MASK |
479 S2TTE_SH_MASK;
480
481 /*
482 * Test that all fields that are not controlled by the host are zero
483 * and that the output address is correctly aligned. Note that
484 * the host is permitted to map any physical address outside PAR.
485 */
486 if ((s2tte & ~mask) != 0UL) {
487 return false;
488 }
489
490 /*
491 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
492 */
493 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
494 return false;
495 }
496
497 /*
498 * Only one value masked by S2TTE_SH_MASK is invalid/reserved.
499 */
500 if ((s2tte & S2TTE_SH_MASK) == S2TTE_SH_RESERVED) {
501 return false;
502 }
503
504 /*
505 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
506 */
507 return true;
508}
509
510/*
511 * Returns the portion of NS S2TTE that is set by the host.
512 */
513unsigned long host_ns_s2tte(unsigned long s2tte, long level)
514{
515 unsigned long mask = addr_level_mask(~0UL, level) |
516 S2TTE_MEMATTR_MASK |
517 S2TTE_AP_MASK |
518 S2TTE_SH_MASK;
519 return (s2tte & mask);
520}
521
522/*
523 * Creates a table s2tte at level @level with output address @pa.
524 */
525unsigned long s2tte_create_table(unsigned long pa, long level)
526{
527 assert(level < RTT_PAGE_LEVEL);
528 assert(GRANULE_ALIGNED(pa));
529
530 return (pa | S2TTE_TABLE);
531}
532
533/*
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100534 * Returns true if s2tte has defined ripas value, namely if it is one of:
535 * - unassigned_empty
536 * - unassigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100537 * - unassigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100538 * - assigned_empty
539 * - assigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100540 * - assigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100541 */
542bool s2tte_has_ripas(unsigned long s2tte, long level)
543{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100544 return (((s2tte & S2TTE_NS) == 0UL) && !s2tte_is_table(s2tte, level));
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100545}
546
547/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000548 * Returns true if @s2tte has HIPAS=@hipas.
549 */
550static bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
551{
552 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
553 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
554
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100555 return ((desc_type == S2TTE_Lx_INVALID) && (invalid_desc_hipas == hipas));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000556}
557
558/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100559 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000560 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100561static bool s2tte_has_unassigned_ripas(unsigned long s2tte, unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000562{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100563 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
564 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
565}
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100566
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100567/*
568 * Returns true if @s2tte has HIPAS=ASSIGNED and RIPAS=@ripas.
569 */
570static bool s2tte_has_assigned_ripas(unsigned long s2tte, unsigned long ripas)
571{
572 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
573 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100574}
575
576/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100577 * Returns true if @s2tte has HIPAS=UNASSIGNED.
578 */
579bool s2tte_is_unassigned(unsigned long s2tte)
580{
581 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED);
582}
583
584/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100585 * Returns true if @s2tte is an unassigned_empty.
586 */
587bool s2tte_is_unassigned_empty(unsigned long s2tte)
588{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100589 return (((s2tte & S2TTE_NS) == 0UL) &&
590 s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100591}
592
593/*
594 * Returns true if @s2tte is an unassigned_ram.
595 */
596bool s2tte_is_unassigned_ram(unsigned long s2tte)
597{
598 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
599}
600
601/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100602 * Returns true if @s2tte is unassigned_ns.
603 */
604bool s2tte_is_unassigned_ns(unsigned long s2tte)
605{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100606 return (((s2tte & S2TTE_NS) != 0UL) &&
607 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000608}
609
610/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100611 * Returns true if @s2tte has RIPAS=DESTROYED.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000612 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100613bool s2tte_is_unassigned_destroyed(unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000614{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100615 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
616}
617
618/*
619 * Returns true if @s2tte is an assigned_destroyed.
620 */
621bool s2tte_is_assigned_destroyed(unsigned long s2tte, long level)
622{
623 (void)level;
624
625 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000626}
627
628/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100629 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000630 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100631bool s2tte_is_assigned_empty(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000632{
633 (void)level;
634
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100635 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000636}
637
638static bool s2tte_check(unsigned long s2tte, long level, unsigned long ns)
639{
640 unsigned long desc_type;
641
642 if ((s2tte & S2TTE_NS) != ns) {
643 return false;
644 }
645
646 desc_type = s2tte & DESC_TYPE_MASK;
647
648 /* Only pages at L3 and valid blocks at L2 allowed */
649 if (((level == RTT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000650 ((level == RTT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK))) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000651 return true;
652 }
653
654 return false;
655}
656
657/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100658 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000659 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100660bool s2tte_is_assigned_ram(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000661{
662 return s2tte_check(s2tte, level, 0UL);
663}
664
665/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100666 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000667 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100668bool s2tte_is_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000669{
670 return s2tte_check(s2tte, level, S2TTE_NS);
671}
672
673/*
674 * Returns true if @s2tte is a table at level @level.
675 */
676bool s2tte_is_table(unsigned long s2tte, long level)
677{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100678 return ((level < RTT_PAGE_LEVEL) &&
679 ((s2tte & DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000680}
681
682/*
683 * Returns RIPAS of @s2tte.
684 *
685 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
686 * The s2tte must be not valid/invalid descriptor.
687 */
688enum ripas s2tte_get_ripas(unsigned long s2tte)
689{
690 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
691
692 /*
693 * If valid s2tte descriptor is passed, then ensure S2AP[0]
694 * bit is 1 (S2AP is set to RW for lower EL), which corresponds
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100695 * to RIPAS_RAM (bits[6:5] = b01) on a valid descriptor.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000696 */
697 if (((s2tte & DESC_TYPE_MASK) != S2TTE_Lx_INVALID) &&
698 (desc_ripas != S2TTE_INVALID_RIPAS_RAM)) {
699 assert(false);
700 }
701
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100702 switch (desc_ripas) {
703 case S2TTE_INVALID_RIPAS_EMPTY:
Yousuf A62808152022-10-31 10:35:42 +0000704 return RIPAS_EMPTY;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100705 case S2TTE_INVALID_RIPAS_RAM:
706 return RIPAS_RAM;
707 default:
708 assert(desc_ripas == S2TTE_INVALID_RIPAS_DESTROYED);
709 return RIPAS_DESTROYED;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000710 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000711}
712
713/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100714 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000715 *
716 * The granule is populated before it is made a table,
717 * hence, don't use s2tte_write for access.
718 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100719void s2tt_init_unassigned_empty(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000720{
721 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100722 s2tt[i] = s2tte_create_unassigned_empty();
723 }
724
725 dsb(ish);
726}
727
728/*
729 * Populates @s2tt with unassigned_ram s2ttes.
730 *
731 * The granule is populated before it is made a table,
732 * hence, don't use s2tte_write for access.
733 */
734void s2tt_init_unassigned_ram(unsigned long *s2tt)
735{
736 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
737 s2tt[i] = s2tte_create_unassigned_ram();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000738 }
739
740 dsb(ish);
741}
742
743/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100744 * Populates @s2tt with unassigned_ns s2ttes.
745 *
746 * The granule is populated before it is made a table,
747 * hence, don't use s2tte_write for access.
748 */
749void s2tt_init_unassigned_ns(unsigned long *s2tt)
750{
751 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
752 s2tt[i] = s2tte_create_unassigned_ns();
753 }
754
755 dsb(ish);
756}
757
758/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000759 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
760 *
761 * The granule is populated before it is made a table,
762 * hence, don't use s2tte_write for access.
763 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100764void s2tt_init_unassigned_destroyed(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000765{
766 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100767 s2tt[i] = s2tte_create_unassigned_destroyed();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000768 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100769 dsb(ish);
770}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000771
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100772/*
773 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
774 * contiguous memory block starting at @pa, and mapped at level @level.
775 *
776 * The granule is populated before it is made a table,
777 * hence, don't use s2tte_write for access.
778 */
779void s2tt_init_assigned_destroyed(unsigned long *s2tt, unsigned long pa, long level)
780{
781 const unsigned long map_size = s2tte_map_size(level);
782
783 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
784 s2tt[i] = s2tte_create_assigned_destroyed(pa, level);
785 pa += map_size;
786 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000787 dsb(ish);
788}
789
790unsigned long s2tte_map_size(int level)
791{
792 int levels, lsb;
793
794 assert(level <= RTT_PAGE_LEVEL);
795
796 levels = RTT_PAGE_LEVEL - level;
797 lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100798 return (1UL << lsb);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000799}
800
801/*
802 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
803 * contiguous memory block starting at @pa, and mapped at level @level.
804 *
805 * The granule is populated before it is made a table,
806 * hence, don't use s2tte_write for access.
807 */
808void s2tt_init_assigned_empty(unsigned long *s2tt, unsigned long pa, long level)
809{
810 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000811
AlexeiFedorov3a739332023-04-13 13:54:04 +0100812 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000813 s2tt[i] = s2tte_create_assigned_empty(pa, level);
814 pa += map_size;
815 }
816 dsb(ish);
817}
818
819/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100820 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000821 * contiguous memory block starting at @pa, and mapped at level @level.
822 *
823 * The granule is populated before it is made a table,
824 * hence, don't use s2tte_write for access.
825 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100826void s2tt_init_assigned_ram(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000827{
828 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000829
AlexeiFedorov3a739332023-04-13 13:54:04 +0100830 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
831 s2tt[i] = s2tte_create_assigned_ram(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000832 pa += map_size;
833 }
834 dsb(ish);
835}
836
837/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100838 * Populates @s2tt with assigned_ns s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000839 * contiguous memory block starting at @pa, and mapped at level @level.
840 *
841 * The granule is populated before it is made a table,
842 * hence, don't use s2tte_write for access.
843 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100844void s2tt_init_assigned_ns(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000845{
846 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000847
AlexeiFedorov3a739332023-04-13 13:54:04 +0100848 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
849 s2tt[i] = s2tte_create_assigned_ns(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000850 pa += map_size;
851 }
852 dsb(ish);
853}
854
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100855/*
856 * Returns true if s2tte has 'output address' field, namely, if it is one of:
857 * - assigned_empty
858 * - assigned_ram
859 * - assigned_ns
860 * - table
861 */
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100862bool s2tte_has_pa(unsigned long s2tte, long level)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100863{
864 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
865
866 /*
867 * Block, page or table
868 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100869 return ((desc_type != S2TTE_INVALID) ||
870 s2tte_is_assigned_empty(s2tte, level));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100871}
872
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100873/*
874 * Returns true if s2tte is a live RTTE entry. i.e.,
875 * neither UNASSIGNED nor DESTROYED.
876 *
877 * NOTE: For now, only the RTTE with PA are live.
878 * This could change with EXPORT/IMPORT support.
879 */
880bool s2tte_is_live(unsigned long s2tte, long level)
881{
882 return s2tte_has_pa(s2tte, level);
883}
884
Soby Mathewb4c6df42022-11-09 11:13:29 +0000885/* Returns physical address of a page entry or block */
886unsigned long s2tte_pa(unsigned long s2tte, long level)
887{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100888 if (!s2tte_has_pa(s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000889 assert(false);
890 }
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100891
892 if (s2tte_is_table(s2tte, level)) {
893 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
894 }
895
Soby Mathewb4c6df42022-11-09 11:13:29 +0000896 return addr_level_mask(s2tte, level);
897}
898
899/* Returns physical address of a table entry */
900unsigned long s2tte_pa_table(unsigned long s2tte, long level)
901{
902 assert(s2tte_is_table(s2tte, level));
903 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
904}
905
906bool addr_is_level_aligned(unsigned long addr, long level)
907{
908 return (addr == addr_level_mask(addr, level));
909}
910
911typedef bool (*s2tte_type_checker)(unsigned long s2tte);
912
913static bool __table_is_uniform_block(unsigned long *table,
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100914 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000915{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100916 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
917 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000918
919 if (!s2tte_is_x(s2tte)) {
920 return false;
921 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000922 }
923
924 return true;
925}
926
927/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100928 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000929 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100930bool table_is_unassigned_empty_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000931{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100932 return __table_is_uniform_block(table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100933}
934
935/*
936 * Returns true if all s2ttes in @table are unassigned_ram.
937 */
938bool table_is_unassigned_ram_block(unsigned long *table)
939{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100940 return __table_is_uniform_block(table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000941}
942
943/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100944 * Returns true if all s2ttes in @table are unassigned_ns
945 */
946bool table_is_unassigned_ns_block(unsigned long *table)
947{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100948 return __table_is_uniform_block(table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100949}
950
951/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100952 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +0000953 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100954bool table_is_unassigned_destroyed_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000955{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100956 return __table_is_uniform_block(table, s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000957}
958
959typedef bool (*s2tte_type_level_checker)(unsigned long s2tte, long level);
960
961static bool __table_maps_block(unsigned long *table,
962 long level,
963 s2tte_type_level_checker s2tte_is_x)
964{
965 unsigned long base_pa;
966 unsigned long map_size = s2tte_map_size(level);
967 unsigned long s2tte = s2tte_read(&table[0]);
968 unsigned int i;
969
970 if (!s2tte_is_x(s2tte, level)) {
971 return false;
972 }
973
974 base_pa = s2tte_pa(s2tte, level);
975 if (!addr_is_level_aligned(base_pa, level - 1L)) {
976 return false;
977 }
978
979 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
980 unsigned long expected_pa = base_pa + (i * map_size);
981
982 s2tte = s2tte_read(&table[i]);
983
984 if (!s2tte_is_x(s2tte, level)) {
985 return false;
986 }
987
988 if (s2tte_pa(s2tte, level) != expected_pa) {
989 return false;
990 }
991 }
992
993 return true;
994}
995
996/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100997 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +0000998 * and refer to a contiguous block of granules aligned to @level - 1.
999 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001000bool table_maps_assigned_empty_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001001{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001002 return __table_maps_block(table, level, s2tte_is_assigned_empty);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001003}
1004
1005/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001006 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001007 * refer to a contiguous block of granules aligned to @level - 1.
1008 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001009bool table_maps_assigned_ram_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001010{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001011 return __table_maps_block(table, level, s2tte_is_assigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001012}
1013
1014/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001015 * Returns true if all s2ttes in @table are assigned_ns s2ttes and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001016 * refer to a contiguous block of granules aligned to @level - 1.
AlexeiFedorov3a739332023-04-13 13:54:04 +01001017 *
1018 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001019 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001020bool table_maps_assigned_ns_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001021{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001022 return __table_maps_block(table, level, s2tte_is_assigned_ns);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001023}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001024
1025/*
1026 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
1027 * skip the non-live entries (i.e., HIPAS is either UNASSIGNED or DESTROYED).
1028 * In other words, the scanning stops when a live RTTE is encountered or we
1029 * reach the end of this RTT.
1030 *
1031 * For now an RTTE can be considered non-live if it doesn't have a PA.
1032 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1033 * in the RTTE.
1034 *
1035 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1036 * with RMI_ERROR_RTT).
1037 *
1038 * Returns:
1039 * - If the entry @wi.index is live, returns @addr.
1040 * - If none of the entries in the @s2tt are "live", returns the address of the
1041 * first entry in the next table.
1042 * - Otherwise, the address of the first live entry in @s2tt
1043 */
1044unsigned long skip_non_live_entries(unsigned long addr,
1045 unsigned long *s2tt,
1046 const struct rtt_walk *wi)
1047{
1048 unsigned int i, index = wi->index;
1049 long level = wi->last_level;
1050 unsigned long map_size;
1051
1052 /*
1053 * If the entry for the map_addr is live,
1054 * return @addr.
1055 */
1056 if (s2tte_is_live(s2tte_read(&s2tt[index]), level)) {
1057 return addr;
1058 }
1059
1060 /*
1061 * Align the address DOWN to the map_size, as expected for the @level,
1062 * so that we can compute the correct address by using the index.
1063 */
1064 map_size = s2tte_map_size(level);
1065 addr &= ~(map_size - 1UL);
1066
1067 /* Skip the "index" */
1068 for (i = index + 1U; i < S2TTES_PER_S2TT; i++) {
1069 unsigned long s2tte = s2tte_read(&s2tt[i]);
1070
1071 if (s2tte_is_live(s2tte, level)) {
1072 break;
1073 }
1074 }
1075
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001076 return (addr + (i - index) * map_size);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001077}