blob: fd6f31541f762c72b34a13456e0fc6fdda84cb66 [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)
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +010068#define S2TTE_NS_ATTR_MASK (S2TTE_MEMATTR_MASK | S2TTE_AP_MASK | \
69 S2TTE_SH_MASK)
Soby Mathewb4c6df42022-11-09 11:13:29 +000070
71#define S2TTE_TABLE S2TTE_L012_TABLE
72#define S2TTE_BLOCK (S2TTE_ATTRS | S2TTE_L012_BLOCK)
73#define S2TTE_PAGE (S2TTE_ATTRS | S2TTE_L3_PAGE)
74#define S2TTE_BLOCK_NS (S2TTE_NS | S2TTE_XN | S2TTE_AF | S2TTE_L012_BLOCK)
75#define S2TTE_PAGE_NS (S2TTE_NS | S2TTE_XN | S2TTE_AF | S2TTE_L3_PAGE)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +010076#define S2TTE_INVALID S2TTE_Lx_INVALID
Soby Mathewb4c6df42022-11-09 11:13:29 +000077
78/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +010079 * The type of stage 2 translation table entry (s2tte) is defined by:
80 * 1. Table level where it resides
81 * 2. DESC_TYPE field[1:0]
AlexeiFedorovc53b1f72023-07-04 15:37:03 +010082 * 4. HIPAS field [4:2]
83 * 4. RIPAS field [6:5]
AlexeiFedorov5ceff352023-04-12 16:17:00 +010084 * 5. NS field [55]
Soby Mathewb4c6df42022-11-09 11:13:29 +000085 *
AlexeiFedorov63614ea2023-07-14 17:07:20 +010086 * ======================================================================================
87 * s2tte type level DESC_TYPE[1:0] HIPAS[4:2] RIPAS[6:5] NS OA alignment
88 * ======================================================================================
89 * unassigned_empty any invalid[0] unassigned[0] empty[0] 0 n/a
90 * --------------------------------------------------------------------------------------
91 * unassigned_ram any invalid[0] unassigned[0] ram[1] 0 n/a
92 * --------------------------------------------------------------------------------------
93 * unassigned_destroyed any invalid[0] unassigned[0] destroyed[2] 0 n/a
94 * --------------------------------------------------------------------------------------
95 * assigned_empty 2,3 invalid[0] assigned[1] empty[0] 0 to level
96 * --------------------------------------------------------------------------------------
97 * assigned_ram 3 page[3] n/a n/a 0 to level
98 * 2 block[1] n/a n/a 0 to level
99 * --------------------------------------------------------------------------------------
100 * assigned_destroyed any invalid[0] assigned[1] destroyed[2] 0 n/a
101 * ======================================================================================
102 * unassigned_ns any invalid[0] unassigned[0] n/a 1 n/a
103 * --------------------------------------------------------------------------------------
104 * assigned_ns 3 page[3] n/a n/a 1 to level
105 * 2 block[1] n/a n/a 1 to level
106 * ======================================================================================
107 * table <=2 table[3] n/a n/a n/a to 4K
108 * ======================================================================================
Soby Mathewb4c6df42022-11-09 11:13:29 +0000109 */
110
111#define S2TTE_INVALID_HIPAS_SHIFT 2
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100112#define S2TTE_INVALID_HIPAS_WIDTH 3U
Soby Mathewb4c6df42022-11-09 11:13:29 +0000113#define S2TTE_INVALID_HIPAS_MASK MASK(S2TTE_INVALID_HIPAS)
114
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100115#define S2TTE_INVALID_HIPAS_UNASSIGNED (INPLACE(S2TTE_INVALID_HIPAS, 0UL))
116#define S2TTE_INVALID_HIPAS_ASSIGNED (INPLACE(S2TTE_INVALID_HIPAS, 1UL))
Soby Mathewb4c6df42022-11-09 11:13:29 +0000117
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100118#define S2TTE_INVALID_RIPAS_SHIFT 5
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100119#define S2TTE_INVALID_RIPAS_WIDTH 2U
Soby Mathewb4c6df42022-11-09 11:13:29 +0000120#define S2TTE_INVALID_RIPAS_MASK MASK(S2TTE_INVALID_RIPAS)
121
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100122#define S2TTE_INVALID_RIPAS_EMPTY (INPLACE(S2TTE_INVALID_RIPAS, 0UL))
123#define S2TTE_INVALID_RIPAS_RAM (INPLACE(S2TTE_INVALID_RIPAS, 1UL))
124#define S2TTE_INVALID_RIPAS_DESTROYED (INPLACE(S2TTE_INVALID_RIPAS, 2UL))
Soby Mathewb4c6df42022-11-09 11:13:29 +0000125
Soby Mathewb4c6df42022-11-09 11:13:29 +0000126#define S2TTE_INVALID_UNPROTECTED 0x0UL
127
128#define NR_RTT_LEVELS 4
129
130/*
131 * Invalidates S2 TLB entries from [ipa, ipa + size] region tagged with `vmid`.
132 */
133static void stage2_tlbi_ipa(const struct realm_s2_context *s2_ctx,
134 unsigned long ipa,
135 unsigned long size)
136{
137 /*
138 * Notes:
139 *
140 * - This follows the description provided in the Arm ARM on
141 * "Invalidation of TLB entries from stage 2 translations".
142 *
143 * - @TODO: Provide additional information to this primitive so that
144 * we can utilize:
145 * - The TTL level hint, see FEAT_TTL,
146 * - Final level lookup only invalidation,
147 * - Address range invalidation.
148 */
149
150 /*
151 * Save the current content of vttb_el2.
152 */
153 unsigned long old_vttbr_el2 = read_vttbr_el2();
154
155 /*
156 * Make 'vmid' the `current vmid`. Note that the tlbi instructions
157 * bellow target the TLB entries that match the `current vmid`.
158 */
159 write_vttbr_el2(INPLACE(VTTBR_EL2_VMID, s2_ctx->vmid));
160 isb();
161
162 /*
163 * Invalidate entries in S2 TLB caches that
164 * match both `ipa` & the `current vmid`.
165 */
166 while (size != 0UL) {
167 tlbiipas2e1is(ipa >> 12);
168 size -= GRANULE_SIZE;
169 ipa += GRANULE_SIZE;
170 }
171 dsb(ish);
172
173 /*
174 * The architecture does not require TLB invalidation by IPA to affect
175 * combined Stage-1 + Stage-2 TLBs. Therefore we must invalidate all of
176 * Stage-1 (tagged with the `current vmid`) after invalidating Stage-2.
177 */
178 tlbivmalle1is();
179 dsb(ish);
180 isb();
181
182 /*
183 * Restore the old content of vttb_el2.
184 */
185 write_vttbr_el2(old_vttbr_el2);
186 isb();
187}
188
189/*
190 * Invalidate S2 TLB entries with "addr" IPA.
191 * Call this function after:
192 * 1. A L3 page desc has been removed.
193 */
194void invalidate_page(const struct realm_s2_context *s2_ctx, unsigned long addr)
195{
196 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
197}
198
199/*
200 * Invalidate S2 TLB entries with "addr" IPA.
201 * Call this function after:
202 * 1. A L2 block desc has been removed, or
203 * 2a. A L2 table desc has been removed, where
204 * 2b. All S2TTEs in L3 table that the L2 table desc was pointed to were invalid.
205 */
206void invalidate_block(const struct realm_s2_context *s2_ctx, unsigned long addr)
207{
208 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
209}
210
211/*
212 * Invalidate S2 TLB entries with "addr" IPA.
213 * Call this function after:
214 * 1a. A L2 table desc has been removed, where
215 * 1b. Some S2TTEs in the table that the L2 table desc was pointed to were valid.
216 */
217void invalidate_pages_in_block(const struct realm_s2_context *s2_ctx, unsigned long addr)
218{
219 stage2_tlbi_ipa(s2_ctx, addr, BLOCK_L2_SIZE);
220}
221
222/*
223 * Return the index of the entry describing @addr in the translation table at
224 * level @level. This only works for non-concatenated page tables, so should
225 * not be called to get the index for the starting level.
226 *
227 * See the library pseudocode
228 * aarch64/translation/vmsa_addrcalc/AArch64.TTEntryAddress on which this is
229 * modeled.
230 */
231static unsigned long s2_addr_to_idx(unsigned long addr, long level)
232{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100233 unsigned int levels, lsb;
234
235 assert(level <= RTT_PAGE_LEVEL);
236
AlexeiFedorov4faab852023-08-30 15:06:49 +0100237 levels = (unsigned int)(RTT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100238 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000239
240 addr >>= lsb;
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100241 addr &= (1UL << S2TTE_STRIDE) - 1UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000242 return addr;
243}
244
245/*
246 * Return the index of the entry describing @addr in the translation table
247 * starting level. This may return an index >= S2TTES_PER_S2TT when the
248 * combination of @start_level and @ipa_bits implies concatenated
249 * stage 2 tables.
250 *
251 * See the library pseudocode
252 * aarch64/translation/vmsa_addrcalc/AArch64.S2SLTTEntryAddress on which
253 * this is modeled.
254 */
255static unsigned long s2_sl_addr_to_idx(unsigned long addr, int start_level,
256 unsigned long ipa_bits)
257{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100258 unsigned int levels, lsb;
259
260 assert(start_level <= RTT_PAGE_LEVEL);
261
AlexeiFedorov4faab852023-08-30 15:06:49 +0100262 levels = (unsigned int)(RTT_PAGE_LEVEL - start_level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100263 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000264
265 addr &= (1UL << ipa_bits) - 1UL;
266 addr >>= lsb;
267 return addr;
268}
269
AlexeiFedorov7641a812023-08-22 14:31:27 +0100270static unsigned long addr_level_mask(unsigned long addr, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000271{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100272 unsigned int levels, lsb, msb;
273
274 assert(level <= RTT_PAGE_LEVEL);
275
AlexeiFedorov4faab852023-08-30 15:06:49 +0100276 levels = (unsigned int)(RTT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100277 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100278 msb = S2TTE_OA_BITS - 1U;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000279
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100280 return (addr & BIT_MASK_ULL(msb, lsb));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000281}
282
283static inline unsigned long table_entry_to_phys(unsigned long entry)
284{
285 return addr_level_mask(entry, RTT_PAGE_LEVEL);
286}
287
288static inline bool entry_is_table(unsigned long entry)
289{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100290 return ((entry & DESC_TYPE_MASK) == S2TTE_L012_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000291}
292
293static unsigned long __table_get_entry(struct granule *g_tbl,
294 unsigned long idx)
295{
296 unsigned long *table, entry;
297
298 table = granule_map(g_tbl, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100299 assert(table != NULL);
300
Soby Mathewb4c6df42022-11-09 11:13:29 +0000301 entry = s2tte_read(&table[idx]);
302 buffer_unmap(table);
303
304 return entry;
305}
306
307static struct granule *__find_next_level_idx(struct granule *g_tbl,
308 unsigned long idx)
309{
310 const unsigned long entry = __table_get_entry(g_tbl, idx);
311
312 if (!entry_is_table(entry)) {
313 return NULL;
314 }
315
316 return addr_to_granule(table_entry_to_phys(entry));
317}
318
319static struct granule *__find_lock_next_level(struct granule *g_tbl,
320 unsigned long map_addr,
321 long level)
322{
323 const unsigned long idx = s2_addr_to_idx(map_addr, level);
324 struct granule *g = __find_next_level_idx(g_tbl, idx);
325
326 if (g != NULL) {
327 granule_lock(g, GRANULE_STATE_RTT);
328 }
329
330 return g;
331}
332
333/*
334 * Walk an RTT until level @level using @map_addr.
335 * @g_root is the root (level 0) table and must be locked before the call.
336 * @start_level is the initial lookup level used for the stage 2 translation
337 * tables which may depend on the configuration of the realm, factoring in the
338 * IPA size of the realm and the desired starting level (within the limits
339 * defined by the Armv8 VMSA including options for stage 2 table concatenation).
340 * The function uses hand-over-hand locking to avoid race conditions and allow
341 * concurrent access to RTT tree which is not part of the current walk; when a
342 * next level table is reached it is locked before releasing previously locked
343 * table.
344 * The walk stops when either:
345 * - The entry found is a leaf entry (not an RTT Table entry), or
346 * - Level @level is reached.
347 *
348 * On return:
349 * - rtt_walk::last_level is the last level that has been reached by the walk.
350 * - rtt_walk.g_llt points to the TABLE granule at level @rtt_walk::level.
351 * The granule is locked.
352 * - rtt_walk::index is the entry index at rtt_walk.g_llt for @map_addr.
353 */
354void rtt_walk_lock_unlock(struct granule *g_root,
355 int start_level,
356 unsigned long ipa_bits,
357 unsigned long map_addr,
358 long level,
359 struct rtt_walk *wi)
360{
361 struct granule *g_tbls[NR_RTT_LEVELS] = { NULL };
362 unsigned long sl_idx;
363 int i, last_level;
364
365 assert(start_level >= MIN_STARTING_LEVEL);
366 assert(level >= start_level);
367 assert(map_addr < (1UL << ipa_bits));
368 assert(wi != NULL);
369
370 /* Handle concatenated starting level (SL) tables */
371 sl_idx = s2_sl_addr_to_idx(map_addr, start_level, ipa_bits);
372 if (sl_idx >= S2TTES_PER_S2TT) {
AlexeiFedorov4faab852023-08-30 15:06:49 +0100373 unsigned int tt_num = (unsigned int)(sl_idx >> S2TTE_STRIDE);
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100374 struct granule *g_concat_root = (struct granule *)((uintptr_t)g_root +
375 (tt_num * sizeof(struct granule)));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000376
377 granule_lock(g_concat_root, GRANULE_STATE_RTT);
378 granule_unlock(g_root);
379 g_root = g_concat_root;
380 }
381
382 g_tbls[start_level] = g_root;
383 for (i = start_level; i < level; i++) {
384 /*
385 * Lock next RTT level. Correct locking order is guaranteed
386 * because reference is obtained from a locked granule
387 * (previous level). Also, hand-over-hand locking/unlocking is
388 * used to avoid race conditions.
389 */
390 g_tbls[i + 1] = __find_lock_next_level(g_tbls[i], map_addr, i);
391 if (g_tbls[i + 1] == NULL) {
392 last_level = i;
393 goto out;
394 }
395 granule_unlock(g_tbls[i]);
396 }
397
AlexeiFedorov4faab852023-08-30 15:06:49 +0100398 last_level = (int)level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000399out:
400 wi->last_level = last_level;
401 wi->g_llt = g_tbls[last_level];
402 wi->index = s2_addr_to_idx(map_addr, last_level);
403}
404
405/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100406 * Creates an unassigned_empty s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000407 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100408unsigned long s2tte_create_unassigned_empty(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000409{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100410 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100411}
412
413/*
414 * Creates an unassigned_ram s2tte.
415 */
416unsigned long s2tte_create_unassigned_ram(void)
417{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100418 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000419}
420
421/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100422 * Creates an unassigned_destroyed s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000423 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100424unsigned long s2tte_create_unassigned_destroyed(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000425{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100426 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
427}
428
429/*
430 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
431 * RIPAS=DESTROYED, at level @level.
432 */
433unsigned long s2tte_create_assigned_destroyed(unsigned long pa, long level)
434{
435 assert(level >= RTT_MIN_BLOCK_LEVEL);
436 assert(addr_is_level_aligned(pa, level));
437 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000438}
439
440/*
441 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
442 * RIPAS=EMPTY, at level @level.
443 */
444unsigned long s2tte_create_assigned_empty(unsigned long pa, long level)
445{
446 assert(level >= RTT_MIN_BLOCK_LEVEL);
447 assert(addr_is_level_aligned(pa, level));
448 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
449}
450
451/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100452 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000453 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100454unsigned long s2tte_create_assigned_ram(unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000455{
456 assert(level >= RTT_MIN_BLOCK_LEVEL);
457 assert(addr_is_level_aligned(pa, level));
458 if (level == RTT_PAGE_LEVEL) {
459 return (pa | S2TTE_PAGE);
460 }
461 return (pa | S2TTE_BLOCK);
462}
463
464/*
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100465 * Creates an assigned s2tte with output address @pa and the same
466 * RIPAS as passed on @s2tte.
467 */
468unsigned long s2tte_create_assigned_unchanged(unsigned long s2tte,
469 unsigned long pa,
470 long level)
471{
472 unsigned long current_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
473
474 assert(level >= RTT_MIN_BLOCK_LEVEL);
475 assert(addr_is_level_aligned(pa, level));
476 assert(EXTRACT(S2TTE_INVALID_RIPAS, current_ripas) <=
477 EXTRACT(S2TTE_INVALID_RIPAS, S2TTE_INVALID_RIPAS_DESTROYED));
478
479 if (current_ripas != S2TTE_INVALID_RIPAS_RAM) {
480 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | current_ripas);
481 }
482
483 return s2tte_create_assigned_ram(pa, level);
484}
485
486/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100487 * Creates an unassigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000488 */
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100489unsigned long s2tte_create_unassigned_ns(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000490{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100491 return (S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED |
492 S2TTE_INVALID_UNPROTECTED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000493}
494
495/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100496 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000497 *
498 * The following S2 TTE fields are provided through @s2tte argument:
499 * - The physical address
500 * - MemAttr
501 * - S2AP
502 * - Shareability
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100503 * Any other field on @s2tte is masked out.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000504 */
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100505unsigned long s2tte_create_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000506{
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100507 unsigned long new_s2tte = s2tte & ~DESC_TYPE_MASK;
508
Soby Mathewb4c6df42022-11-09 11:13:29 +0000509 assert(level >= RTT_MIN_BLOCK_LEVEL);
510 if (level == RTT_PAGE_LEVEL) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100511 return (new_s2tte | S2TTE_PAGE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000512 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100513 return (new_s2tte | S2TTE_BLOCK_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000514}
515
516/*
517 * Validate the portion of NS S2TTE that is provided by the host.
518 */
519bool host_ns_s2tte_is_valid(unsigned long s2tte, long level)
520{
521 unsigned long mask = addr_level_mask(~0UL, level) |
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100522 S2TTE_NS_ATTR_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000523
524 /*
525 * Test that all fields that are not controlled by the host are zero
526 * and that the output address is correctly aligned. Note that
527 * the host is permitted to map any physical address outside PAR.
528 */
529 if ((s2tte & ~mask) != 0UL) {
530 return false;
531 }
532
533 /*
534 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
535 */
536 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
537 return false;
538 }
539
540 /*
541 * Only one value masked by S2TTE_SH_MASK is invalid/reserved.
542 */
543 if ((s2tte & S2TTE_SH_MASK) == S2TTE_SH_RESERVED) {
544 return false;
545 }
546
547 /*
548 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
549 */
550 return true;
551}
552
553/*
554 * Returns the portion of NS S2TTE that is set by the host.
555 */
556unsigned long host_ns_s2tte(unsigned long s2tte, long level)
557{
558 unsigned long mask = addr_level_mask(~0UL, level) |
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100559 S2TTE_NS_ATTR_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000560 return (s2tte & mask);
561}
562
563/*
564 * Creates a table s2tte at level @level with output address @pa.
565 */
566unsigned long s2tte_create_table(unsigned long pa, long level)
567{
568 assert(level < RTT_PAGE_LEVEL);
569 assert(GRANULE_ALIGNED(pa));
570
571 return (pa | S2TTE_TABLE);
572}
573
574/*
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100575 * Returns true if s2tte has defined ripas value, namely if it is one of:
576 * - unassigned_empty
577 * - unassigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100578 * - unassigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100579 * - assigned_empty
580 * - assigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100581 * - assigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100582 */
583bool s2tte_has_ripas(unsigned long s2tte, long level)
584{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100585 return (((s2tte & S2TTE_NS) == 0UL) && !s2tte_is_table(s2tte, level));
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100586}
587
588/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000589 * Returns true if @s2tte has HIPAS=@hipas.
590 */
591static bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
592{
593 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
594 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
595
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100596 return ((desc_type == S2TTE_INVALID) && (invalid_desc_hipas == hipas));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000597}
598
599/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100600 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000601 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100602static bool s2tte_has_unassigned_ripas(unsigned long s2tte, unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000603{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100604 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
605 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
606}
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100607
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100608/*
609 * Returns true if @s2tte has HIPAS=ASSIGNED and RIPAS=@ripas.
610 */
611static bool s2tte_has_assigned_ripas(unsigned long s2tte, unsigned long ripas)
612{
613 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
614 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100615}
616
617/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100618 * Returns true if @s2tte has HIPAS=UNASSIGNED.
619 */
620bool s2tte_is_unassigned(unsigned long s2tte)
621{
622 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED);
623}
624
625/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100626 * Returns true if @s2tte is an unassigned_empty.
627 */
628bool s2tte_is_unassigned_empty(unsigned long s2tte)
629{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100630 return (((s2tte & S2TTE_NS) == 0UL) &&
631 s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100632}
633
634/*
635 * Returns true if @s2tte is an unassigned_ram.
636 */
637bool s2tte_is_unassigned_ram(unsigned long s2tte)
638{
639 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
640}
641
642/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100643 * Returns true if @s2tte is unassigned_ns.
644 */
645bool s2tte_is_unassigned_ns(unsigned long s2tte)
646{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100647 return (((s2tte & S2TTE_NS) != 0UL) &&
648 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000649}
650
651/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100652 * Returns true if @s2tte has RIPAS=DESTROYED.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000653 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100654bool s2tte_is_unassigned_destroyed(unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000655{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100656 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
657}
658
659/*
660 * Returns true if @s2tte is an assigned_destroyed.
661 */
662bool s2tte_is_assigned_destroyed(unsigned long s2tte, long level)
663{
664 (void)level;
665
666 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000667}
668
669/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100670 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000671 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100672bool s2tte_is_assigned_empty(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000673{
674 (void)level;
675
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100676 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000677}
678
679static bool s2tte_check(unsigned long s2tte, long level, unsigned long ns)
680{
681 unsigned long desc_type;
682
683 if ((s2tte & S2TTE_NS) != ns) {
684 return false;
685 }
686
687 desc_type = s2tte & DESC_TYPE_MASK;
688
689 /* Only pages at L3 and valid blocks at L2 allowed */
690 if (((level == RTT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000691 ((level == RTT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK))) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000692 return true;
693 }
694
695 return false;
696}
697
698/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100699 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000700 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100701bool s2tte_is_assigned_ram(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000702{
703 return s2tte_check(s2tte, level, 0UL);
704}
705
706/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100707 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000708 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100709bool s2tte_is_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000710{
711 return s2tte_check(s2tte, level, S2TTE_NS);
712}
713
714/*
715 * Returns true if @s2tte is a table at level @level.
716 */
717bool s2tte_is_table(unsigned long s2tte, long level)
718{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100719 return ((level < RTT_PAGE_LEVEL) &&
720 ((s2tte & DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000721}
722
723/*
724 * Returns RIPAS of @s2tte.
725 *
726 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
727 * The s2tte must be not valid/invalid descriptor.
728 */
729enum ripas s2tte_get_ripas(unsigned long s2tte)
730{
731 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
732
733 /*
734 * If valid s2tte descriptor is passed, then ensure S2AP[0]
735 * bit is 1 (S2AP is set to RW for lower EL), which corresponds
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100736 * to RIPAS_RAM (bits[6:5] = b01) on a valid descriptor.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000737 */
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100738 if (((s2tte & DESC_TYPE_MASK) != S2TTE_INVALID) &&
Soby Mathewb4c6df42022-11-09 11:13:29 +0000739 (desc_ripas != S2TTE_INVALID_RIPAS_RAM)) {
740 assert(false);
741 }
742
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100743 switch (desc_ripas) {
744 case S2TTE_INVALID_RIPAS_EMPTY:
Yousuf A62808152022-10-31 10:35:42 +0000745 return RIPAS_EMPTY;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100746 case S2TTE_INVALID_RIPAS_RAM:
747 return RIPAS_RAM;
748 default:
749 assert(desc_ripas == S2TTE_INVALID_RIPAS_DESTROYED);
750 return RIPAS_DESTROYED;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000751 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000752}
753
754/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100755 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000756 *
757 * The granule is populated before it is made a table,
758 * hence, don't use s2tte_write for access.
759 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100760void s2tt_init_unassigned_empty(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000761{
762 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100763 s2tt[i] = s2tte_create_unassigned_empty();
764 }
765
766 dsb(ish);
767}
768
769/*
770 * Populates @s2tt with unassigned_ram s2ttes.
771 *
772 * The granule is populated before it is made a table,
773 * hence, don't use s2tte_write for access.
774 */
775void s2tt_init_unassigned_ram(unsigned long *s2tt)
776{
777 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
778 s2tt[i] = s2tte_create_unassigned_ram();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000779 }
780
781 dsb(ish);
782}
783
784/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100785 * Populates @s2tt with unassigned_ns s2ttes.
786 *
787 * The granule is populated before it is made a table,
788 * hence, don't use s2tte_write for access.
789 */
790void s2tt_init_unassigned_ns(unsigned long *s2tt)
791{
792 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
793 s2tt[i] = s2tte_create_unassigned_ns();
794 }
795
796 dsb(ish);
797}
798
799/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000800 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
801 *
802 * The granule is populated before it is made a table,
803 * hence, don't use s2tte_write for access.
804 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100805void s2tt_init_unassigned_destroyed(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000806{
807 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100808 s2tt[i] = s2tte_create_unassigned_destroyed();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000809 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100810 dsb(ish);
811}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000812
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100813/*
814 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
815 * contiguous memory block starting at @pa, and mapped at level @level.
816 *
817 * The granule is populated before it is made a table,
818 * hence, don't use s2tte_write for access.
819 */
820void s2tt_init_assigned_destroyed(unsigned long *s2tt, unsigned long pa, long level)
821{
822 const unsigned long map_size = s2tte_map_size(level);
823
824 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
825 s2tt[i] = s2tte_create_assigned_destroyed(pa, level);
826 pa += map_size;
827 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000828 dsb(ish);
829}
830
AlexeiFedorov4faab852023-08-30 15:06:49 +0100831unsigned long s2tte_map_size(long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000832{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100833 unsigned int levels, lsb;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000834
835 assert(level <= RTT_PAGE_LEVEL);
836
AlexeiFedorov4faab852023-08-30 15:06:49 +0100837 levels = (unsigned int)(RTT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100838 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100839 return (1UL << lsb);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000840}
841
842/*
843 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
844 * contiguous memory block starting at @pa, and mapped at level @level.
845 *
846 * The granule is populated before it is made a table,
847 * hence, don't use s2tte_write for access.
848 */
849void s2tt_init_assigned_empty(unsigned long *s2tt, unsigned long pa, long level)
850{
851 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000852
AlexeiFedorov3a739332023-04-13 13:54:04 +0100853 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000854 s2tt[i] = s2tte_create_assigned_empty(pa, level);
855 pa += map_size;
856 }
857 dsb(ish);
858}
859
860/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100861 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000862 * contiguous memory block starting at @pa, and mapped at level @level.
863 *
864 * The granule is populated before it is made a table,
865 * hence, don't use s2tte_write for access.
866 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100867void s2tt_init_assigned_ram(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000868{
869 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000870
AlexeiFedorov3a739332023-04-13 13:54:04 +0100871 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
872 s2tt[i] = s2tte_create_assigned_ram(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000873 pa += map_size;
874 }
875 dsb(ish);
876}
877
878/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100879 * Populates @s2tt with NS attributes @attrs that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000880 * contiguous memory block starting at @pa, and mapped at level @level.
881 *
882 * The granule is populated before it is made a table,
883 * hence, don't use s2tte_write for access.
884 */
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100885void s2tt_init_assigned_ns(unsigned long *s2tt, unsigned long attrs,
886 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000887{
888 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000889
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100890 assert(addr_is_level_aligned(pa, level));
891
AlexeiFedorov3a739332023-04-13 13:54:04 +0100892 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100893 unsigned long s2tte = attrs & S2TTE_NS_ATTR_MASK;
894
895 s2tt[i] = s2tte_create_assigned_ns(s2tte | pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000896 pa += map_size;
897 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100898
Soby Mathewb4c6df42022-11-09 11:13:29 +0000899 dsb(ish);
900}
901
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100902/*
903 * Returns true if s2tte has 'output address' field, namely, if it is one of:
904 * - assigned_empty
905 * - assigned_ram
906 * - assigned_ns
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100907 * - assigned_destroyed
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100908 * - table
909 */
AlexeiFedorov7641a812023-08-22 14:31:27 +0100910static bool s2tte_has_pa(unsigned long s2tte, long level)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100911{
912 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
913
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100914 return ((desc_type != S2TTE_INVALID) || /* block, page or table */
915 s2tte_is_assigned_empty(s2tte, level) ||
916 s2tte_is_assigned_destroyed(s2tte, level));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100917}
918
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100919/*
920 * Returns true if s2tte is a live RTTE entry. i.e.,
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100921 * HIPAS is ASSIGNED.
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100922 *
923 * NOTE: For now, only the RTTE with PA are live.
924 * This could change with EXPORT/IMPORT support.
925 */
AlexeiFedorov7641a812023-08-22 14:31:27 +0100926static bool s2tte_is_live(unsigned long s2tte, long level)
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100927{
928 return s2tte_has_pa(s2tte, level);
929}
930
Soby Mathewb4c6df42022-11-09 11:13:29 +0000931/* Returns physical address of a page entry or block */
932unsigned long s2tte_pa(unsigned long s2tte, long level)
933{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100934 if (!s2tte_has_pa(s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000935 assert(false);
936 }
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100937
938 if (s2tte_is_table(s2tte, level)) {
939 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
940 }
941
Soby Mathewb4c6df42022-11-09 11:13:29 +0000942 return addr_level_mask(s2tte, level);
943}
944
945/* Returns physical address of a table entry */
946unsigned long s2tte_pa_table(unsigned long s2tte, long level)
947{
948 assert(s2tte_is_table(s2tte, level));
949 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
950}
951
952bool addr_is_level_aligned(unsigned long addr, long level)
953{
954 return (addr == addr_level_mask(addr, level));
955}
956
957typedef bool (*s2tte_type_checker)(unsigned long s2tte);
958
959static bool __table_is_uniform_block(unsigned long *table,
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100960 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000961{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100962 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
963 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000964
965 if (!s2tte_is_x(s2tte)) {
966 return false;
967 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000968 }
969
970 return true;
971}
972
973/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100974 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000975 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100976bool table_is_unassigned_empty_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000977{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100978 return __table_is_uniform_block(table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100979}
980
981/*
982 * Returns true if all s2ttes in @table are unassigned_ram.
983 */
984bool table_is_unassigned_ram_block(unsigned long *table)
985{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100986 return __table_is_uniform_block(table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000987}
988
989/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100990 * Returns true if all s2ttes in @table are unassigned_ns
991 */
992bool table_is_unassigned_ns_block(unsigned long *table)
993{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100994 return __table_is_uniform_block(table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100995}
996
997/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100998 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +0000999 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001000bool table_is_unassigned_destroyed_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001001{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001002 return __table_is_uniform_block(table, s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001003}
1004
1005typedef bool (*s2tte_type_level_checker)(unsigned long s2tte, long level);
1006
1007static bool __table_maps_block(unsigned long *table,
1008 long level,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001009 s2tte_type_level_checker s2tte_is_x,
1010 bool check_ns_attrs)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001011{
1012 unsigned long base_pa;
1013 unsigned long map_size = s2tte_map_size(level);
1014 unsigned long s2tte = s2tte_read(&table[0]);
1015 unsigned int i;
1016
1017 if (!s2tte_is_x(s2tte, level)) {
1018 return false;
1019 }
1020
1021 base_pa = s2tte_pa(s2tte, level);
1022 if (!addr_is_level_aligned(base_pa, level - 1L)) {
1023 return false;
1024 }
1025
1026 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
1027 unsigned long expected_pa = base_pa + (i * map_size);
1028
1029 s2tte = s2tte_read(&table[i]);
1030
1031 if (!s2tte_is_x(s2tte, level)) {
1032 return false;
1033 }
1034
1035 if (s2tte_pa(s2tte, level) != expected_pa) {
1036 return false;
1037 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001038
1039 if (check_ns_attrs) {
1040 unsigned long ns_attrs = s2tte & S2TTE_NS_ATTR_MASK;
1041
1042 /*
1043 * We match all the attributes in the S2TTE
1044 * except for the AF bit.
1045 */
1046 if ((s2tte & S2TTE_NS_ATTR_MASK) != ns_attrs) {
1047 return false;
1048 }
1049 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001050 }
1051
1052 return true;
1053}
1054
1055/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001056 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +00001057 * and refer to a contiguous block of granules aligned to @level - 1.
1058 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001059bool table_maps_assigned_empty_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001060{
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001061 return __table_maps_block(table, level, s2tte_is_assigned_empty,
1062 false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001063}
1064
1065/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001066 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001067 * refer to a contiguous block of granules aligned to @level - 1.
1068 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001069bool table_maps_assigned_ram_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001070{
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001071 return __table_maps_block(table, level, s2tte_is_assigned_ram, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001072}
1073
1074/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001075 * Returns true if
1076 * - all s2ttes in @table are assigned_ns s2ttes and
1077 * - they refer to a contiguous block of granules aligned to @level - 1 and
1078 * - all the s2tte attributes in @table controlled by the host are identical
AlexeiFedorov3a739332023-04-13 13:54:04 +01001079 *
1080 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001081 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001082bool table_maps_assigned_ns_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001083{
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001084 return __table_maps_block(table, level, s2tte_is_assigned_ns, true);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001085}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001086
1087/*
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001088 * Returns true if all s2ttes are assigned_destroyed and
1089 * refer to a contiguous block of granules aligned to @level - 1.
1090 */
1091bool table_maps_assigned_destroyed_block(unsigned long *table, long level)
1092{
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001093 return __table_maps_block(table, level, s2tte_is_assigned_destroyed,
1094 false);
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001095}
1096
1097/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001098 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001099 * skip the non-live entries (i.e., HIPAS=UNASSIGNED).
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001100 * In other words, the scanning stops when a live RTTE is encountered or we
1101 * reach the end of this RTT.
1102 *
1103 * For now an RTTE can be considered non-live if it doesn't have a PA.
1104 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1105 * in the RTTE.
1106 *
1107 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1108 * with RMI_ERROR_RTT).
1109 *
1110 * Returns:
1111 * - If the entry @wi.index is live, returns @addr.
1112 * - If none of the entries in the @s2tt are "live", returns the address of the
1113 * first entry in the next table.
1114 * - Otherwise, the address of the first live entry in @s2tt
1115 */
1116unsigned long skip_non_live_entries(unsigned long addr,
1117 unsigned long *s2tt,
1118 const struct rtt_walk *wi)
1119{
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001120 unsigned long i, index = wi->index;
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001121 long level = wi->last_level;
1122 unsigned long map_size;
1123
1124 /*
1125 * If the entry for the map_addr is live,
1126 * return @addr.
1127 */
1128 if (s2tte_is_live(s2tte_read(&s2tt[index]), level)) {
1129 return addr;
1130 }
1131
1132 /*
1133 * Align the address DOWN to the map_size, as expected for the @level,
1134 * so that we can compute the correct address by using the index.
1135 */
1136 map_size = s2tte_map_size(level);
1137 addr &= ~(map_size - 1UL);
1138
1139 /* Skip the "index" */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001140 for (i = index + 1UL; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001141 unsigned long s2tte = s2tte_read(&s2tt[i]);
1142
1143 if (s2tte_is_live(s2tte, level)) {
1144 break;
1145 }
1146 }
1147
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001148 return (addr + ((i - index) * map_size));
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001149}