blob: c36655c0a525c38f5e14806106f84229c3ff1082 [file] [log] [blame]
Soby Mathewb4c6df42022-11-09 11:13:29 +00001/*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
6#include <arch_helpers.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +00007#include <bitmap.h>
8#include <buffer.h>
9#include <gic.h>
10#include <granule.h>
11#include <memory_alloc.h>
12#include <realm.h>
13#include <ripas.h>
14#include <smc.h>
15#include <status.h>
16#include <stddef.h>
17#include <string.h>
18#include <table.h>
19
20/*
21 * For prototyping we assume 4K pages
22 */
23#define BLOCK_L2_SIZE (GRANULE_SIZE * S2TTES_PER_S2TT)
24
25/*
26 * The maximum number of bits supported by the RMM for a stage 2 translation
27 * output address (including stage 2 table entries).
28 */
AlexeiFedorov93f5ec52023-08-31 14:26:53 +010029#define S2TTE_OA_BITS 48U
Soby Mathewb4c6df42022-11-09 11:13:29 +000030
AlexeiFedorovc53b1f72023-07-04 15:37:03 +010031#define DESC_TYPE_MASK 3UL
32#define S2TTE_Lx_INVALID 0UL
33#define S2TTE_L012_BLOCK 1UL
34#define S2TTE_L012_TABLE 3UL
35#define S2TTE_L3_PAGE 3UL
Soby Mathewb4c6df42022-11-09 11:13:29 +000036
37/*
38 * The following constants for the mapping attributes (S2_TTE_MEMATTR_*)
39 * assume that HCR_EL2.FWB is set.
40 */
41#define S2TTE_MEMATTR_SHIFT 2
42#define S2TTE_MEMATTR_MASK (0x7UL << S2TTE_MEMATTR_SHIFT)
43#define S2TTE_MEMATTR_FWB_NORMAL_WB ((1UL << 4) | (2UL << 2))
44#define S2TTE_MEMATTR_FWB_RESERVED ((1UL << 4) | (0UL << 2))
45
46#define S2TTE_AP_SHIFT 6
47#define S2TTE_AP_MASK (3UL << S2TTE_AP_SHIFT)
48#define S2TTE_AP_RW (3UL << S2TTE_AP_SHIFT)
49
50#define S2TTE_SH_SHIFT 8
51#define S2TTE_SH_MASK (3UL << S2TTE_SH_SHIFT)
52#define S2TTE_SH_NS (0UL << S2TTE_SH_SHIFT)
53#define S2TTE_SH_RESERVED (1UL << S2TTE_SH_SHIFT)
54#define S2TTE_SH_OS (2UL << S2TTE_SH_SHIFT)
55#define S2TTE_SH_IS (3UL << S2TTE_SH_SHIFT) /* Inner Shareable */
56
57/*
58 * We set HCR_EL2.FWB So we set bit[4] to 1 and bits[3:2] to 2 and force
59 * everyting to be Normal Write-Back
60 */
61#define S2TTE_MEMATTR_FWB_NORMAL_WB ((1UL << 4) | (2UL << 2))
62#define S2TTE_AF (1UL << 10)
63#define S2TTE_XN (2UL << 53)
64#define S2TTE_NS (1UL << 55)
65
66#define S2TTE_ATTRS (S2TTE_MEMATTR_FWB_NORMAL_WB | S2TTE_AP_RW | \
67 S2TTE_SH_IS | S2TTE_AF)
68
69#define S2TTE_TABLE S2TTE_L012_TABLE
70#define S2TTE_BLOCK (S2TTE_ATTRS | S2TTE_L012_BLOCK)
71#define S2TTE_PAGE (S2TTE_ATTRS | S2TTE_L3_PAGE)
72#define S2TTE_BLOCK_NS (S2TTE_NS | S2TTE_XN | S2TTE_AF | S2TTE_L012_BLOCK)
73#define S2TTE_PAGE_NS (S2TTE_NS | S2TTE_XN | S2TTE_AF | S2TTE_L3_PAGE)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +010074#define S2TTE_INVALID S2TTE_Lx_INVALID
Soby Mathewb4c6df42022-11-09 11:13:29 +000075
76/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +010077 * The type of stage 2 translation table entry (s2tte) is defined by:
78 * 1. Table level where it resides
79 * 2. DESC_TYPE field[1:0]
AlexeiFedorovc53b1f72023-07-04 15:37:03 +010080 * 4. HIPAS field [4:2]
81 * 4. RIPAS field [6:5]
AlexeiFedorov5ceff352023-04-12 16:17:00 +010082 * 5. NS field [55]
Soby Mathewb4c6df42022-11-09 11:13:29 +000083 *
AlexeiFedorov63614ea2023-07-14 17:07:20 +010084 * ======================================================================================
85 * s2tte type level DESC_TYPE[1:0] HIPAS[4:2] RIPAS[6:5] NS OA alignment
86 * ======================================================================================
87 * unassigned_empty any invalid[0] unassigned[0] empty[0] 0 n/a
88 * --------------------------------------------------------------------------------------
89 * unassigned_ram any invalid[0] unassigned[0] ram[1] 0 n/a
90 * --------------------------------------------------------------------------------------
91 * unassigned_destroyed any invalid[0] unassigned[0] destroyed[2] 0 n/a
92 * --------------------------------------------------------------------------------------
93 * assigned_empty 2,3 invalid[0] assigned[1] empty[0] 0 to level
94 * --------------------------------------------------------------------------------------
95 * assigned_ram 3 page[3] n/a n/a 0 to level
96 * 2 block[1] n/a n/a 0 to level
97 * --------------------------------------------------------------------------------------
98 * assigned_destroyed any invalid[0] assigned[1] destroyed[2] 0 n/a
99 * ======================================================================================
100 * unassigned_ns any invalid[0] unassigned[0] n/a 1 n/a
101 * --------------------------------------------------------------------------------------
102 * assigned_ns 3 page[3] n/a n/a 1 to level
103 * 2 block[1] n/a n/a 1 to level
104 * ======================================================================================
105 * table <=2 table[3] n/a n/a n/a to 4K
106 * ======================================================================================
Soby Mathewb4c6df42022-11-09 11:13:29 +0000107 */
108
109#define S2TTE_INVALID_HIPAS_SHIFT 2
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100110#define S2TTE_INVALID_HIPAS_WIDTH 3U
Soby Mathewb4c6df42022-11-09 11:13:29 +0000111#define S2TTE_INVALID_HIPAS_MASK MASK(S2TTE_INVALID_HIPAS)
112
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100113#define S2TTE_INVALID_HIPAS_UNASSIGNED (INPLACE(S2TTE_INVALID_HIPAS, 0UL))
114#define S2TTE_INVALID_HIPAS_ASSIGNED (INPLACE(S2TTE_INVALID_HIPAS, 1UL))
Soby Mathewb4c6df42022-11-09 11:13:29 +0000115
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100116#define S2TTE_INVALID_RIPAS_SHIFT 5
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100117#define S2TTE_INVALID_RIPAS_WIDTH 2U
Soby Mathewb4c6df42022-11-09 11:13:29 +0000118#define S2TTE_INVALID_RIPAS_MASK MASK(S2TTE_INVALID_RIPAS)
119
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100120#define S2TTE_INVALID_RIPAS_EMPTY (INPLACE(S2TTE_INVALID_RIPAS, 0UL))
121#define S2TTE_INVALID_RIPAS_RAM (INPLACE(S2TTE_INVALID_RIPAS, 1UL))
122#define S2TTE_INVALID_RIPAS_DESTROYED (INPLACE(S2TTE_INVALID_RIPAS, 2UL))
Soby Mathewb4c6df42022-11-09 11:13:29 +0000123
Soby Mathewb4c6df42022-11-09 11:13:29 +0000124#define S2TTE_INVALID_UNPROTECTED 0x0UL
125
126#define NR_RTT_LEVELS 4
127
128/*
129 * Invalidates S2 TLB entries from [ipa, ipa + size] region tagged with `vmid`.
130 */
131static void stage2_tlbi_ipa(const struct realm_s2_context *s2_ctx,
132 unsigned long ipa,
133 unsigned long size)
134{
135 /*
136 * Notes:
137 *
138 * - This follows the description provided in the Arm ARM on
139 * "Invalidation of TLB entries from stage 2 translations".
140 *
141 * - @TODO: Provide additional information to this primitive so that
142 * we can utilize:
143 * - The TTL level hint, see FEAT_TTL,
144 * - Final level lookup only invalidation,
145 * - Address range invalidation.
146 */
147
148 /*
149 * Save the current content of vttb_el2.
150 */
151 unsigned long old_vttbr_el2 = read_vttbr_el2();
152
153 /*
154 * Make 'vmid' the `current vmid`. Note that the tlbi instructions
155 * bellow target the TLB entries that match the `current vmid`.
156 */
157 write_vttbr_el2(INPLACE(VTTBR_EL2_VMID, s2_ctx->vmid));
158 isb();
159
160 /*
161 * Invalidate entries in S2 TLB caches that
162 * match both `ipa` & the `current vmid`.
163 */
164 while (size != 0UL) {
165 tlbiipas2e1is(ipa >> 12);
166 size -= GRANULE_SIZE;
167 ipa += GRANULE_SIZE;
168 }
169 dsb(ish);
170
171 /*
172 * The architecture does not require TLB invalidation by IPA to affect
173 * combined Stage-1 + Stage-2 TLBs. Therefore we must invalidate all of
174 * Stage-1 (tagged with the `current vmid`) after invalidating Stage-2.
175 */
176 tlbivmalle1is();
177 dsb(ish);
178 isb();
179
180 /*
181 * Restore the old content of vttb_el2.
182 */
183 write_vttbr_el2(old_vttbr_el2);
184 isb();
185}
186
187/*
188 * Invalidate S2 TLB entries with "addr" IPA.
189 * Call this function after:
190 * 1. A L3 page desc has been removed.
191 */
192void invalidate_page(const struct realm_s2_context *s2_ctx, unsigned long addr)
193{
194 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
195}
196
197/*
198 * Invalidate S2 TLB entries with "addr" IPA.
199 * Call this function after:
200 * 1. A L2 block desc has been removed, or
201 * 2a. A L2 table desc has been removed, where
202 * 2b. All S2TTEs in L3 table that the L2 table desc was pointed to were invalid.
203 */
204void invalidate_block(const struct realm_s2_context *s2_ctx, unsigned long addr)
205{
206 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
207}
208
209/*
210 * Invalidate S2 TLB entries with "addr" IPA.
211 * Call this function after:
212 * 1a. A L2 table desc has been removed, where
213 * 1b. Some S2TTEs in the table that the L2 table desc was pointed to were valid.
214 */
215void invalidate_pages_in_block(const struct realm_s2_context *s2_ctx, unsigned long addr)
216{
217 stage2_tlbi_ipa(s2_ctx, addr, BLOCK_L2_SIZE);
218}
219
220/*
221 * Return the index of the entry describing @addr in the translation table at
222 * level @level. This only works for non-concatenated page tables, so should
223 * not be called to get the index for the starting level.
224 *
225 * See the library pseudocode
226 * aarch64/translation/vmsa_addrcalc/AArch64.TTEntryAddress on which this is
227 * modeled.
228 */
229static unsigned long s2_addr_to_idx(unsigned long addr, long level)
230{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100231 unsigned int levels, lsb;
232
233 assert(level <= RTT_PAGE_LEVEL);
234
AlexeiFedorov4faab852023-08-30 15:06:49 +0100235 levels = (unsigned int)(RTT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100236 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000237
238 addr >>= lsb;
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100239 addr &= (1UL << S2TTE_STRIDE) - 1UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000240 return addr;
241}
242
243/*
244 * Return the index of the entry describing @addr in the translation table
245 * starting level. This may return an index >= S2TTES_PER_S2TT when the
246 * combination of @start_level and @ipa_bits implies concatenated
247 * stage 2 tables.
248 *
249 * See the library pseudocode
250 * aarch64/translation/vmsa_addrcalc/AArch64.S2SLTTEntryAddress on which
251 * this is modeled.
252 */
253static unsigned long s2_sl_addr_to_idx(unsigned long addr, int start_level,
254 unsigned long ipa_bits)
255{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100256 unsigned int levels, lsb;
257
258 assert(start_level <= RTT_PAGE_LEVEL);
259
AlexeiFedorov4faab852023-08-30 15:06:49 +0100260 levels = (unsigned int)(RTT_PAGE_LEVEL - start_level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100261 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000262
263 addr &= (1UL << ipa_bits) - 1UL;
264 addr >>= lsb;
265 return addr;
266}
267
AlexeiFedorov7641a812023-08-22 14:31:27 +0100268static unsigned long addr_level_mask(unsigned long addr, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000269{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100270 unsigned int levels, lsb, msb;
271
272 assert(level <= RTT_PAGE_LEVEL);
273
AlexeiFedorov4faab852023-08-30 15:06:49 +0100274 levels = (unsigned int)(RTT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100275 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100276 msb = S2TTE_OA_BITS - 1U;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000277
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100278 return (addr & BIT_MASK_ULL(msb, lsb));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000279}
280
281static inline unsigned long table_entry_to_phys(unsigned long entry)
282{
283 return addr_level_mask(entry, RTT_PAGE_LEVEL);
284}
285
286static inline bool entry_is_table(unsigned long entry)
287{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100288 return ((entry & DESC_TYPE_MASK) == S2TTE_L012_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000289}
290
291static unsigned long __table_get_entry(struct granule *g_tbl,
292 unsigned long idx)
293{
294 unsigned long *table, entry;
295
296 table = granule_map(g_tbl, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100297 assert(table != NULL);
298
Soby Mathewb4c6df42022-11-09 11:13:29 +0000299 entry = s2tte_read(&table[idx]);
300 buffer_unmap(table);
301
302 return entry;
303}
304
305static struct granule *__find_next_level_idx(struct granule *g_tbl,
306 unsigned long idx)
307{
308 const unsigned long entry = __table_get_entry(g_tbl, idx);
309
310 if (!entry_is_table(entry)) {
311 return NULL;
312 }
313
314 return addr_to_granule(table_entry_to_phys(entry));
315}
316
317static struct granule *__find_lock_next_level(struct granule *g_tbl,
318 unsigned long map_addr,
319 long level)
320{
321 const unsigned long idx = s2_addr_to_idx(map_addr, level);
322 struct granule *g = __find_next_level_idx(g_tbl, idx);
323
324 if (g != NULL) {
325 granule_lock(g, GRANULE_STATE_RTT);
326 }
327
328 return g;
329}
330
331/*
332 * Walk an RTT until level @level using @map_addr.
333 * @g_root is the root (level 0) table and must be locked before the call.
334 * @start_level is the initial lookup level used for the stage 2 translation
335 * tables which may depend on the configuration of the realm, factoring in the
336 * IPA size of the realm and the desired starting level (within the limits
337 * defined by the Armv8 VMSA including options for stage 2 table concatenation).
338 * The function uses hand-over-hand locking to avoid race conditions and allow
339 * concurrent access to RTT tree which is not part of the current walk; when a
340 * next level table is reached it is locked before releasing previously locked
341 * table.
342 * The walk stops when either:
343 * - The entry found is a leaf entry (not an RTT Table entry), or
344 * - Level @level is reached.
345 *
346 * On return:
347 * - rtt_walk::last_level is the last level that has been reached by the walk.
348 * - rtt_walk.g_llt points to the TABLE granule at level @rtt_walk::level.
349 * The granule is locked.
350 * - rtt_walk::index is the entry index at rtt_walk.g_llt for @map_addr.
351 */
352void rtt_walk_lock_unlock(struct granule *g_root,
353 int start_level,
354 unsigned long ipa_bits,
355 unsigned long map_addr,
356 long level,
357 struct rtt_walk *wi)
358{
359 struct granule *g_tbls[NR_RTT_LEVELS] = { NULL };
360 unsigned long sl_idx;
361 int i, last_level;
362
363 assert(start_level >= MIN_STARTING_LEVEL);
364 assert(level >= start_level);
365 assert(map_addr < (1UL << ipa_bits));
366 assert(wi != NULL);
367
368 /* Handle concatenated starting level (SL) tables */
369 sl_idx = s2_sl_addr_to_idx(map_addr, start_level, ipa_bits);
370 if (sl_idx >= S2TTES_PER_S2TT) {
AlexeiFedorov4faab852023-08-30 15:06:49 +0100371 unsigned int tt_num = (unsigned int)(sl_idx >> S2TTE_STRIDE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000372 struct granule *g_concat_root = g_root + tt_num;
373
374 granule_lock(g_concat_root, GRANULE_STATE_RTT);
375 granule_unlock(g_root);
376 g_root = g_concat_root;
377 }
378
379 g_tbls[start_level] = g_root;
380 for (i = start_level; i < level; i++) {
381 /*
382 * Lock next RTT level. Correct locking order is guaranteed
383 * because reference is obtained from a locked granule
384 * (previous level). Also, hand-over-hand locking/unlocking is
385 * used to avoid race conditions.
386 */
387 g_tbls[i + 1] = __find_lock_next_level(g_tbls[i], map_addr, i);
388 if (g_tbls[i + 1] == NULL) {
389 last_level = i;
390 goto out;
391 }
392 granule_unlock(g_tbls[i]);
393 }
394
AlexeiFedorov4faab852023-08-30 15:06:49 +0100395 last_level = (int)level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000396out:
397 wi->last_level = last_level;
398 wi->g_llt = g_tbls[last_level];
399 wi->index = s2_addr_to_idx(map_addr, last_level);
400}
401
402/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100403 * Creates an unassigned_empty s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000404 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100405unsigned long s2tte_create_unassigned_empty(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000406{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100407 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100408}
409
410/*
411 * Creates an unassigned_ram s2tte.
412 */
413unsigned long s2tte_create_unassigned_ram(void)
414{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100415 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000416}
417
418/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100419 * Creates an unassigned_destroyed s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000420 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100421unsigned long s2tte_create_unassigned_destroyed(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000422{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100423 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
424}
425
426/*
427 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
428 * RIPAS=DESTROYED, at level @level.
429 */
430unsigned long s2tte_create_assigned_destroyed(unsigned long pa, long level)
431{
432 assert(level >= RTT_MIN_BLOCK_LEVEL);
433 assert(addr_is_level_aligned(pa, level));
434 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000435}
436
437/*
438 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
439 * RIPAS=EMPTY, at level @level.
440 */
441unsigned long s2tte_create_assigned_empty(unsigned long pa, long level)
442{
443 assert(level >= RTT_MIN_BLOCK_LEVEL);
444 assert(addr_is_level_aligned(pa, level));
445 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
446}
447
448/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100449 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000450 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100451unsigned long s2tte_create_assigned_ram(unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000452{
453 assert(level >= RTT_MIN_BLOCK_LEVEL);
454 assert(addr_is_level_aligned(pa, level));
455 if (level == RTT_PAGE_LEVEL) {
456 return (pa | S2TTE_PAGE);
457 }
458 return (pa | S2TTE_BLOCK);
459}
460
461/*
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100462 * Creates an assigned s2tte with output address @pa and the same
463 * RIPAS as passed on @s2tte.
464 */
465unsigned long s2tte_create_assigned_unchanged(unsigned long s2tte,
466 unsigned long pa,
467 long level)
468{
469 unsigned long current_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
470
471 assert(level >= RTT_MIN_BLOCK_LEVEL);
472 assert(addr_is_level_aligned(pa, level));
473 assert(EXTRACT(S2TTE_INVALID_RIPAS, current_ripas) <=
474 EXTRACT(S2TTE_INVALID_RIPAS, S2TTE_INVALID_RIPAS_DESTROYED));
475
476 if (current_ripas != S2TTE_INVALID_RIPAS_RAM) {
477 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | current_ripas);
478 }
479
480 return s2tte_create_assigned_ram(pa, level);
481}
482
483/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100484 * Creates an unassigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000485 */
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100486unsigned long s2tte_create_unassigned_ns(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000487{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100488 return (S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED |
489 S2TTE_INVALID_UNPROTECTED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000490}
491
492/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100493 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000494 *
495 * The following S2 TTE fields are provided through @s2tte argument:
496 * - The physical address
497 * - MemAttr
498 * - S2AP
499 * - Shareability
500 */
AlexeiFedorov950bd7b2023-08-24 15:25:22 +0100501unsigned long s2tte_create_assigned_ns(unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000502{
503 assert(level >= RTT_MIN_BLOCK_LEVEL);
504 if (level == RTT_PAGE_LEVEL) {
AlexeiFedorov950bd7b2023-08-24 15:25:22 +0100505 return (pa | S2TTE_PAGE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000506 }
AlexeiFedorov950bd7b2023-08-24 15:25:22 +0100507 return (pa | S2TTE_BLOCK_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000508}
509
510/*
511 * Validate the portion of NS S2TTE that is provided by the host.
512 */
513bool host_ns_s2tte_is_valid(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
520 /*
521 * Test that all fields that are not controlled by the host are zero
522 * and that the output address is correctly aligned. Note that
523 * the host is permitted to map any physical address outside PAR.
524 */
525 if ((s2tte & ~mask) != 0UL) {
526 return false;
527 }
528
529 /*
530 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
531 */
532 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
533 return false;
534 }
535
536 /*
537 * Only one value masked by S2TTE_SH_MASK is invalid/reserved.
538 */
539 if ((s2tte & S2TTE_SH_MASK) == S2TTE_SH_RESERVED) {
540 return false;
541 }
542
543 /*
544 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
545 */
546 return true;
547}
548
549/*
550 * Returns the portion of NS S2TTE that is set by the host.
551 */
552unsigned long host_ns_s2tte(unsigned long s2tte, long level)
553{
554 unsigned long mask = addr_level_mask(~0UL, level) |
555 S2TTE_MEMATTR_MASK |
556 S2TTE_AP_MASK |
557 S2TTE_SH_MASK;
558 return (s2tte & mask);
559}
560
561/*
562 * Creates a table s2tte at level @level with output address @pa.
563 */
564unsigned long s2tte_create_table(unsigned long pa, long level)
565{
566 assert(level < RTT_PAGE_LEVEL);
567 assert(GRANULE_ALIGNED(pa));
568
569 return (pa | S2TTE_TABLE);
570}
571
572/*
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100573 * Returns true if s2tte has defined ripas value, namely if it is one of:
574 * - unassigned_empty
575 * - unassigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100576 * - unassigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100577 * - assigned_empty
578 * - assigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100579 * - assigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100580 */
581bool s2tte_has_ripas(unsigned long s2tte, long level)
582{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100583 return (((s2tte & S2TTE_NS) == 0UL) && !s2tte_is_table(s2tte, level));
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100584}
585
586/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000587 * Returns true if @s2tte has HIPAS=@hipas.
588 */
589static bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
590{
591 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
592 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
593
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100594 return ((desc_type == S2TTE_INVALID) && (invalid_desc_hipas == hipas));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000595}
596
597/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100598 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000599 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100600static bool s2tte_has_unassigned_ripas(unsigned long s2tte, unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000601{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100602 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
603 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
604}
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100605
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100606/*
607 * Returns true if @s2tte has HIPAS=ASSIGNED and RIPAS=@ripas.
608 */
609static bool s2tte_has_assigned_ripas(unsigned long s2tte, unsigned long ripas)
610{
611 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
612 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100613}
614
615/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100616 * Returns true if @s2tte has HIPAS=UNASSIGNED.
617 */
618bool s2tte_is_unassigned(unsigned long s2tte)
619{
620 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED);
621}
622
623/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100624 * Returns true if @s2tte is an unassigned_empty.
625 */
626bool s2tte_is_unassigned_empty(unsigned long s2tte)
627{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100628 return (((s2tte & S2TTE_NS) == 0UL) &&
629 s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100630}
631
632/*
633 * Returns true if @s2tte is an unassigned_ram.
634 */
635bool s2tte_is_unassigned_ram(unsigned long s2tte)
636{
637 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
638}
639
640/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100641 * Returns true if @s2tte is unassigned_ns.
642 */
643bool s2tte_is_unassigned_ns(unsigned long s2tte)
644{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100645 return (((s2tte & S2TTE_NS) != 0UL) &&
646 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000647}
648
649/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100650 * Returns true if @s2tte has RIPAS=DESTROYED.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000651 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100652bool s2tte_is_unassigned_destroyed(unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000653{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100654 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
655}
656
657/*
658 * Returns true if @s2tte is an assigned_destroyed.
659 */
660bool s2tte_is_assigned_destroyed(unsigned long s2tte, long level)
661{
662 (void)level;
663
664 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000665}
666
667/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100668 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000669 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100670bool s2tte_is_assigned_empty(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000671{
672 (void)level;
673
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100674 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000675}
676
677static bool s2tte_check(unsigned long s2tte, long level, unsigned long ns)
678{
679 unsigned long desc_type;
680
681 if ((s2tte & S2TTE_NS) != ns) {
682 return false;
683 }
684
685 desc_type = s2tte & DESC_TYPE_MASK;
686
687 /* Only pages at L3 and valid blocks at L2 allowed */
688 if (((level == RTT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000689 ((level == RTT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK))) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000690 return true;
691 }
692
693 return false;
694}
695
696/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100697 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000698 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100699bool s2tte_is_assigned_ram(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000700{
701 return s2tte_check(s2tte, level, 0UL);
702}
703
704/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100705 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000706 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100707bool s2tte_is_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000708{
709 return s2tte_check(s2tte, level, S2TTE_NS);
710}
711
712/*
713 * Returns true if @s2tte is a table at level @level.
714 */
715bool s2tte_is_table(unsigned long s2tte, long level)
716{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100717 return ((level < RTT_PAGE_LEVEL) &&
718 ((s2tte & DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000719}
720
721/*
722 * Returns RIPAS of @s2tte.
723 *
724 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
725 * The s2tte must be not valid/invalid descriptor.
726 */
727enum ripas s2tte_get_ripas(unsigned long s2tte)
728{
729 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
730
731 /*
732 * If valid s2tte descriptor is passed, then ensure S2AP[0]
733 * bit is 1 (S2AP is set to RW for lower EL), which corresponds
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100734 * to RIPAS_RAM (bits[6:5] = b01) on a valid descriptor.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000735 */
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100736 if (((s2tte & DESC_TYPE_MASK) != S2TTE_INVALID) &&
Soby Mathewb4c6df42022-11-09 11:13:29 +0000737 (desc_ripas != S2TTE_INVALID_RIPAS_RAM)) {
738 assert(false);
739 }
740
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100741 switch (desc_ripas) {
742 case S2TTE_INVALID_RIPAS_EMPTY:
Yousuf A62808152022-10-31 10:35:42 +0000743 return RIPAS_EMPTY;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100744 case S2TTE_INVALID_RIPAS_RAM:
745 return RIPAS_RAM;
746 default:
747 assert(desc_ripas == S2TTE_INVALID_RIPAS_DESTROYED);
748 return RIPAS_DESTROYED;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000749 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000750}
751
752/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100753 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000754 *
755 * The granule is populated before it is made a table,
756 * hence, don't use s2tte_write for access.
757 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100758void s2tt_init_unassigned_empty(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000759{
760 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100761 s2tt[i] = s2tte_create_unassigned_empty();
762 }
763
764 dsb(ish);
765}
766
767/*
768 * Populates @s2tt with unassigned_ram s2ttes.
769 *
770 * The granule is populated before it is made a table,
771 * hence, don't use s2tte_write for access.
772 */
773void s2tt_init_unassigned_ram(unsigned long *s2tt)
774{
775 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
776 s2tt[i] = s2tte_create_unassigned_ram();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000777 }
778
779 dsb(ish);
780}
781
782/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100783 * Populates @s2tt with unassigned_ns s2ttes.
784 *
785 * The granule is populated before it is made a table,
786 * hence, don't use s2tte_write for access.
787 */
788void s2tt_init_unassigned_ns(unsigned long *s2tt)
789{
790 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
791 s2tt[i] = s2tte_create_unassigned_ns();
792 }
793
794 dsb(ish);
795}
796
797/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000798 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
799 *
800 * The granule is populated before it is made a table,
801 * hence, don't use s2tte_write for access.
802 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100803void s2tt_init_unassigned_destroyed(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000804{
805 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100806 s2tt[i] = s2tte_create_unassigned_destroyed();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000807 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100808 dsb(ish);
809}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000810
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100811/*
812 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
813 * 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 */
818void s2tt_init_assigned_destroyed(unsigned long *s2tt, unsigned long pa, long level)
819{
820 const unsigned long map_size = s2tte_map_size(level);
821
822 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
823 s2tt[i] = s2tte_create_assigned_destroyed(pa, level);
824 pa += map_size;
825 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000826 dsb(ish);
827}
828
AlexeiFedorov4faab852023-08-30 15:06:49 +0100829unsigned long s2tte_map_size(long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000830{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100831 unsigned int levels, lsb;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000832
833 assert(level <= RTT_PAGE_LEVEL);
834
AlexeiFedorov4faab852023-08-30 15:06:49 +0100835 levels = (unsigned int)(RTT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100836 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100837 return (1UL << lsb);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000838}
839
840/*
841 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
842 * contiguous memory block starting at @pa, and mapped at level @level.
843 *
844 * The granule is populated before it is made a table,
845 * hence, don't use s2tte_write for access.
846 */
847void s2tt_init_assigned_empty(unsigned long *s2tt, unsigned long pa, long level)
848{
849 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000850
AlexeiFedorov3a739332023-04-13 13:54:04 +0100851 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000852 s2tt[i] = s2tte_create_assigned_empty(pa, level);
853 pa += map_size;
854 }
855 dsb(ish);
856}
857
858/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100859 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000860 * contiguous memory block starting at @pa, and mapped at level @level.
861 *
862 * The granule is populated before it is made a table,
863 * hence, don't use s2tte_write for access.
864 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100865void s2tt_init_assigned_ram(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000866{
867 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000868
AlexeiFedorov3a739332023-04-13 13:54:04 +0100869 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
870 s2tt[i] = s2tte_create_assigned_ram(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000871 pa += map_size;
872 }
873 dsb(ish);
874}
875
876/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100877 * Populates @s2tt with assigned_ns s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000878 * contiguous memory block starting at @pa, and mapped at level @level.
879 *
880 * The granule is populated before it is made a table,
881 * hence, don't use s2tte_write for access.
882 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100883void s2tt_init_assigned_ns(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000884{
885 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000886
AlexeiFedorov3a739332023-04-13 13:54:04 +0100887 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
888 s2tt[i] = s2tte_create_assigned_ns(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000889 pa += map_size;
890 }
891 dsb(ish);
892}
893
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100894/*
895 * Returns true if s2tte has 'output address' field, namely, if it is one of:
896 * - assigned_empty
897 * - assigned_ram
898 * - assigned_ns
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100899 * - assigned_destroyed
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100900 * - table
901 */
AlexeiFedorov7641a812023-08-22 14:31:27 +0100902static bool s2tte_has_pa(unsigned long s2tte, long level)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100903{
904 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
905
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100906 return ((desc_type != S2TTE_INVALID) || /* block, page or table */
907 s2tte_is_assigned_empty(s2tte, level) ||
908 s2tte_is_assigned_destroyed(s2tte, level));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100909}
910
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100911/*
912 * Returns true if s2tte is a live RTTE entry. i.e.,
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100913 * HIPAS is ASSIGNED.
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100914 *
915 * NOTE: For now, only the RTTE with PA are live.
916 * This could change with EXPORT/IMPORT support.
917 */
AlexeiFedorov7641a812023-08-22 14:31:27 +0100918static bool s2tte_is_live(unsigned long s2tte, long level)
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100919{
920 return s2tte_has_pa(s2tte, level);
921}
922
Soby Mathewb4c6df42022-11-09 11:13:29 +0000923/* Returns physical address of a page entry or block */
924unsigned long s2tte_pa(unsigned long s2tte, long level)
925{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100926 if (!s2tte_has_pa(s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000927 assert(false);
928 }
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100929
930 if (s2tte_is_table(s2tte, level)) {
931 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
932 }
933
Soby Mathewb4c6df42022-11-09 11:13:29 +0000934 return addr_level_mask(s2tte, level);
935}
936
937/* Returns physical address of a table entry */
938unsigned long s2tte_pa_table(unsigned long s2tte, long level)
939{
940 assert(s2tte_is_table(s2tte, level));
941 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
942}
943
944bool addr_is_level_aligned(unsigned long addr, long level)
945{
946 return (addr == addr_level_mask(addr, level));
947}
948
949typedef bool (*s2tte_type_checker)(unsigned long s2tte);
950
951static bool __table_is_uniform_block(unsigned long *table,
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100952 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000953{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100954 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
955 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000956
957 if (!s2tte_is_x(s2tte)) {
958 return false;
959 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000960 }
961
962 return true;
963}
964
965/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100966 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000967 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100968bool table_is_unassigned_empty_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000969{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100970 return __table_is_uniform_block(table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100971}
972
973/*
974 * Returns true if all s2ttes in @table are unassigned_ram.
975 */
976bool table_is_unassigned_ram_block(unsigned long *table)
977{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100978 return __table_is_uniform_block(table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000979}
980
981/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100982 * Returns true if all s2ttes in @table are unassigned_ns
983 */
984bool table_is_unassigned_ns_block(unsigned long *table)
985{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100986 return __table_is_uniform_block(table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100987}
988
989/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100990 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +0000991 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100992bool table_is_unassigned_destroyed_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000993{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100994 return __table_is_uniform_block(table, s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000995}
996
997typedef bool (*s2tte_type_level_checker)(unsigned long s2tte, long level);
998
999static bool __table_maps_block(unsigned long *table,
1000 long level,
1001 s2tte_type_level_checker s2tte_is_x)
1002{
1003 unsigned long base_pa;
1004 unsigned long map_size = s2tte_map_size(level);
1005 unsigned long s2tte = s2tte_read(&table[0]);
1006 unsigned int i;
1007
1008 if (!s2tte_is_x(s2tte, level)) {
1009 return false;
1010 }
1011
1012 base_pa = s2tte_pa(s2tte, level);
1013 if (!addr_is_level_aligned(base_pa, level - 1L)) {
1014 return false;
1015 }
1016
1017 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
1018 unsigned long expected_pa = base_pa + (i * map_size);
1019
1020 s2tte = s2tte_read(&table[i]);
1021
1022 if (!s2tte_is_x(s2tte, level)) {
1023 return false;
1024 }
1025
1026 if (s2tte_pa(s2tte, level) != expected_pa) {
1027 return false;
1028 }
1029 }
1030
1031 return true;
1032}
1033
1034/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001035 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +00001036 * and refer to a contiguous block of granules aligned to @level - 1.
1037 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001038bool table_maps_assigned_empty_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001039{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001040 return __table_maps_block(table, level, s2tte_is_assigned_empty);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001041}
1042
1043/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001044 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001045 * refer to a contiguous block of granules aligned to @level - 1.
1046 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001047bool table_maps_assigned_ram_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001048{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001049 return __table_maps_block(table, level, s2tte_is_assigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001050}
1051
1052/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001053 * Returns true if all s2ttes in @table are assigned_ns s2ttes and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001054 * refer to a contiguous block of granules aligned to @level - 1.
AlexeiFedorov3a739332023-04-13 13:54:04 +01001055 *
1056 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001057 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001058bool table_maps_assigned_ns_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001059{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001060 return __table_maps_block(table, level, s2tte_is_assigned_ns);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001061}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001062
1063/*
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001064 * Returns true if all s2ttes are assigned_destroyed and
1065 * refer to a contiguous block of granules aligned to @level - 1.
1066 */
1067bool table_maps_assigned_destroyed_block(unsigned long *table, long level)
1068{
1069 return __table_maps_block(table, level, s2tte_is_assigned_destroyed);
1070}
1071
1072/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001073 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001074 * skip the non-live entries (i.e., HIPAS=UNASSIGNED).
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001075 * In other words, the scanning stops when a live RTTE is encountered or we
1076 * reach the end of this RTT.
1077 *
1078 * For now an RTTE can be considered non-live if it doesn't have a PA.
1079 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1080 * in the RTTE.
1081 *
1082 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1083 * with RMI_ERROR_RTT).
1084 *
1085 * Returns:
1086 * - If the entry @wi.index is live, returns @addr.
1087 * - If none of the entries in the @s2tt are "live", returns the address of the
1088 * first entry in the next table.
1089 * - Otherwise, the address of the first live entry in @s2tt
1090 */
1091unsigned long skip_non_live_entries(unsigned long addr,
1092 unsigned long *s2tt,
1093 const struct rtt_walk *wi)
1094{
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001095 unsigned long i, index = wi->index;
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001096 long level = wi->last_level;
1097 unsigned long map_size;
1098
1099 /*
1100 * If the entry for the map_addr is live,
1101 * return @addr.
1102 */
1103 if (s2tte_is_live(s2tte_read(&s2tt[index]), level)) {
1104 return addr;
1105 }
1106
1107 /*
1108 * Align the address DOWN to the map_size, as expected for the @level,
1109 * so that we can compute the correct address by using the index.
1110 */
1111 map_size = s2tte_map_size(level);
1112 addr &= ~(map_size - 1UL);
1113
1114 /* Skip the "index" */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001115 for (i = index + 1UL; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001116 unsigned long s2tte = s2tte_read(&s2tt[i]);
1117
1118 if (s2tte_is_live(s2tte, level)) {
1119 break;
1120 }
1121 }
1122
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001123 return (addr + ((i - index) * map_size));
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001124}