blob: 471a0243edf16d190cf5fd62e7e7176ac4a691dc [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
32#define DESC_TYPE_MASK 0x3UL
33#define S2TTE_L012_TABLE 0x3UL
34#define S2TTE_L012_BLOCK 0x1UL
35#define S2TTE_L3_PAGE 0x3UL
36#define S2TTE_Lx_INVALID 0x0UL
37
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)
75#define S2TTE_INVALID 0
76
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]
81 * 4. HIPAS field [5:2]
82 * 4. RIPAS field [6]
83 * 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
107#define S2TTE_INVALID_HIPAS_WIDTH 4
108#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))
112#define S2TTE_INVALID_HIPAS_DESTROYED (INPLACE(S2TTE_INVALID_HIPAS, 2))
113
114#define S2TTE_INVALID_RIPAS_SHIFT 6
115#define S2TTE_INVALID_RIPAS_WIDTH 1
116#define S2TTE_INVALID_RIPAS_MASK MASK(S2TTE_INVALID_RIPAS)
117
118#define S2TTE_INVALID_RIPAS_EMPTY (INPLACE(S2TTE_INVALID_RIPAS, 0))
119#define S2TTE_INVALID_RIPAS_RAM (INPLACE(S2TTE_INVALID_RIPAS, 1))
120
121#define S2TTE_INVALID_DESTROYED S2TTE_INVALID_HIPAS_DESTROYED
122#define S2TTE_INVALID_UNPROTECTED 0x0UL
123
124#define NR_RTT_LEVELS 4
125
126/*
127 * Invalidates S2 TLB entries from [ipa, ipa + size] region tagged with `vmid`.
128 */
129static void stage2_tlbi_ipa(const struct realm_s2_context *s2_ctx,
130 unsigned long ipa,
131 unsigned long size)
132{
133 /*
134 * Notes:
135 *
136 * - This follows the description provided in the Arm ARM on
137 * "Invalidation of TLB entries from stage 2 translations".
138 *
139 * - @TODO: Provide additional information to this primitive so that
140 * we can utilize:
141 * - The TTL level hint, see FEAT_TTL,
142 * - Final level lookup only invalidation,
143 * - Address range invalidation.
144 */
145
146 /*
147 * Save the current content of vttb_el2.
148 */
149 unsigned long old_vttbr_el2 = read_vttbr_el2();
150
151 /*
152 * Make 'vmid' the `current vmid`. Note that the tlbi instructions
153 * bellow target the TLB entries that match the `current vmid`.
154 */
155 write_vttbr_el2(INPLACE(VTTBR_EL2_VMID, s2_ctx->vmid));
156 isb();
157
158 /*
159 * Invalidate entries in S2 TLB caches that
160 * match both `ipa` & the `current vmid`.
161 */
162 while (size != 0UL) {
163 tlbiipas2e1is(ipa >> 12);
164 size -= GRANULE_SIZE;
165 ipa += GRANULE_SIZE;
166 }
167 dsb(ish);
168
169 /*
170 * The architecture does not require TLB invalidation by IPA to affect
171 * combined Stage-1 + Stage-2 TLBs. Therefore we must invalidate all of
172 * Stage-1 (tagged with the `current vmid`) after invalidating Stage-2.
173 */
174 tlbivmalle1is();
175 dsb(ish);
176 isb();
177
178 /*
179 * Restore the old content of vttb_el2.
180 */
181 write_vttbr_el2(old_vttbr_el2);
182 isb();
183}
184
185/*
186 * Invalidate S2 TLB entries with "addr" IPA.
187 * Call this function after:
188 * 1. A L3 page desc has been removed.
189 */
190void invalidate_page(const struct realm_s2_context *s2_ctx, unsigned long addr)
191{
192 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
193}
194
195/*
196 * Invalidate S2 TLB entries with "addr" IPA.
197 * Call this function after:
198 * 1. A L2 block desc has been removed, or
199 * 2a. A L2 table desc has been removed, where
200 * 2b. All S2TTEs in L3 table that the L2 table desc was pointed to were invalid.
201 */
202void invalidate_block(const struct realm_s2_context *s2_ctx, unsigned long addr)
203{
204 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
205}
206
207/*
208 * Invalidate S2 TLB entries with "addr" IPA.
209 * Call this function after:
210 * 1a. A L2 table desc has been removed, where
211 * 1b. Some S2TTEs in the table that the L2 table desc was pointed to were valid.
212 */
213void invalidate_pages_in_block(const struct realm_s2_context *s2_ctx, unsigned long addr)
214{
215 stage2_tlbi_ipa(s2_ctx, addr, BLOCK_L2_SIZE);
216}
217
218/*
219 * Return the index of the entry describing @addr in the translation table at
220 * level @level. This only works for non-concatenated page tables, so should
221 * not be called to get the index for the starting level.
222 *
223 * See the library pseudocode
224 * aarch64/translation/vmsa_addrcalc/AArch64.TTEntryAddress on which this is
225 * modeled.
226 */
227static unsigned long s2_addr_to_idx(unsigned long addr, long level)
228{
229 int levels = RTT_PAGE_LEVEL - level;
230 int lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
231
232 addr >>= lsb;
233 addr &= (1UL << S2TTE_STRIDE) - 1;
234 return addr;
235}
236
237/*
238 * Return the index of the entry describing @addr in the translation table
239 * starting level. This may return an index >= S2TTES_PER_S2TT when the
240 * combination of @start_level and @ipa_bits implies concatenated
241 * stage 2 tables.
242 *
243 * See the library pseudocode
244 * aarch64/translation/vmsa_addrcalc/AArch64.S2SLTTEntryAddress on which
245 * this is modeled.
246 */
247static unsigned long s2_sl_addr_to_idx(unsigned long addr, int start_level,
248 unsigned long ipa_bits)
249{
250 int levels = RTT_PAGE_LEVEL - start_level;
251 int lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
252
253 addr &= (1UL << ipa_bits) - 1UL;
254 addr >>= lsb;
255 return addr;
256}
257
258static unsigned long addr_level_mask(unsigned long addr, long level)
259{
260 int levels = RTT_PAGE_LEVEL - level;
261 unsigned int lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
262 unsigned int msb = S2TTE_OA_BITS - 1;
263
264 return addr & BIT_MASK_ULL(msb, lsb);
265}
266
267static inline unsigned long table_entry_to_phys(unsigned long entry)
268{
269 return addr_level_mask(entry, RTT_PAGE_LEVEL);
270}
271
272static inline bool entry_is_table(unsigned long entry)
273{
274 return (entry & DESC_TYPE_MASK) == S2TTE_L012_TABLE;
275}
276
277static unsigned long __table_get_entry(struct granule *g_tbl,
278 unsigned long idx)
279{
280 unsigned long *table, entry;
281
282 table = granule_map(g_tbl, SLOT_RTT);
283 entry = s2tte_read(&table[idx]);
284 buffer_unmap(table);
285
286 return entry;
287}
288
289static struct granule *__find_next_level_idx(struct granule *g_tbl,
290 unsigned long idx)
291{
292 const unsigned long entry = __table_get_entry(g_tbl, idx);
293
294 if (!entry_is_table(entry)) {
295 return NULL;
296 }
297
298 return addr_to_granule(table_entry_to_phys(entry));
299}
300
301static struct granule *__find_lock_next_level(struct granule *g_tbl,
302 unsigned long map_addr,
303 long level)
304{
305 const unsigned long idx = s2_addr_to_idx(map_addr, level);
306 struct granule *g = __find_next_level_idx(g_tbl, idx);
307
308 if (g != NULL) {
309 granule_lock(g, GRANULE_STATE_RTT);
310 }
311
312 return g;
313}
314
315/*
316 * Walk an RTT until level @level using @map_addr.
317 * @g_root is the root (level 0) table and must be locked before the call.
318 * @start_level is the initial lookup level used for the stage 2 translation
319 * tables which may depend on the configuration of the realm, factoring in the
320 * IPA size of the realm and the desired starting level (within the limits
321 * defined by the Armv8 VMSA including options for stage 2 table concatenation).
322 * The function uses hand-over-hand locking to avoid race conditions and allow
323 * concurrent access to RTT tree which is not part of the current walk; when a
324 * next level table is reached it is locked before releasing previously locked
325 * table.
326 * The walk stops when either:
327 * - The entry found is a leaf entry (not an RTT Table entry), or
328 * - Level @level is reached.
329 *
330 * On return:
331 * - rtt_walk::last_level is the last level that has been reached by the walk.
332 * - rtt_walk.g_llt points to the TABLE granule at level @rtt_walk::level.
333 * The granule is locked.
334 * - rtt_walk::index is the entry index at rtt_walk.g_llt for @map_addr.
335 */
336void rtt_walk_lock_unlock(struct granule *g_root,
337 int start_level,
338 unsigned long ipa_bits,
339 unsigned long map_addr,
340 long level,
341 struct rtt_walk *wi)
342{
343 struct granule *g_tbls[NR_RTT_LEVELS] = { NULL };
344 unsigned long sl_idx;
345 int i, last_level;
346
347 assert(start_level >= MIN_STARTING_LEVEL);
348 assert(level >= start_level);
349 assert(map_addr < (1UL << ipa_bits));
350 assert(wi != NULL);
351
352 /* Handle concatenated starting level (SL) tables */
353 sl_idx = s2_sl_addr_to_idx(map_addr, start_level, ipa_bits);
354 if (sl_idx >= S2TTES_PER_S2TT) {
355 unsigned int tt_num = (sl_idx >> S2TTE_STRIDE);
356 struct granule *g_concat_root = g_root + tt_num;
357
358 granule_lock(g_concat_root, GRANULE_STATE_RTT);
359 granule_unlock(g_root);
360 g_root = g_concat_root;
361 }
362
363 g_tbls[start_level] = g_root;
364 for (i = start_level; i < level; i++) {
365 /*
366 * Lock next RTT level. Correct locking order is guaranteed
367 * because reference is obtained from a locked granule
368 * (previous level). Also, hand-over-hand locking/unlocking is
369 * used to avoid race conditions.
370 */
371 g_tbls[i + 1] = __find_lock_next_level(g_tbls[i], map_addr, i);
372 if (g_tbls[i + 1] == NULL) {
373 last_level = i;
374 goto out;
375 }
376 granule_unlock(g_tbls[i]);
377 }
378
379 last_level = level;
380out:
381 wi->last_level = last_level;
382 wi->g_llt = g_tbls[last_level];
383 wi->index = s2_addr_to_idx(map_addr, last_level);
384}
385
386/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100387 * Creates an unassigned_empty s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000388 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100389unsigned long s2tte_create_unassigned_empty(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000390{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100391 return S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_EMPTY;
392}
393
394/*
395 * Creates an unassigned_ram s2tte.
396 */
397unsigned long s2tte_create_unassigned_ram(void)
398{
399 return S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_RAM;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000400}
401
402/*
403 * Creates an invalid s2tte with HIPAS=DESTROYED.
404 */
405unsigned long s2tte_create_destroyed(void)
406{
407 return S2TTE_INVALID_DESTROYED;
408}
409
410/*
411 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
412 * RIPAS=EMPTY, at level @level.
413 */
414unsigned long s2tte_create_assigned_empty(unsigned long pa, long level)
415{
416 assert(level >= RTT_MIN_BLOCK_LEVEL);
417 assert(addr_is_level_aligned(pa, level));
418 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
419}
420
421/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100422 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000423 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100424unsigned long s2tte_create_assigned_ram(unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000425{
426 assert(level >= RTT_MIN_BLOCK_LEVEL);
427 assert(addr_is_level_aligned(pa, level));
428 if (level == RTT_PAGE_LEVEL) {
429 return (pa | S2TTE_PAGE);
430 }
431 return (pa | S2TTE_BLOCK);
432}
433
434/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100435 * Creates an unassigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000436 */
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100437unsigned long s2tte_create_unassigned_ns(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000438{
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100439 return S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED |
440 S2TTE_INVALID_UNPROTECTED;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000441}
442
443/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100444 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000445 *
446 * The following S2 TTE fields are provided through @s2tte argument:
447 * - The physical address
448 * - MemAttr
449 * - S2AP
450 * - Shareability
451 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100452unsigned long s2tte_create_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000453{
454 assert(level >= RTT_MIN_BLOCK_LEVEL);
455 if (level == RTT_PAGE_LEVEL) {
456 return (s2tte | S2TTE_PAGE_NS);
457 }
458 return (s2tte | S2TTE_BLOCK_NS);
459}
460
461/*
462 * Validate the portion of NS S2TTE that is provided by the host.
463 */
464bool host_ns_s2tte_is_valid(unsigned long s2tte, long level)
465{
466 unsigned long mask = addr_level_mask(~0UL, level) |
467 S2TTE_MEMATTR_MASK |
468 S2TTE_AP_MASK |
469 S2TTE_SH_MASK;
470
471 /*
472 * Test that all fields that are not controlled by the host are zero
473 * and that the output address is correctly aligned. Note that
474 * the host is permitted to map any physical address outside PAR.
475 */
476 if ((s2tte & ~mask) != 0UL) {
477 return false;
478 }
479
480 /*
481 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
482 */
483 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
484 return false;
485 }
486
487 /*
488 * Only one value masked by S2TTE_SH_MASK is invalid/reserved.
489 */
490 if ((s2tte & S2TTE_SH_MASK) == S2TTE_SH_RESERVED) {
491 return false;
492 }
493
494 /*
495 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
496 */
497 return true;
498}
499
500/*
501 * Returns the portion of NS S2TTE that is set by the host.
502 */
503unsigned long host_ns_s2tte(unsigned long s2tte, long level)
504{
505 unsigned long mask = addr_level_mask(~0UL, level) |
506 S2TTE_MEMATTR_MASK |
507 S2TTE_AP_MASK |
508 S2TTE_SH_MASK;
509 return (s2tte & mask);
510}
511
512/*
513 * Creates a table s2tte at level @level with output address @pa.
514 */
515unsigned long s2tte_create_table(unsigned long pa, long level)
516{
517 assert(level < RTT_PAGE_LEVEL);
518 assert(GRANULE_ALIGNED(pa));
519
520 return (pa | S2TTE_TABLE);
521}
522
523/*
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100524 * Returns true if s2tte has defined ripas value, namely if it is one of:
525 * - unassigned_empty
526 * - unassigned_ram
527 * - assigned_empty
528 * - assigned_ram
529 */
530bool s2tte_has_ripas(unsigned long s2tte, long level)
531{
532 if (s2tte_is_table(s2tte, level) || s2tte_is_destroyed(s2tte) ||
533 ((s2tte & S2TTE_NS) != 0UL)) {
534 return false;
535 }
536 return true;
537}
538
539/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000540 * Returns true if @s2tte has HIPAS=@hipas.
541 */
542static bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
543{
544 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
545 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
546
547 if ((desc_type != S2TTE_Lx_INVALID) || (invalid_desc_hipas != hipas)) {
548 return false;
549 }
550 return true;
551}
552
553/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100554 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000555 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100556static bool s2tte_has_unassigned_ripas(unsigned long s2tte, unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000557{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100558 unsigned long invalid_desc_ripas;
559
560 if (!s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED)) {
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100561 return false;
562 }
563
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100564 invalid_desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
565 return (invalid_desc_ripas == ripas);
566}
567
568/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100569 * Returns true if @s2tte is an unassigned_empty.
570 */
571bool s2tte_is_unassigned_empty(unsigned long s2tte)
572{
573 if (!s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY)) {
574 return false;
575 }
576
577 return ((s2tte & S2TTE_NS) == 0UL);
578}
579
580/*
581 * Returns true if @s2tte is an unassigned_ram.
582 */
583bool s2tte_is_unassigned_ram(unsigned long s2tte)
584{
585 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
586}
587
588/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100589 * Returns true if @s2tte is unassigned_ns.
590 */
591bool s2tte_is_unassigned_ns(unsigned long s2tte)
592{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100593 if (!s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED)) {
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100594 return false;
595 }
596
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100597 return ((s2tte & S2TTE_NS) != 0UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000598}
599
600/*
601 * Returns true if @s2tte has HIPAS=DESTROYED.
602 */
603bool s2tte_is_destroyed(unsigned long s2tte)
604{
605 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_DESTROYED);
606}
607
608/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100609 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000610 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100611bool s2tte_is_assigned_empty(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000612{
613 (void)level;
614
615 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED);
616}
617
618static bool s2tte_check(unsigned long s2tte, long level, unsigned long ns)
619{
620 unsigned long desc_type;
621
622 if ((s2tte & S2TTE_NS) != ns) {
623 return false;
624 }
625
626 desc_type = s2tte & DESC_TYPE_MASK;
627
628 /* Only pages at L3 and valid blocks at L2 allowed */
629 if (((level == RTT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000630 ((level == RTT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK))) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000631 return true;
632 }
633
634 return false;
635}
636
637/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100638 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000639 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100640bool s2tte_is_assigned_ram(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000641{
642 return s2tte_check(s2tte, level, 0UL);
643}
644
645/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100646 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000647 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100648bool s2tte_is_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000649{
650 return s2tte_check(s2tte, level, S2TTE_NS);
651}
652
653/*
654 * Returns true if @s2tte is a table at level @level.
655 */
656bool s2tte_is_table(unsigned long s2tte, long level)
657{
658 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
659
660 if ((level < RTT_PAGE_LEVEL) && (desc_type == S2TTE_TABLE)) {
661 return true;
662 }
663
664 return false;
665}
666
667/*
668 * Returns RIPAS of @s2tte.
669 *
670 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
671 * The s2tte must be not valid/invalid descriptor.
672 */
673enum ripas s2tte_get_ripas(unsigned long s2tte)
674{
675 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
676
677 /*
678 * If valid s2tte descriptor is passed, then ensure S2AP[0]
679 * bit is 1 (S2AP is set to RW for lower EL), which corresponds
680 * to RIPAS_RAM (bit[6]) on a valid descriptor.
681 */
682 if (((s2tte & DESC_TYPE_MASK) != S2TTE_Lx_INVALID) &&
683 (desc_ripas != S2TTE_INVALID_RIPAS_RAM)) {
684 assert(false);
685 }
686
687 if (desc_ripas == S2TTE_INVALID_RIPAS_EMPTY) {
Yousuf A62808152022-10-31 10:35:42 +0000688 return RIPAS_EMPTY;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000689 }
690
Yousuf A62808152022-10-31 10:35:42 +0000691 return RIPAS_RAM;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000692}
693
694/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100695 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000696 *
697 * The granule is populated before it is made a table,
698 * hence, don't use s2tte_write for access.
699 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100700void s2tt_init_unassigned_empty(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000701{
702 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100703 s2tt[i] = s2tte_create_unassigned_empty();
704 }
705
706 dsb(ish);
707}
708
709/*
710 * Populates @s2tt with unassigned_ram s2ttes.
711 *
712 * The granule is populated before it is made a table,
713 * hence, don't use s2tte_write for access.
714 */
715void s2tt_init_unassigned_ram(unsigned long *s2tt)
716{
717 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
718 s2tt[i] = s2tte_create_unassigned_ram();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000719 }
720
721 dsb(ish);
722}
723
724/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100725 * Populates @s2tt with unassigned_ns s2ttes.
726 *
727 * The granule is populated before it is made a table,
728 * hence, don't use s2tte_write for access.
729 */
730void s2tt_init_unassigned_ns(unsigned long *s2tt)
731{
732 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
733 s2tt[i] = s2tte_create_unassigned_ns();
734 }
735
736 dsb(ish);
737}
738
739/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000740 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
741 *
742 * The granule is populated before it is made a table,
743 * hence, don't use s2tte_write for access.
744 */
745void s2tt_init_destroyed(unsigned long *s2tt)
746{
747 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
748 s2tt[i] = s2tte_create_destroyed();
749 }
750
751 dsb(ish);
752}
753
754unsigned long s2tte_map_size(int level)
755{
756 int levels, lsb;
757
758 assert(level <= RTT_PAGE_LEVEL);
759
760 levels = RTT_PAGE_LEVEL - level;
761 lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
762 return 1UL << lsb;
763}
764
765/*
766 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
767 * contiguous memory block starting at @pa, and mapped at level @level.
768 *
769 * The granule is populated before it is made a table,
770 * hence, don't use s2tte_write for access.
771 */
772void s2tt_init_assigned_empty(unsigned long *s2tt, unsigned long pa, long level)
773{
774 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000775
AlexeiFedorov3a739332023-04-13 13:54:04 +0100776 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000777 s2tt[i] = s2tte_create_assigned_empty(pa, level);
778 pa += map_size;
779 }
780 dsb(ish);
781}
782
783/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100784 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000785 * contiguous memory block starting at @pa, and mapped at level @level.
786 *
787 * The granule is populated before it is made a table,
788 * hence, don't use s2tte_write for access.
789 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100790void s2tt_init_assigned_ram(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000791{
792 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000793
AlexeiFedorov3a739332023-04-13 13:54:04 +0100794 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
795 s2tt[i] = s2tte_create_assigned_ram(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000796 pa += map_size;
797 }
798 dsb(ish);
799}
800
801/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100802 * Populates @s2tt with assigned_ns s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000803 * 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 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100808void s2tt_init_assigned_ns(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000809{
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++) {
813 s2tt[i] = s2tte_create_assigned_ns(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000814 pa += map_size;
815 }
816 dsb(ish);
817}
818
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100819/*
820 * Returns true if s2tte has 'output address' field, namely, if it is one of:
821 * - assigned_empty
822 * - assigned_ram
823 * - assigned_ns
824 * - table
825 */
826static bool s2tte_has_pa(unsigned long s2tte, long level)
827{
828 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
829
830 /*
831 * Block, page or table
832 */
833 if ((desc_type != S2TTE_INVALID) ||
834 s2tte_is_assigned_empty(s2tte, level)) {
835 return true;
836 }
837
838 return false;
839}
840
Soby Mathewb4c6df42022-11-09 11:13:29 +0000841/* Returns physical address of a page entry or block */
842unsigned long s2tte_pa(unsigned long s2tte, long level)
843{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100844 if (!s2tte_has_pa(s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000845 assert(false);
846 }
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100847
848 if (s2tte_is_table(s2tte, level)) {
849 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
850 }
851
Soby Mathewb4c6df42022-11-09 11:13:29 +0000852 return addr_level_mask(s2tte, level);
853}
854
855/* Returns physical address of a table entry */
856unsigned long s2tte_pa_table(unsigned long s2tte, long level)
857{
858 assert(s2tte_is_table(s2tte, level));
859 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
860}
861
862bool addr_is_level_aligned(unsigned long addr, long level)
863{
864 return (addr == addr_level_mask(addr, level));
865}
866
867typedef bool (*s2tte_type_checker)(unsigned long s2tte);
868
869static bool __table_is_uniform_block(unsigned long *table,
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100870 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000871{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100872 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
873 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000874
875 if (!s2tte_is_x(s2tte)) {
876 return false;
877 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000878 }
879
880 return true;
881}
882
883/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100884 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000885 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100886bool table_is_unassigned_empty_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000887{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100888 return __table_is_uniform_block(table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100889}
890
891/*
892 * Returns true if all s2ttes in @table are unassigned_ram.
893 */
894bool table_is_unassigned_ram_block(unsigned long *table)
895{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100896 return __table_is_uniform_block(table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000897}
898
899/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100900 * Returns true if all s2ttes in @table are unassigned_ns
901 */
902bool table_is_unassigned_ns_block(unsigned long *table)
903{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100904 return __table_is_uniform_block(table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100905}
906
907/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000908 * Returns true if all s2ttes in @table have HIPAS=DESTROYED.
909 */
910bool table_is_destroyed_block(unsigned long *table)
911{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100912 return __table_is_uniform_block(table, s2tte_is_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000913}
914
915typedef bool (*s2tte_type_level_checker)(unsigned long s2tte, long level);
916
917static bool __table_maps_block(unsigned long *table,
918 long level,
919 s2tte_type_level_checker s2tte_is_x)
920{
921 unsigned long base_pa;
922 unsigned long map_size = s2tte_map_size(level);
923 unsigned long s2tte = s2tte_read(&table[0]);
924 unsigned int i;
925
926 if (!s2tte_is_x(s2tte, level)) {
927 return false;
928 }
929
930 base_pa = s2tte_pa(s2tte, level);
931 if (!addr_is_level_aligned(base_pa, level - 1L)) {
932 return false;
933 }
934
935 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
936 unsigned long expected_pa = base_pa + (i * map_size);
937
938 s2tte = s2tte_read(&table[i]);
939
940 if (!s2tte_is_x(s2tte, level)) {
941 return false;
942 }
943
944 if (s2tte_pa(s2tte, level) != expected_pa) {
945 return false;
946 }
947 }
948
949 return true;
950}
951
952/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100953 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +0000954 * and refer to a contiguous block of granules aligned to @level - 1.
955 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100956bool table_maps_assigned_empty_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000957{
AlexeiFedorov3a739332023-04-13 13:54:04 +0100958 return __table_maps_block(table, level, s2tte_is_assigned_empty);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000959}
960
961/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100962 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +0000963 * refer to a contiguous block of granules aligned to @level - 1.
964 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100965bool table_maps_assigned_ram_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000966{
AlexeiFedorov3a739332023-04-13 13:54:04 +0100967 return __table_maps_block(table, level, s2tte_is_assigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000968}
969
970/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100971 * Returns true if all s2ttes in @table are assigned_ns s2ttes and
Soby Mathewb4c6df42022-11-09 11:13:29 +0000972 * refer to a contiguous block of granules aligned to @level - 1.
AlexeiFedorov3a739332023-04-13 13:54:04 +0100973 *
974 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000975 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100976bool table_maps_assigned_ns_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000977{
AlexeiFedorov3a739332023-04-13 13:54:04 +0100978 return __table_maps_block(table, level, s2tte_is_assigned_ns);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000979}