blob: 6b6a9aef383d123405d4d3acbbc10cb833bc7c9e [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/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100577 * Returns true if @s2tte is an unassigned_empty.
578 */
579bool s2tte_is_unassigned_empty(unsigned long s2tte)
580{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100581 return (((s2tte & S2TTE_NS) == 0UL) &&
582 s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100583}
584
585/*
586 * Returns true if @s2tte is an unassigned_ram.
587 */
588bool s2tte_is_unassigned_ram(unsigned long s2tte)
589{
590 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
591}
592
593/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100594 * Returns true if @s2tte is unassigned_ns.
595 */
596bool s2tte_is_unassigned_ns(unsigned long s2tte)
597{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100598 return (((s2tte & S2TTE_NS) != 0UL) &&
599 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000600}
601
602/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100603 * Returns true if @s2tte has RIPAS=DESTROYED.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000604 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100605bool s2tte_is_unassigned_destroyed(unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000606{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100607 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
608}
609
610/*
611 * Returns true if @s2tte is an assigned_destroyed.
612 */
613bool s2tte_is_assigned_destroyed(unsigned long s2tte, long level)
614{
615 (void)level;
616
617 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000618}
619
620/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100621 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000622 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100623bool s2tte_is_assigned_empty(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000624{
625 (void)level;
626
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100627 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000628}
629
630static bool s2tte_check(unsigned long s2tte, long level, unsigned long ns)
631{
632 unsigned long desc_type;
633
634 if ((s2tte & S2TTE_NS) != ns) {
635 return false;
636 }
637
638 desc_type = s2tte & DESC_TYPE_MASK;
639
640 /* Only pages at L3 and valid blocks at L2 allowed */
641 if (((level == RTT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000642 ((level == RTT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK))) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000643 return true;
644 }
645
646 return false;
647}
648
649/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100650 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000651 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100652bool s2tte_is_assigned_ram(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000653{
654 return s2tte_check(s2tte, level, 0UL);
655}
656
657/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100658 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000659 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100660bool s2tte_is_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000661{
662 return s2tte_check(s2tte, level, S2TTE_NS);
663}
664
665/*
666 * Returns true if @s2tte is a table at level @level.
667 */
668bool s2tte_is_table(unsigned long s2tte, long level)
669{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100670 return ((level < RTT_PAGE_LEVEL) &&
671 ((s2tte & DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000672}
673
674/*
675 * Returns RIPAS of @s2tte.
676 *
677 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
678 * The s2tte must be not valid/invalid descriptor.
679 */
680enum ripas s2tte_get_ripas(unsigned long s2tte)
681{
682 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
683
684 /*
685 * If valid s2tte descriptor is passed, then ensure S2AP[0]
686 * bit is 1 (S2AP is set to RW for lower EL), which corresponds
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100687 * to RIPAS_RAM (bits[6:5] = b01) on a valid descriptor.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000688 */
689 if (((s2tte & DESC_TYPE_MASK) != S2TTE_Lx_INVALID) &&
690 (desc_ripas != S2TTE_INVALID_RIPAS_RAM)) {
691 assert(false);
692 }
693
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100694 switch (desc_ripas) {
695 case S2TTE_INVALID_RIPAS_EMPTY:
Yousuf A62808152022-10-31 10:35:42 +0000696 return RIPAS_EMPTY;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100697 case S2TTE_INVALID_RIPAS_RAM:
698 return RIPAS_RAM;
699 default:
700 assert(desc_ripas == S2TTE_INVALID_RIPAS_DESTROYED);
701 return RIPAS_DESTROYED;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000702 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000703}
704
705/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100706 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000707 *
708 * The granule is populated before it is made a table,
709 * hence, don't use s2tte_write for access.
710 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100711void s2tt_init_unassigned_empty(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000712{
713 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100714 s2tt[i] = s2tte_create_unassigned_empty();
715 }
716
717 dsb(ish);
718}
719
720/*
721 * Populates @s2tt with unassigned_ram s2ttes.
722 *
723 * The granule is populated before it is made a table,
724 * hence, don't use s2tte_write for access.
725 */
726void s2tt_init_unassigned_ram(unsigned long *s2tt)
727{
728 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
729 s2tt[i] = s2tte_create_unassigned_ram();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000730 }
731
732 dsb(ish);
733}
734
735/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100736 * Populates @s2tt with unassigned_ns s2ttes.
737 *
738 * The granule is populated before it is made a table,
739 * hence, don't use s2tte_write for access.
740 */
741void s2tt_init_unassigned_ns(unsigned long *s2tt)
742{
743 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
744 s2tt[i] = s2tte_create_unassigned_ns();
745 }
746
747 dsb(ish);
748}
749
750/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000751 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
752 *
753 * The granule is populated before it is made a table,
754 * hence, don't use s2tte_write for access.
755 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100756void s2tt_init_unassigned_destroyed(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000757{
758 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100759 s2tt[i] = s2tte_create_unassigned_destroyed();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000760 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100761 dsb(ish);
762}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000763
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100764/*
765 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
766 * contiguous memory block starting at @pa, and mapped at level @level.
767 *
768 * The granule is populated before it is made a table,
769 * hence, don't use s2tte_write for access.
770 */
771void s2tt_init_assigned_destroyed(unsigned long *s2tt, unsigned long pa, long level)
772{
773 const unsigned long map_size = s2tte_map_size(level);
774
775 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
776 s2tt[i] = s2tte_create_assigned_destroyed(pa, level);
777 pa += map_size;
778 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000779 dsb(ish);
780}
781
782unsigned long s2tte_map_size(int level)
783{
784 int levels, lsb;
785
786 assert(level <= RTT_PAGE_LEVEL);
787
788 levels = RTT_PAGE_LEVEL - level;
789 lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100790 return (1UL << lsb);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000791}
792
793/*
794 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
795 * contiguous memory block starting at @pa, and mapped at level @level.
796 *
797 * The granule is populated before it is made a table,
798 * hence, don't use s2tte_write for access.
799 */
800void s2tt_init_assigned_empty(unsigned long *s2tt, unsigned long pa, long level)
801{
802 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000803
AlexeiFedorov3a739332023-04-13 13:54:04 +0100804 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000805 s2tt[i] = s2tte_create_assigned_empty(pa, level);
806 pa += map_size;
807 }
808 dsb(ish);
809}
810
811/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100812 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000813 * contiguous memory block starting at @pa, and mapped at level @level.
814 *
815 * The granule is populated before it is made a table,
816 * hence, don't use s2tte_write for access.
817 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100818void s2tt_init_assigned_ram(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000819{
820 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000821
AlexeiFedorov3a739332023-04-13 13:54:04 +0100822 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
823 s2tt[i] = s2tte_create_assigned_ram(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000824 pa += map_size;
825 }
826 dsb(ish);
827}
828
829/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100830 * Populates @s2tt with assigned_ns s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000831 * contiguous memory block starting at @pa, and mapped at level @level.
832 *
833 * The granule is populated before it is made a table,
834 * hence, don't use s2tte_write for access.
835 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100836void s2tt_init_assigned_ns(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000837{
838 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000839
AlexeiFedorov3a739332023-04-13 13:54:04 +0100840 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
841 s2tt[i] = s2tte_create_assigned_ns(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000842 pa += map_size;
843 }
844 dsb(ish);
845}
846
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100847/*
848 * Returns true if s2tte has 'output address' field, namely, if it is one of:
849 * - assigned_empty
850 * - assigned_ram
851 * - assigned_ns
852 * - table
853 */
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100854bool s2tte_has_pa(unsigned long s2tte, long level)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100855{
856 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
857
858 /*
859 * Block, page or table
860 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100861 return ((desc_type != S2TTE_INVALID) ||
862 s2tte_is_assigned_empty(s2tte, level));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100863}
864
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100865/*
866 * Returns true if s2tte is a live RTTE entry. i.e.,
867 * neither UNASSIGNED nor DESTROYED.
868 *
869 * NOTE: For now, only the RTTE with PA are live.
870 * This could change with EXPORT/IMPORT support.
871 */
872bool s2tte_is_live(unsigned long s2tte, long level)
873{
874 return s2tte_has_pa(s2tte, level);
875}
876
Soby Mathewb4c6df42022-11-09 11:13:29 +0000877/* Returns physical address of a page entry or block */
878unsigned long s2tte_pa(unsigned long s2tte, long level)
879{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100880 if (!s2tte_has_pa(s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000881 assert(false);
882 }
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100883
884 if (s2tte_is_table(s2tte, level)) {
885 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
886 }
887
Soby Mathewb4c6df42022-11-09 11:13:29 +0000888 return addr_level_mask(s2tte, level);
889}
890
891/* Returns physical address of a table entry */
892unsigned long s2tte_pa_table(unsigned long s2tte, long level)
893{
894 assert(s2tte_is_table(s2tte, level));
895 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
896}
897
898bool addr_is_level_aligned(unsigned long addr, long level)
899{
900 return (addr == addr_level_mask(addr, level));
901}
902
903typedef bool (*s2tte_type_checker)(unsigned long s2tte);
904
905static bool __table_is_uniform_block(unsigned long *table,
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100906 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000907{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100908 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
909 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000910
911 if (!s2tte_is_x(s2tte)) {
912 return false;
913 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000914 }
915
916 return true;
917}
918
919/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100920 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000921 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100922bool table_is_unassigned_empty_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000923{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100924 return __table_is_uniform_block(table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100925}
926
927/*
928 * Returns true if all s2ttes in @table are unassigned_ram.
929 */
930bool table_is_unassigned_ram_block(unsigned long *table)
931{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100932 return __table_is_uniform_block(table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000933}
934
935/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100936 * Returns true if all s2ttes in @table are unassigned_ns
937 */
938bool table_is_unassigned_ns_block(unsigned long *table)
939{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100940 return __table_is_uniform_block(table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100941}
942
943/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100944 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +0000945 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100946bool table_is_unassigned_destroyed_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000947{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100948 return __table_is_uniform_block(table, s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000949}
950
951typedef bool (*s2tte_type_level_checker)(unsigned long s2tte, long level);
952
953static bool __table_maps_block(unsigned long *table,
954 long level,
955 s2tte_type_level_checker s2tte_is_x)
956{
957 unsigned long base_pa;
958 unsigned long map_size = s2tte_map_size(level);
959 unsigned long s2tte = s2tte_read(&table[0]);
960 unsigned int i;
961
962 if (!s2tte_is_x(s2tte, level)) {
963 return false;
964 }
965
966 base_pa = s2tte_pa(s2tte, level);
967 if (!addr_is_level_aligned(base_pa, level - 1L)) {
968 return false;
969 }
970
971 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
972 unsigned long expected_pa = base_pa + (i * map_size);
973
974 s2tte = s2tte_read(&table[i]);
975
976 if (!s2tte_is_x(s2tte, level)) {
977 return false;
978 }
979
980 if (s2tte_pa(s2tte, level) != expected_pa) {
981 return false;
982 }
983 }
984
985 return true;
986}
987
988/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100989 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +0000990 * and refer to a contiguous block of granules aligned to @level - 1.
991 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100992bool table_maps_assigned_empty_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000993{
AlexeiFedorov3a739332023-04-13 13:54:04 +0100994 return __table_maps_block(table, level, s2tte_is_assigned_empty);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000995}
996
997/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100998 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +0000999 * refer to a contiguous block of granules aligned to @level - 1.
1000 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001001bool table_maps_assigned_ram_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001002{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001003 return __table_maps_block(table, level, s2tte_is_assigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001004}
1005
1006/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001007 * Returns true if all s2ttes in @table are assigned_ns s2ttes and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001008 * refer to a contiguous block of granules aligned to @level - 1.
AlexeiFedorov3a739332023-04-13 13:54:04 +01001009 *
1010 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001011 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001012bool table_maps_assigned_ns_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001013{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001014 return __table_maps_block(table, level, s2tte_is_assigned_ns);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001015}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001016
1017/*
1018 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
1019 * skip the non-live entries (i.e., HIPAS is either UNASSIGNED or DESTROYED).
1020 * In other words, the scanning stops when a live RTTE is encountered or we
1021 * reach the end of this RTT.
1022 *
1023 * For now an RTTE can be considered non-live if it doesn't have a PA.
1024 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1025 * in the RTTE.
1026 *
1027 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1028 * with RMI_ERROR_RTT).
1029 *
1030 * Returns:
1031 * - If the entry @wi.index is live, returns @addr.
1032 * - If none of the entries in the @s2tt are "live", returns the address of the
1033 * first entry in the next table.
1034 * - Otherwise, the address of the first live entry in @s2tt
1035 */
1036unsigned long skip_non_live_entries(unsigned long addr,
1037 unsigned long *s2tt,
1038 const struct rtt_walk *wi)
1039{
1040 unsigned int i, index = wi->index;
1041 long level = wi->last_level;
1042 unsigned long map_size;
1043
1044 /*
1045 * If the entry for the map_addr is live,
1046 * return @addr.
1047 */
1048 if (s2tte_is_live(s2tte_read(&s2tt[index]), level)) {
1049 return addr;
1050 }
1051
1052 /*
1053 * Align the address DOWN to the map_size, as expected for the @level,
1054 * so that we can compute the correct address by using the index.
1055 */
1056 map_size = s2tte_map_size(level);
1057 addr &= ~(map_size - 1UL);
1058
1059 /* Skip the "index" */
1060 for (i = index + 1U; i < S2TTES_PER_S2TT; i++) {
1061 unsigned long s2tte = s2tte_read(&s2tt[i]);
1062
1063 if (s2tte_is_live(s2tte, level)) {
1064 break;
1065 }
1066 }
1067
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001068 return (addr + (i - index) * map_size);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001069}