blob: 646bd65b11728c2971939f59c24fb0fbf679471a [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);
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +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);
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +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);
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100275 lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
276 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/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100462 * Creates an unassigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000463 */
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100464unsigned long s2tte_create_unassigned_ns(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000465{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100466 return (S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED |
467 S2TTE_INVALID_UNPROTECTED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000468}
469
470/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100471 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000472 *
473 * The following S2 TTE fields are provided through @s2tte argument:
474 * - The physical address
475 * - MemAttr
476 * - S2AP
477 * - Shareability
478 */
AlexeiFedorov950bd7b2023-08-24 15:25:22 +0100479unsigned long s2tte_create_assigned_ns(unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000480{
481 assert(level >= RTT_MIN_BLOCK_LEVEL);
482 if (level == RTT_PAGE_LEVEL) {
AlexeiFedorov950bd7b2023-08-24 15:25:22 +0100483 return (pa | S2TTE_PAGE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000484 }
AlexeiFedorov950bd7b2023-08-24 15:25:22 +0100485 return (pa | S2TTE_BLOCK_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000486}
487
488/*
489 * Validate the portion of NS S2TTE that is provided by the host.
490 */
491bool host_ns_s2tte_is_valid(unsigned long s2tte, long level)
492{
493 unsigned long mask = addr_level_mask(~0UL, level) |
494 S2TTE_MEMATTR_MASK |
495 S2TTE_AP_MASK |
496 S2TTE_SH_MASK;
497
498 /*
499 * Test that all fields that are not controlled by the host are zero
500 * and that the output address is correctly aligned. Note that
501 * the host is permitted to map any physical address outside PAR.
502 */
503 if ((s2tte & ~mask) != 0UL) {
504 return false;
505 }
506
507 /*
508 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
509 */
510 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
511 return false;
512 }
513
514 /*
515 * Only one value masked by S2TTE_SH_MASK is invalid/reserved.
516 */
517 if ((s2tte & S2TTE_SH_MASK) == S2TTE_SH_RESERVED) {
518 return false;
519 }
520
521 /*
522 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
523 */
524 return true;
525}
526
527/*
528 * Returns the portion of NS S2TTE that is set by the host.
529 */
530unsigned long host_ns_s2tte(unsigned long s2tte, long level)
531{
532 unsigned long mask = addr_level_mask(~0UL, level) |
533 S2TTE_MEMATTR_MASK |
534 S2TTE_AP_MASK |
535 S2TTE_SH_MASK;
536 return (s2tte & mask);
537}
538
539/*
540 * Creates a table s2tte at level @level with output address @pa.
541 */
542unsigned long s2tte_create_table(unsigned long pa, long level)
543{
544 assert(level < RTT_PAGE_LEVEL);
545 assert(GRANULE_ALIGNED(pa));
546
547 return (pa | S2TTE_TABLE);
548}
549
550/*
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100551 * Returns true if s2tte has defined ripas value, namely if it is one of:
552 * - unassigned_empty
553 * - unassigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100554 * - unassigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100555 * - assigned_empty
556 * - assigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100557 * - assigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100558 */
559bool s2tte_has_ripas(unsigned long s2tte, long level)
560{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100561 return (((s2tte & S2TTE_NS) == 0UL) && !s2tte_is_table(s2tte, level));
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100562}
563
564/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000565 * Returns true if @s2tte has HIPAS=@hipas.
566 */
567static bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
568{
569 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
570 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
571
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100572 return ((desc_type == S2TTE_INVALID) && (invalid_desc_hipas == hipas));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000573}
574
575/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100576 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000577 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100578static bool s2tte_has_unassigned_ripas(unsigned long s2tte, unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000579{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100580 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
581 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
582}
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100583
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100584/*
585 * Returns true if @s2tte has HIPAS=ASSIGNED and RIPAS=@ripas.
586 */
587static bool s2tte_has_assigned_ripas(unsigned long s2tte, unsigned long ripas)
588{
589 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
590 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100591}
592
593/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100594 * Returns true if @s2tte has HIPAS=UNASSIGNED.
595 */
596bool s2tte_is_unassigned(unsigned long s2tte)
597{
598 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED);
599}
600
601/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100602 * Returns true if @s2tte is an unassigned_empty.
603 */
604bool s2tte_is_unassigned_empty(unsigned long s2tte)
605{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100606 return (((s2tte & S2TTE_NS) == 0UL) &&
607 s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100608}
609
610/*
611 * Returns true if @s2tte is an unassigned_ram.
612 */
613bool s2tte_is_unassigned_ram(unsigned long s2tte)
614{
615 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
616}
617
618/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100619 * Returns true if @s2tte is unassigned_ns.
620 */
621bool s2tte_is_unassigned_ns(unsigned long s2tte)
622{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100623 return (((s2tte & S2TTE_NS) != 0UL) &&
624 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000625}
626
627/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100628 * Returns true if @s2tte has RIPAS=DESTROYED.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000629 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100630bool s2tte_is_unassigned_destroyed(unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000631{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100632 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
633}
634
635/*
636 * Returns true if @s2tte is an assigned_destroyed.
637 */
638bool s2tte_is_assigned_destroyed(unsigned long s2tte, long level)
639{
640 (void)level;
641
642 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000643}
644
645/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100646 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000647 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100648bool s2tte_is_assigned_empty(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000649{
650 (void)level;
651
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100652 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000653}
654
655static bool s2tte_check(unsigned long s2tte, long level, unsigned long ns)
656{
657 unsigned long desc_type;
658
659 if ((s2tte & S2TTE_NS) != ns) {
660 return false;
661 }
662
663 desc_type = s2tte & DESC_TYPE_MASK;
664
665 /* Only pages at L3 and valid blocks at L2 allowed */
666 if (((level == RTT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000667 ((level == RTT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK))) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000668 return true;
669 }
670
671 return false;
672}
673
674/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100675 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000676 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100677bool s2tte_is_assigned_ram(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000678{
679 return s2tte_check(s2tte, level, 0UL);
680}
681
682/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100683 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000684 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100685bool s2tte_is_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000686{
687 return s2tte_check(s2tte, level, S2TTE_NS);
688}
689
690/*
691 * Returns true if @s2tte is a table at level @level.
692 */
693bool s2tte_is_table(unsigned long s2tte, long level)
694{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100695 return ((level < RTT_PAGE_LEVEL) &&
696 ((s2tte & DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000697}
698
699/*
700 * Returns RIPAS of @s2tte.
701 *
702 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
703 * The s2tte must be not valid/invalid descriptor.
704 */
705enum ripas s2tte_get_ripas(unsigned long s2tte)
706{
707 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
708
709 /*
710 * If valid s2tte descriptor is passed, then ensure S2AP[0]
711 * bit is 1 (S2AP is set to RW for lower EL), which corresponds
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100712 * to RIPAS_RAM (bits[6:5] = b01) on a valid descriptor.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000713 */
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100714 if (((s2tte & DESC_TYPE_MASK) != S2TTE_INVALID) &&
Soby Mathewb4c6df42022-11-09 11:13:29 +0000715 (desc_ripas != S2TTE_INVALID_RIPAS_RAM)) {
716 assert(false);
717 }
718
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100719 switch (desc_ripas) {
720 case S2TTE_INVALID_RIPAS_EMPTY:
Yousuf A62808152022-10-31 10:35:42 +0000721 return RIPAS_EMPTY;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100722 case S2TTE_INVALID_RIPAS_RAM:
723 return RIPAS_RAM;
724 default:
725 assert(desc_ripas == S2TTE_INVALID_RIPAS_DESTROYED);
726 return RIPAS_DESTROYED;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000727 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000728}
729
730/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100731 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000732 *
733 * The granule is populated before it is made a table,
734 * hence, don't use s2tte_write for access.
735 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100736void s2tt_init_unassigned_empty(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000737{
738 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100739 s2tt[i] = s2tte_create_unassigned_empty();
740 }
741
742 dsb(ish);
743}
744
745/*
746 * Populates @s2tt with unassigned_ram s2ttes.
747 *
748 * The granule is populated before it is made a table,
749 * hence, don't use s2tte_write for access.
750 */
751void s2tt_init_unassigned_ram(unsigned long *s2tt)
752{
753 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
754 s2tt[i] = s2tte_create_unassigned_ram();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000755 }
756
757 dsb(ish);
758}
759
760/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100761 * Populates @s2tt with unassigned_ns s2ttes.
762 *
763 * The granule is populated before it is made a table,
764 * hence, don't use s2tte_write for access.
765 */
766void s2tt_init_unassigned_ns(unsigned long *s2tt)
767{
768 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
769 s2tt[i] = s2tte_create_unassigned_ns();
770 }
771
772 dsb(ish);
773}
774
775/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000776 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
777 *
778 * The granule is populated before it is made a table,
779 * hence, don't use s2tte_write for access.
780 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100781void s2tt_init_unassigned_destroyed(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000782{
783 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100784 s2tt[i] = s2tte_create_unassigned_destroyed();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000785 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100786 dsb(ish);
787}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000788
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100789/*
790 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
791 * contiguous memory block starting at @pa, and mapped at level @level.
792 *
793 * The granule is populated before it is made a table,
794 * hence, don't use s2tte_write for access.
795 */
796void s2tt_init_assigned_destroyed(unsigned long *s2tt, unsigned long pa, long level)
797{
798 const unsigned long map_size = s2tte_map_size(level);
799
800 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
801 s2tt[i] = s2tte_create_assigned_destroyed(pa, level);
802 pa += map_size;
803 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000804 dsb(ish);
805}
806
AlexeiFedorov4faab852023-08-30 15:06:49 +0100807unsigned long s2tte_map_size(long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000808{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100809 unsigned int levels, lsb;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000810
811 assert(level <= RTT_PAGE_LEVEL);
812
AlexeiFedorov4faab852023-08-30 15:06:49 +0100813 levels = (unsigned int)(RTT_PAGE_LEVEL - level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000814 lsb = levels * S2TTE_STRIDE + GRANULE_SHIFT;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100815 return (1UL << lsb);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000816}
817
818/*
819 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
820 * contiguous memory block starting at @pa, and mapped at level @level.
821 *
822 * The granule is populated before it is made a table,
823 * hence, don't use s2tte_write for access.
824 */
825void s2tt_init_assigned_empty(unsigned long *s2tt, unsigned long pa, long level)
826{
827 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000828
AlexeiFedorov3a739332023-04-13 13:54:04 +0100829 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000830 s2tt[i] = s2tte_create_assigned_empty(pa, level);
831 pa += map_size;
832 }
833 dsb(ish);
834}
835
836/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100837 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000838 * contiguous memory block starting at @pa, and mapped at level @level.
839 *
840 * The granule is populated before it is made a table,
841 * hence, don't use s2tte_write for access.
842 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100843void s2tt_init_assigned_ram(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000844{
845 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000846
AlexeiFedorov3a739332023-04-13 13:54:04 +0100847 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
848 s2tt[i] = s2tte_create_assigned_ram(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000849 pa += map_size;
850 }
851 dsb(ish);
852}
853
854/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100855 * Populates @s2tt with assigned_ns s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000856 * contiguous memory block starting at @pa, and mapped at level @level.
857 *
858 * The granule is populated before it is made a table,
859 * hence, don't use s2tte_write for access.
860 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100861void s2tt_init_assigned_ns(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000862{
863 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000864
AlexeiFedorov3a739332023-04-13 13:54:04 +0100865 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
866 s2tt[i] = s2tte_create_assigned_ns(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000867 pa += map_size;
868 }
869 dsb(ish);
870}
871
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100872/*
873 * Returns true if s2tte has 'output address' field, namely, if it is one of:
874 * - assigned_empty
875 * - assigned_ram
876 * - assigned_ns
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100877 * - assigned_destroyed
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100878 * - table
879 */
AlexeiFedorov7641a812023-08-22 14:31:27 +0100880static bool s2tte_has_pa(unsigned long s2tte, long level)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100881{
882 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
883
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100884 return ((desc_type != S2TTE_INVALID) || /* block, page or table */
885 s2tte_is_assigned_empty(s2tte, level) ||
886 s2tte_is_assigned_destroyed(s2tte, level));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100887}
888
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100889/*
890 * Returns true if s2tte is a live RTTE entry. i.e.,
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100891 * HIPAS is ASSIGNED.
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100892 *
893 * NOTE: For now, only the RTTE with PA are live.
894 * This could change with EXPORT/IMPORT support.
895 */
AlexeiFedorov7641a812023-08-22 14:31:27 +0100896static bool s2tte_is_live(unsigned long s2tte, long level)
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100897{
898 return s2tte_has_pa(s2tte, level);
899}
900
Soby Mathewb4c6df42022-11-09 11:13:29 +0000901/* Returns physical address of a page entry or block */
902unsigned long s2tte_pa(unsigned long s2tte, long level)
903{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100904 if (!s2tte_has_pa(s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000905 assert(false);
906 }
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100907
908 if (s2tte_is_table(s2tte, level)) {
909 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
910 }
911
Soby Mathewb4c6df42022-11-09 11:13:29 +0000912 return addr_level_mask(s2tte, level);
913}
914
915/* Returns physical address of a table entry */
916unsigned long s2tte_pa_table(unsigned long s2tte, long level)
917{
918 assert(s2tte_is_table(s2tte, level));
919 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
920}
921
922bool addr_is_level_aligned(unsigned long addr, long level)
923{
924 return (addr == addr_level_mask(addr, level));
925}
926
927typedef bool (*s2tte_type_checker)(unsigned long s2tte);
928
929static bool __table_is_uniform_block(unsigned long *table,
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100930 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000931{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100932 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
933 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000934
935 if (!s2tte_is_x(s2tte)) {
936 return false;
937 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000938 }
939
940 return true;
941}
942
943/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100944 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000945 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100946bool table_is_unassigned_empty_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000947{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100948 return __table_is_uniform_block(table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100949}
950
951/*
952 * Returns true if all s2ttes in @table are unassigned_ram.
953 */
954bool table_is_unassigned_ram_block(unsigned long *table)
955{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100956 return __table_is_uniform_block(table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000957}
958
959/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100960 * Returns true if all s2ttes in @table are unassigned_ns
961 */
962bool table_is_unassigned_ns_block(unsigned long *table)
963{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100964 return __table_is_uniform_block(table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100965}
966
967/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100968 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +0000969 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100970bool table_is_unassigned_destroyed_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000971{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100972 return __table_is_uniform_block(table, s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000973}
974
975typedef bool (*s2tte_type_level_checker)(unsigned long s2tte, long level);
976
977static bool __table_maps_block(unsigned long *table,
978 long level,
979 s2tte_type_level_checker s2tte_is_x)
980{
981 unsigned long base_pa;
982 unsigned long map_size = s2tte_map_size(level);
983 unsigned long s2tte = s2tte_read(&table[0]);
984 unsigned int i;
985
986 if (!s2tte_is_x(s2tte, level)) {
987 return false;
988 }
989
990 base_pa = s2tte_pa(s2tte, level);
991 if (!addr_is_level_aligned(base_pa, level - 1L)) {
992 return false;
993 }
994
995 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
996 unsigned long expected_pa = base_pa + (i * map_size);
997
998 s2tte = s2tte_read(&table[i]);
999
1000 if (!s2tte_is_x(s2tte, level)) {
1001 return false;
1002 }
1003
1004 if (s2tte_pa(s2tte, level) != expected_pa) {
1005 return false;
1006 }
1007 }
1008
1009 return true;
1010}
1011
1012/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001013 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +00001014 * and refer to a contiguous block of granules aligned to @level - 1.
1015 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001016bool table_maps_assigned_empty_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001017{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001018 return __table_maps_block(table, level, s2tte_is_assigned_empty);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001019}
1020
1021/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001022 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001023 * refer to a contiguous block of granules aligned to @level - 1.
1024 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001025bool table_maps_assigned_ram_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001026{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001027 return __table_maps_block(table, level, s2tte_is_assigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001028}
1029
1030/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001031 * Returns true if all s2ttes in @table are assigned_ns s2ttes and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001032 * refer to a contiguous block of granules aligned to @level - 1.
AlexeiFedorov3a739332023-04-13 13:54:04 +01001033 *
1034 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001035 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001036bool table_maps_assigned_ns_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001037{
AlexeiFedorov3a739332023-04-13 13:54:04 +01001038 return __table_maps_block(table, level, s2tte_is_assigned_ns);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001039}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001040
1041/*
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001042 * Returns true if all s2ttes are assigned_destroyed and
1043 * refer to a contiguous block of granules aligned to @level - 1.
1044 */
1045bool table_maps_assigned_destroyed_block(unsigned long *table, long level)
1046{
1047 return __table_maps_block(table, level, s2tte_is_assigned_destroyed);
1048}
1049
1050/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001051 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001052 * skip the non-live entries (i.e., HIPAS=UNASSIGNED).
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001053 * In other words, the scanning stops when a live RTTE is encountered or we
1054 * reach the end of this RTT.
1055 *
1056 * For now an RTTE can be considered non-live if it doesn't have a PA.
1057 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1058 * in the RTTE.
1059 *
1060 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1061 * with RMI_ERROR_RTT).
1062 *
1063 * Returns:
1064 * - If the entry @wi.index is live, returns @addr.
1065 * - If none of the entries in the @s2tt are "live", returns the address of the
1066 * first entry in the next table.
1067 * - Otherwise, the address of the first live entry in @s2tt
1068 */
1069unsigned long skip_non_live_entries(unsigned long addr,
1070 unsigned long *s2tt,
1071 const struct rtt_walk *wi)
1072{
AlexeiFedorov4faab852023-08-30 15:06:49 +01001073 unsigned int i, index = (unsigned int)wi->index;
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001074 long level = wi->last_level;
1075 unsigned long map_size;
1076
1077 /*
1078 * If the entry for the map_addr is live,
1079 * return @addr.
1080 */
1081 if (s2tte_is_live(s2tte_read(&s2tt[index]), level)) {
1082 return addr;
1083 }
1084
1085 /*
1086 * Align the address DOWN to the map_size, as expected for the @level,
1087 * so that we can compute the correct address by using the index.
1088 */
1089 map_size = s2tte_map_size(level);
1090 addr &= ~(map_size - 1UL);
1091
1092 /* Skip the "index" */
1093 for (i = index + 1U; i < S2TTES_PER_S2TT; i++) {
1094 unsigned long s2tte = s2tte_read(&s2tt[i]);
1095
1096 if (s2tte_is_live(s2tte, level)) {
1097 break;
1098 }
1099 }
1100
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001101 return (addr + (i - index) * map_size);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001102}