blob: f42200100b1f14b072bb1cabafbf869c150eecbf [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/*
387 * Creates a value which can be OR'd with an s2tte to set RIPAS=@ripas.
388 */
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100389unsigned long s2tte_create_ripas(enum ripas ripas_val)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000390{
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100391 if (ripas_val == RIPAS_EMPTY) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000392 return S2TTE_INVALID_RIPAS_EMPTY;
393 }
394 return S2TTE_INVALID_RIPAS_RAM;
395}
396
397/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100398 * Creates an unassigned_empty s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000399 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100400unsigned long s2tte_create_unassigned_empty(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000401{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100402 return S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_EMPTY;
403}
404
405/*
406 * Creates an unassigned_ram s2tte.
407 */
408unsigned long s2tte_create_unassigned_ram(void)
409{
410 return S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_RAM;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000411}
412
413/*
414 * Creates an invalid s2tte with HIPAS=DESTROYED.
415 */
416unsigned long s2tte_create_destroyed(void)
417{
418 return S2TTE_INVALID_DESTROYED;
419}
420
421/*
422 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
423 * RIPAS=EMPTY, at level @level.
424 */
425unsigned long s2tte_create_assigned_empty(unsigned long pa, long level)
426{
427 assert(level >= RTT_MIN_BLOCK_LEVEL);
428 assert(addr_is_level_aligned(pa, level));
429 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
430}
431
432/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100433 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000434 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100435unsigned long s2tte_create_assigned_ram(unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000436{
437 assert(level >= RTT_MIN_BLOCK_LEVEL);
438 assert(addr_is_level_aligned(pa, level));
439 if (level == RTT_PAGE_LEVEL) {
440 return (pa | S2TTE_PAGE);
441 }
442 return (pa | S2TTE_BLOCK);
443}
444
445/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100446 * Creates an unassigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000447 */
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100448unsigned long s2tte_create_unassigned_ns(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000449{
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100450 return S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED |
451 S2TTE_INVALID_UNPROTECTED;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000452}
453
454/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100455 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000456 *
457 * The following S2 TTE fields are provided through @s2tte argument:
458 * - The physical address
459 * - MemAttr
460 * - S2AP
461 * - Shareability
462 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100463unsigned long s2tte_create_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000464{
465 assert(level >= RTT_MIN_BLOCK_LEVEL);
466 if (level == RTT_PAGE_LEVEL) {
467 return (s2tte | S2TTE_PAGE_NS);
468 }
469 return (s2tte | S2TTE_BLOCK_NS);
470}
471
472/*
473 * Validate the portion of NS S2TTE that is provided by the host.
474 */
475bool host_ns_s2tte_is_valid(unsigned long s2tte, long level)
476{
477 unsigned long mask = addr_level_mask(~0UL, level) |
478 S2TTE_MEMATTR_MASK |
479 S2TTE_AP_MASK |
480 S2TTE_SH_MASK;
481
482 /*
483 * Test that all fields that are not controlled by the host are zero
484 * and that the output address is correctly aligned. Note that
485 * the host is permitted to map any physical address outside PAR.
486 */
487 if ((s2tte & ~mask) != 0UL) {
488 return false;
489 }
490
491 /*
492 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
493 */
494 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
495 return false;
496 }
497
498 /*
499 * Only one value masked by S2TTE_SH_MASK is invalid/reserved.
500 */
501 if ((s2tte & S2TTE_SH_MASK) == S2TTE_SH_RESERVED) {
502 return false;
503 }
504
505 /*
506 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
507 */
508 return true;
509}
510
511/*
512 * Returns the portion of NS S2TTE that is set by the host.
513 */
514unsigned long host_ns_s2tte(unsigned long s2tte, long level)
515{
516 unsigned long mask = addr_level_mask(~0UL, level) |
517 S2TTE_MEMATTR_MASK |
518 S2TTE_AP_MASK |
519 S2TTE_SH_MASK;
520 return (s2tte & mask);
521}
522
523/*
524 * Creates a table s2tte at level @level with output address @pa.
525 */
526unsigned long s2tte_create_table(unsigned long pa, long level)
527{
528 assert(level < RTT_PAGE_LEVEL);
529 assert(GRANULE_ALIGNED(pa));
530
531 return (pa | S2TTE_TABLE);
532}
533
534/*
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100535 * Returns true if s2tte has defined ripas value, namely if it is one of:
536 * - unassigned_empty
537 * - unassigned_ram
538 * - assigned_empty
539 * - assigned_ram
540 */
541bool s2tte_has_ripas(unsigned long s2tte, long level)
542{
543 if (s2tte_is_table(s2tte, level) || s2tte_is_destroyed(s2tte) ||
544 ((s2tte & S2TTE_NS) != 0UL)) {
545 return false;
546 }
547 return true;
548}
549
550/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000551 * Returns true if @s2tte has HIPAS=@hipas.
552 */
553static bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
554{
555 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
556 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
557
558 if ((desc_type != S2TTE_Lx_INVALID) || (invalid_desc_hipas != hipas)) {
559 return false;
560 }
561 return true;
562}
563
564/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100565 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000566 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100567static bool s2tte_has_unassigned_ripas(unsigned long s2tte, unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000568{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100569 unsigned long invalid_desc_ripas;
570
571 if (!s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED)) {
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100572 return false;
573 }
574
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100575 invalid_desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
576 return (invalid_desc_ripas == ripas);
577}
578
579/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100580 * Returns true if @s2tte is an unassigned_empty.
581 */
582bool s2tte_is_unassigned_empty(unsigned long s2tte)
583{
584 if (!s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY)) {
585 return false;
586 }
587
588 return ((s2tte & S2TTE_NS) == 0UL);
589}
590
591/*
592 * Returns true if @s2tte is an unassigned_ram.
593 */
594bool s2tte_is_unassigned_ram(unsigned long s2tte)
595{
596 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
597}
598
599/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100600 * Returns true if @s2tte is unassigned_ns.
601 */
602bool s2tte_is_unassigned_ns(unsigned long s2tte)
603{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100604 if (!s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED)) {
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100605 return false;
606 }
607
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100608 return ((s2tte & S2TTE_NS) != 0UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000609}
610
611/*
612 * Returns true if @s2tte has HIPAS=DESTROYED.
613 */
614bool s2tte_is_destroyed(unsigned long s2tte)
615{
616 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_DESTROYED);
617}
618
619/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100620 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000621 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100622bool s2tte_is_assigned_empty(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000623{
624 (void)level;
625
626 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED);
627}
628
629static bool s2tte_check(unsigned long s2tte, long level, unsigned long ns)
630{
631 unsigned long desc_type;
632
633 if ((s2tte & S2TTE_NS) != ns) {
634 return false;
635 }
636
637 desc_type = s2tte & DESC_TYPE_MASK;
638
639 /* Only pages at L3 and valid blocks at L2 allowed */
640 if (((level == RTT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000641 ((level == RTT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK))) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000642 return true;
643 }
644
645 return false;
646}
647
648/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100649 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000650 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100651bool s2tte_is_assigned_ram(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000652{
653 return s2tte_check(s2tte, level, 0UL);
654}
655
656/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100657 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000658 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100659bool s2tte_is_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000660{
661 return s2tte_check(s2tte, level, S2TTE_NS);
662}
663
664/*
665 * Returns true if @s2tte is a table at level @level.
666 */
667bool s2tte_is_table(unsigned long s2tte, long level)
668{
669 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
670
671 if ((level < RTT_PAGE_LEVEL) && (desc_type == S2TTE_TABLE)) {
672 return true;
673 }
674
675 return false;
676}
677
678/*
679 * Returns RIPAS of @s2tte.
680 *
681 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
682 * The s2tte must be not valid/invalid descriptor.
683 */
684enum ripas s2tte_get_ripas(unsigned long s2tte)
685{
686 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
687
688 /*
689 * If valid s2tte descriptor is passed, then ensure S2AP[0]
690 * bit is 1 (S2AP is set to RW for lower EL), which corresponds
691 * to RIPAS_RAM (bit[6]) on a valid descriptor.
692 */
693 if (((s2tte & DESC_TYPE_MASK) != S2TTE_Lx_INVALID) &&
694 (desc_ripas != S2TTE_INVALID_RIPAS_RAM)) {
695 assert(false);
696 }
697
698 if (desc_ripas == S2TTE_INVALID_RIPAS_EMPTY) {
Yousuf A62808152022-10-31 10:35:42 +0000699 return RIPAS_EMPTY;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000700 }
701
Yousuf A62808152022-10-31 10:35:42 +0000702 return RIPAS_RAM;
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 */
756void s2tt_init_destroyed(unsigned long *s2tt)
757{
758 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
759 s2tt[i] = s2tte_create_destroyed();
760 }
761
762 dsb(ish);
763}
764
765unsigned long s2tte_map_size(int level)
766{
767 int levels, lsb;
768
769 assert(level <= RTT_PAGE_LEVEL);
770
771 levels = RTT_PAGE_LEVEL - level;
772 lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
773 return 1UL << lsb;
774}
775
776/*
777 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
778 * contiguous memory block starting at @pa, and mapped at level @level.
779 *
780 * The granule is populated before it is made a table,
781 * hence, don't use s2tte_write for access.
782 */
783void s2tt_init_assigned_empty(unsigned long *s2tt, unsigned long pa, long level)
784{
785 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000786
AlexeiFedorov3a739332023-04-13 13:54:04 +0100787 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000788 s2tt[i] = s2tte_create_assigned_empty(pa, level);
789 pa += map_size;
790 }
791 dsb(ish);
792}
793
794/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100795 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000796 * contiguous memory block starting at @pa, and mapped at level @level.
797 *
798 * The granule is populated before it is made a table,
799 * hence, don't use s2tte_write for access.
800 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100801void s2tt_init_assigned_ram(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000802{
803 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000804
AlexeiFedorov3a739332023-04-13 13:54:04 +0100805 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
806 s2tt[i] = s2tte_create_assigned_ram(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000807 pa += map_size;
808 }
809 dsb(ish);
810}
811
812/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100813 * Populates @s2tt with assigned_ns s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000814 * contiguous memory block starting at @pa, and mapped at level @level.
815 *
816 * The granule is populated before it is made a table,
817 * hence, don't use s2tte_write for access.
818 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100819void s2tt_init_assigned_ns(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000820{
821 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000822
AlexeiFedorov3a739332023-04-13 13:54:04 +0100823 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
824 s2tt[i] = s2tte_create_assigned_ns(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000825 pa += map_size;
826 }
827 dsb(ish);
828}
829
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100830/*
831 * Returns true if s2tte has 'output address' field, namely, if it is one of:
832 * - assigned_empty
833 * - assigned_ram
834 * - assigned_ns
835 * - table
836 */
837static bool s2tte_has_pa(unsigned long s2tte, long level)
838{
839 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
840
841 /*
842 * Block, page or table
843 */
844 if ((desc_type != S2TTE_INVALID) ||
845 s2tte_is_assigned_empty(s2tte, level)) {
846 return true;
847 }
848
849 return false;
850}
851
Soby Mathewb4c6df42022-11-09 11:13:29 +0000852/* Returns physical address of a page entry or block */
853unsigned long s2tte_pa(unsigned long s2tte, long level)
854{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100855 if (!s2tte_has_pa(s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000856 assert(false);
857 }
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100858
859 if (s2tte_is_table(s2tte, level)) {
860 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
861 }
862
Soby Mathewb4c6df42022-11-09 11:13:29 +0000863 return addr_level_mask(s2tte, level);
864}
865
866/* Returns physical address of a table entry */
867unsigned long s2tte_pa_table(unsigned long s2tte, long level)
868{
869 assert(s2tte_is_table(s2tte, level));
870 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
871}
872
873bool addr_is_level_aligned(unsigned long addr, long level)
874{
875 return (addr == addr_level_mask(addr, level));
876}
877
878typedef bool (*s2tte_type_checker)(unsigned long s2tte);
879
880static bool __table_is_uniform_block(unsigned long *table,
881 s2tte_type_checker s2tte_is_x,
882 enum ripas *ripas_ptr)
883{
884 unsigned long s2tte = s2tte_read(&table[0]);
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100885 enum ripas ripas_val;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000886 unsigned int i;
887
888 if (!s2tte_is_x(s2tte)) {
889 return false;
890 }
891
892 if (ripas_ptr != NULL) {
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100893 ripas_val = s2tte_get_ripas(s2tte);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000894 }
895
896 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
897 s2tte = s2tte_read(&table[i]);
898
899 if (!s2tte_is_x(s2tte)) {
900 return false;
901 }
902
903 if ((ripas_ptr != NULL) &&
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100904 (s2tte_get_ripas(s2tte) != ripas_val)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000905 return false;
906 }
907 }
908
909 if (ripas_ptr != NULL) {
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100910 *ripas_ptr = ripas_val;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000911 }
912
913 return true;
914}
915
916/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100917 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000918 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100919bool table_is_unassigned_empty_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000920{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100921 return __table_is_uniform_block(table, s2tte_is_unassigned_empty, NULL);
922}
923
924/*
925 * Returns true if all s2ttes in @table are unassigned_ram.
926 */
927bool table_is_unassigned_ram_block(unsigned long *table)
928{
929 return __table_is_uniform_block(table, s2tte_is_unassigned_ram, NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000930}
931
932/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100933 * Returns true if all s2ttes in @table are unassigned_ns
934 */
935bool table_is_unassigned_ns_block(unsigned long *table)
936{
937 return __table_is_uniform_block(table, s2tte_is_unassigned_ns, NULL);
938}
939
940/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000941 * Returns true if all s2ttes in @table have HIPAS=DESTROYED.
942 */
943bool table_is_destroyed_block(unsigned long *table)
944{
945 return __table_is_uniform_block(table, s2tte_is_destroyed, NULL);
946}
947
948typedef bool (*s2tte_type_level_checker)(unsigned long s2tte, long level);
949
950static bool __table_maps_block(unsigned long *table,
951 long level,
952 s2tte_type_level_checker s2tte_is_x)
953{
954 unsigned long base_pa;
955 unsigned long map_size = s2tte_map_size(level);
956 unsigned long s2tte = s2tte_read(&table[0]);
957 unsigned int i;
958
959 if (!s2tte_is_x(s2tte, level)) {
960 return false;
961 }
962
963 base_pa = s2tte_pa(s2tte, level);
964 if (!addr_is_level_aligned(base_pa, level - 1L)) {
965 return false;
966 }
967
968 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
969 unsigned long expected_pa = base_pa + (i * map_size);
970
971 s2tte = s2tte_read(&table[i]);
972
973 if (!s2tte_is_x(s2tte, level)) {
974 return false;
975 }
976
977 if (s2tte_pa(s2tte, level) != expected_pa) {
978 return false;
979 }
980 }
981
982 return true;
983}
984
985/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100986 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +0000987 * and refer to a contiguous block of granules aligned to @level - 1.
988 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100989bool table_maps_assigned_empty_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000990{
AlexeiFedorov3a739332023-04-13 13:54:04 +0100991 return __table_maps_block(table, level, s2tte_is_assigned_empty);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000992}
993
994/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100995 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +0000996 * refer to a contiguous block of granules aligned to @level - 1.
997 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100998bool table_maps_assigned_ram_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000999{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001000 return __table_maps_block(table, level, s2tte_is_assigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001001}
1002
1003/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001004 * Returns true if all s2ttes in @table are assigned_ns s2ttes and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001005 * refer to a contiguous block of granules aligned to @level - 1.
AlexeiFedorov3a739332023-04-13 13:54:04 +01001006 *
1007 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001008 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001009bool table_maps_assigned_ns_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_ns);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001012}