blob: b66dde6405e24cd1299e5b77c8e7f8cb94cfddcf [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);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000374 struct granule *g_concat_root = g_root + tt_num;
375
376 granule_lock(g_concat_root, GRANULE_STATE_RTT);
377 granule_unlock(g_root);
378 g_root = g_concat_root;
379 }
380
381 g_tbls[start_level] = g_root;
382 for (i = start_level; i < level; i++) {
383 /*
384 * Lock next RTT level. Correct locking order is guaranteed
385 * because reference is obtained from a locked granule
386 * (previous level). Also, hand-over-hand locking/unlocking is
387 * used to avoid race conditions.
388 */
389 g_tbls[i + 1] = __find_lock_next_level(g_tbls[i], map_addr, i);
390 if (g_tbls[i + 1] == NULL) {
391 last_level = i;
392 goto out;
393 }
394 granule_unlock(g_tbls[i]);
395 }
396
AlexeiFedorov4faab852023-08-30 15:06:49 +0100397 last_level = (int)level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000398out:
399 wi->last_level = last_level;
400 wi->g_llt = g_tbls[last_level];
401 wi->index = s2_addr_to_idx(map_addr, last_level);
402}
403
404/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100405 * Creates an unassigned_empty s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000406 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100407unsigned long s2tte_create_unassigned_empty(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000408{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100409 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100410}
411
412/*
413 * Creates an unassigned_ram s2tte.
414 */
415unsigned long s2tte_create_unassigned_ram(void)
416{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100417 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000418}
419
420/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100421 * Creates an unassigned_destroyed s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000422 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100423unsigned long s2tte_create_unassigned_destroyed(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000424{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100425 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
426}
427
428/*
429 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
430 * RIPAS=DESTROYED, at level @level.
431 */
432unsigned long s2tte_create_assigned_destroyed(unsigned long pa, long level)
433{
434 assert(level >= RTT_MIN_BLOCK_LEVEL);
435 assert(addr_is_level_aligned(pa, level));
436 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000437}
438
439/*
440 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
441 * RIPAS=EMPTY, at level @level.
442 */
443unsigned long s2tte_create_assigned_empty(unsigned long pa, long level)
444{
445 assert(level >= RTT_MIN_BLOCK_LEVEL);
446 assert(addr_is_level_aligned(pa, level));
447 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
448}
449
450/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100451 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000452 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100453unsigned long s2tte_create_assigned_ram(unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000454{
455 assert(level >= RTT_MIN_BLOCK_LEVEL);
456 assert(addr_is_level_aligned(pa, level));
457 if (level == RTT_PAGE_LEVEL) {
458 return (pa | S2TTE_PAGE);
459 }
460 return (pa | S2TTE_BLOCK);
461}
462
463/*
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100464 * Creates an assigned s2tte with output address @pa and the same
465 * RIPAS as passed on @s2tte.
466 */
467unsigned long s2tte_create_assigned_unchanged(unsigned long s2tte,
468 unsigned long pa,
469 long level)
470{
471 unsigned long current_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
472
473 assert(level >= RTT_MIN_BLOCK_LEVEL);
474 assert(addr_is_level_aligned(pa, level));
475 assert(EXTRACT(S2TTE_INVALID_RIPAS, current_ripas) <=
476 EXTRACT(S2TTE_INVALID_RIPAS, S2TTE_INVALID_RIPAS_DESTROYED));
477
478 if (current_ripas != S2TTE_INVALID_RIPAS_RAM) {
479 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | current_ripas);
480 }
481
482 return s2tte_create_assigned_ram(pa, level);
483}
484
485/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100486 * Creates an unassigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000487 */
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100488unsigned long s2tte_create_unassigned_ns(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000489{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100490 return (S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED |
491 S2TTE_INVALID_UNPROTECTED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000492}
493
494/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100495 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000496 *
497 * The following S2 TTE fields are provided through @s2tte argument:
498 * - The physical address
499 * - MemAttr
500 * - S2AP
501 * - Shareability
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100502 * Any other field on @s2tte is masked out.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000503 */
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100504unsigned long s2tte_create_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000505{
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100506 unsigned long new_s2tte = s2tte & ~DESC_TYPE_MASK;
507
Soby Mathewb4c6df42022-11-09 11:13:29 +0000508 assert(level >= RTT_MIN_BLOCK_LEVEL);
509 if (level == RTT_PAGE_LEVEL) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100510 return (new_s2tte | S2TTE_PAGE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000511 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100512 return (new_s2tte | S2TTE_BLOCK_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000513}
514
515/*
516 * Validate the portion of NS S2TTE that is provided by the host.
517 */
518bool host_ns_s2tte_is_valid(unsigned long s2tte, long level)
519{
520 unsigned long mask = addr_level_mask(~0UL, level) |
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100521 S2TTE_NS_ATTR_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000522
523 /*
524 * Test that all fields that are not controlled by the host are zero
525 * and that the output address is correctly aligned. Note that
526 * the host is permitted to map any physical address outside PAR.
527 */
528 if ((s2tte & ~mask) != 0UL) {
529 return false;
530 }
531
532 /*
533 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
534 */
535 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
536 return false;
537 }
538
539 /*
540 * Only one value masked by S2TTE_SH_MASK is invalid/reserved.
541 */
542 if ((s2tte & S2TTE_SH_MASK) == S2TTE_SH_RESERVED) {
543 return false;
544 }
545
546 /*
547 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
548 */
549 return true;
550}
551
552/*
553 * Returns the portion of NS S2TTE that is set by the host.
554 */
555unsigned long host_ns_s2tte(unsigned long s2tte, long level)
556{
557 unsigned long mask = addr_level_mask(~0UL, level) |
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100558 S2TTE_NS_ATTR_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000559 return (s2tte & mask);
560}
561
562/*
563 * Creates a table s2tte at level @level with output address @pa.
564 */
565unsigned long s2tte_create_table(unsigned long pa, long level)
566{
567 assert(level < RTT_PAGE_LEVEL);
568 assert(GRANULE_ALIGNED(pa));
569
570 return (pa | S2TTE_TABLE);
571}
572
573/*
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100574 * Returns true if s2tte has defined ripas value, namely if it is one of:
575 * - unassigned_empty
576 * - unassigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100577 * - unassigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100578 * - assigned_empty
579 * - assigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100580 * - assigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100581 */
582bool s2tte_has_ripas(unsigned long s2tte, long level)
583{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100584 return (((s2tte & S2TTE_NS) == 0UL) && !s2tte_is_table(s2tte, level));
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100585}
586
587/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000588 * Returns true if @s2tte has HIPAS=@hipas.
589 */
590static bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
591{
592 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
593 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
594
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100595 return ((desc_type == S2TTE_INVALID) && (invalid_desc_hipas == hipas));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000596}
597
598/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100599 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000600 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100601static bool s2tte_has_unassigned_ripas(unsigned long s2tte, unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000602{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100603 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
604 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
605}
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100606
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100607/*
608 * Returns true if @s2tte has HIPAS=ASSIGNED and RIPAS=@ripas.
609 */
610static bool s2tte_has_assigned_ripas(unsigned long s2tte, unsigned long ripas)
611{
612 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
613 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100614}
615
616/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100617 * Returns true if @s2tte has HIPAS=UNASSIGNED.
618 */
619bool s2tte_is_unassigned(unsigned long s2tte)
620{
621 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED);
622}
623
624/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100625 * Returns true if @s2tte is an unassigned_empty.
626 */
627bool s2tte_is_unassigned_empty(unsigned long s2tte)
628{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100629 return (((s2tte & S2TTE_NS) == 0UL) &&
630 s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100631}
632
633/*
634 * Returns true if @s2tte is an unassigned_ram.
635 */
636bool s2tte_is_unassigned_ram(unsigned long s2tte)
637{
638 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
639}
640
641/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100642 * Returns true if @s2tte is unassigned_ns.
643 */
644bool s2tte_is_unassigned_ns(unsigned long s2tte)
645{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100646 return (((s2tte & S2TTE_NS) != 0UL) &&
647 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000648}
649
650/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100651 * Returns true if @s2tte has RIPAS=DESTROYED.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000652 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100653bool s2tte_is_unassigned_destroyed(unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000654{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100655 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
656}
657
658/*
659 * Returns true if @s2tte is an assigned_destroyed.
660 */
661bool s2tte_is_assigned_destroyed(unsigned long s2tte, long level)
662{
663 (void)level;
664
665 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000666}
667
668/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100669 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000670 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100671bool s2tte_is_assigned_empty(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000672{
673 (void)level;
674
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100675 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000676}
677
678static bool s2tte_check(unsigned long s2tte, long level, unsigned long ns)
679{
680 unsigned long desc_type;
681
682 if ((s2tte & S2TTE_NS) != ns) {
683 return false;
684 }
685
686 desc_type = s2tte & DESC_TYPE_MASK;
687
688 /* Only pages at L3 and valid blocks at L2 allowed */
689 if (((level == RTT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000690 ((level == RTT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK))) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000691 return true;
692 }
693
694 return false;
695}
696
697/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100698 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000699 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100700bool s2tte_is_assigned_ram(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000701{
702 return s2tte_check(s2tte, level, 0UL);
703}
704
705/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100706 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000707 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100708bool s2tte_is_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000709{
710 return s2tte_check(s2tte, level, S2TTE_NS);
711}
712
713/*
714 * Returns true if @s2tte is a table at level @level.
715 */
716bool s2tte_is_table(unsigned long s2tte, long level)
717{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100718 return ((level < RTT_PAGE_LEVEL) &&
719 ((s2tte & DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000720}
721
722/*
723 * Returns RIPAS of @s2tte.
724 *
725 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
726 * The s2tte must be not valid/invalid descriptor.
727 */
728enum ripas s2tte_get_ripas(unsigned long s2tte)
729{
730 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
731
732 /*
733 * If valid s2tte descriptor is passed, then ensure S2AP[0]
734 * bit is 1 (S2AP is set to RW for lower EL), which corresponds
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100735 * to RIPAS_RAM (bits[6:5] = b01) on a valid descriptor.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000736 */
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100737 if (((s2tte & DESC_TYPE_MASK) != S2TTE_INVALID) &&
Soby Mathewb4c6df42022-11-09 11:13:29 +0000738 (desc_ripas != S2TTE_INVALID_RIPAS_RAM)) {
739 assert(false);
740 }
741
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100742 switch (desc_ripas) {
743 case S2TTE_INVALID_RIPAS_EMPTY:
Yousuf A62808152022-10-31 10:35:42 +0000744 return RIPAS_EMPTY;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100745 case S2TTE_INVALID_RIPAS_RAM:
746 return RIPAS_RAM;
747 default:
748 assert(desc_ripas == S2TTE_INVALID_RIPAS_DESTROYED);
749 return RIPAS_DESTROYED;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000750 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000751}
752
753/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100754 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000755 *
756 * The granule is populated before it is made a table,
757 * hence, don't use s2tte_write for access.
758 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100759void s2tt_init_unassigned_empty(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000760{
761 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100762 s2tt[i] = s2tte_create_unassigned_empty();
763 }
764
765 dsb(ish);
766}
767
768/*
769 * Populates @s2tt with unassigned_ram s2ttes.
770 *
771 * The granule is populated before it is made a table,
772 * hence, don't use s2tte_write for access.
773 */
774void s2tt_init_unassigned_ram(unsigned long *s2tt)
775{
776 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
777 s2tt[i] = s2tte_create_unassigned_ram();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000778 }
779
780 dsb(ish);
781}
782
783/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100784 * Populates @s2tt with unassigned_ns s2ttes.
785 *
786 * The granule is populated before it is made a table,
787 * hence, don't use s2tte_write for access.
788 */
789void s2tt_init_unassigned_ns(unsigned long *s2tt)
790{
791 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
792 s2tt[i] = s2tte_create_unassigned_ns();
793 }
794
795 dsb(ish);
796}
797
798/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000799 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
800 *
801 * The granule is populated before it is made a table,
802 * hence, don't use s2tte_write for access.
803 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100804void s2tt_init_unassigned_destroyed(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000805{
806 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100807 s2tt[i] = s2tte_create_unassigned_destroyed();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000808 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100809 dsb(ish);
810}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000811
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100812/*
813 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
814 * contiguous memory block starting at @pa, and mapped at level @level.
815 *
816 * The granule is populated before it is made a table,
817 * hence, don't use s2tte_write for access.
818 */
819void s2tt_init_assigned_destroyed(unsigned long *s2tt, unsigned long pa, long level)
820{
821 const unsigned long map_size = s2tte_map_size(level);
822
823 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
824 s2tt[i] = s2tte_create_assigned_destroyed(pa, level);
825 pa += map_size;
826 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000827 dsb(ish);
828}
829
AlexeiFedorov4faab852023-08-30 15:06:49 +0100830unsigned long s2tte_map_size(long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000831{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100832 unsigned int levels, lsb;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000833
834 assert(level <= RTT_PAGE_LEVEL);
835
AlexeiFedorov4faab852023-08-30 15:06:49 +0100836 levels = (unsigned int)(RTT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100837 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100838 return (1UL << lsb);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000839}
840
841/*
842 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
843 * contiguous memory block starting at @pa, and mapped at level @level.
844 *
845 * The granule is populated before it is made a table,
846 * hence, don't use s2tte_write for access.
847 */
848void s2tt_init_assigned_empty(unsigned long *s2tt, unsigned long pa, long level)
849{
850 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000851
AlexeiFedorov3a739332023-04-13 13:54:04 +0100852 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000853 s2tt[i] = s2tte_create_assigned_empty(pa, level);
854 pa += map_size;
855 }
856 dsb(ish);
857}
858
859/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100860 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000861 * contiguous memory block starting at @pa, and mapped at level @level.
862 *
863 * The granule is populated before it is made a table,
864 * hence, don't use s2tte_write for access.
865 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100866void s2tt_init_assigned_ram(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000867{
868 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000869
AlexeiFedorov3a739332023-04-13 13:54:04 +0100870 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
871 s2tt[i] = s2tte_create_assigned_ram(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000872 pa += map_size;
873 }
874 dsb(ish);
875}
876
877/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100878 * Populates @s2tt with NS attributes @attrs that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000879 * contiguous memory block starting at @pa, and mapped at level @level.
880 *
881 * The granule is populated before it is made a table,
882 * hence, don't use s2tte_write for access.
883 */
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100884void s2tt_init_assigned_ns(unsigned long *s2tt, unsigned long attrs,
885 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000886{
887 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000888
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100889 assert(addr_is_level_aligned(pa, level));
890
AlexeiFedorov3a739332023-04-13 13:54:04 +0100891 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100892 unsigned long s2tte = attrs & S2TTE_NS_ATTR_MASK;
893
894 s2tt[i] = s2tte_create_assigned_ns(s2tte | pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000895 pa += map_size;
896 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100897
Soby Mathewb4c6df42022-11-09 11:13:29 +0000898 dsb(ish);
899}
900
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100901/*
902 * Returns true if s2tte has 'output address' field, namely, if it is one of:
903 * - assigned_empty
904 * - assigned_ram
905 * - assigned_ns
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100906 * - assigned_destroyed
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100907 * - table
908 */
AlexeiFedorov7641a812023-08-22 14:31:27 +0100909static bool s2tte_has_pa(unsigned long s2tte, long level)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100910{
911 unsigned long desc_type = s2tte & DESC_TYPE_MASK;
912
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100913 return ((desc_type != S2TTE_INVALID) || /* block, page or table */
914 s2tte_is_assigned_empty(s2tte, level) ||
915 s2tte_is_assigned_destroyed(s2tte, level));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100916}
917
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100918/*
919 * Returns true if s2tte is a live RTTE entry. i.e.,
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100920 * HIPAS is ASSIGNED.
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100921 *
922 * NOTE: For now, only the RTTE with PA are live.
923 * This could change with EXPORT/IMPORT support.
924 */
AlexeiFedorov7641a812023-08-22 14:31:27 +0100925static bool s2tte_is_live(unsigned long s2tte, long level)
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100926{
927 return s2tte_has_pa(s2tte, level);
928}
929
Soby Mathewb4c6df42022-11-09 11:13:29 +0000930/* Returns physical address of a page entry or block */
931unsigned long s2tte_pa(unsigned long s2tte, long level)
932{
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100933 if (!s2tte_has_pa(s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000934 assert(false);
935 }
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100936
937 if (s2tte_is_table(s2tte, level)) {
938 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
939 }
940
Soby Mathewb4c6df42022-11-09 11:13:29 +0000941 return addr_level_mask(s2tte, level);
942}
943
944/* Returns physical address of a table entry */
945unsigned long s2tte_pa_table(unsigned long s2tte, long level)
946{
947 assert(s2tte_is_table(s2tte, level));
948 return addr_level_mask(s2tte, RTT_PAGE_LEVEL);
949}
950
951bool addr_is_level_aligned(unsigned long addr, long level)
952{
953 return (addr == addr_level_mask(addr, level));
954}
955
956typedef bool (*s2tte_type_checker)(unsigned long s2tte);
957
958static bool __table_is_uniform_block(unsigned long *table,
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100959 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000960{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100961 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
962 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000963
964 if (!s2tte_is_x(s2tte)) {
965 return false;
966 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000967 }
968
969 return true;
970}
971
972/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100973 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000974 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100975bool table_is_unassigned_empty_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000976{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100977 return __table_is_uniform_block(table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100978}
979
980/*
981 * Returns true if all s2ttes in @table are unassigned_ram.
982 */
983bool table_is_unassigned_ram_block(unsigned long *table)
984{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100985 return __table_is_uniform_block(table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000986}
987
988/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100989 * Returns true if all s2ttes in @table are unassigned_ns
990 */
991bool table_is_unassigned_ns_block(unsigned long *table)
992{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100993 return __table_is_uniform_block(table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100994}
995
996/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100997 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +0000998 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100999bool table_is_unassigned_destroyed_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001000{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001001 return __table_is_uniform_block(table, s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001002}
1003
1004typedef bool (*s2tte_type_level_checker)(unsigned long s2tte, long level);
1005
1006static bool __table_maps_block(unsigned long *table,
1007 long level,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001008 s2tte_type_level_checker s2tte_is_x,
1009 bool check_ns_attrs)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001010{
1011 unsigned long base_pa;
1012 unsigned long map_size = s2tte_map_size(level);
1013 unsigned long s2tte = s2tte_read(&table[0]);
1014 unsigned int i;
1015
1016 if (!s2tte_is_x(s2tte, level)) {
1017 return false;
1018 }
1019
1020 base_pa = s2tte_pa(s2tte, level);
1021 if (!addr_is_level_aligned(base_pa, level - 1L)) {
1022 return false;
1023 }
1024
1025 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
1026 unsigned long expected_pa = base_pa + (i * map_size);
1027
1028 s2tte = s2tte_read(&table[i]);
1029
1030 if (!s2tte_is_x(s2tte, level)) {
1031 return false;
1032 }
1033
1034 if (s2tte_pa(s2tte, level) != expected_pa) {
1035 return false;
1036 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001037
1038 if (check_ns_attrs) {
1039 unsigned long ns_attrs = s2tte & S2TTE_NS_ATTR_MASK;
1040
1041 /*
1042 * We match all the attributes in the S2TTE
1043 * except for the AF bit.
1044 */
1045 if ((s2tte & S2TTE_NS_ATTR_MASK) != ns_attrs) {
1046 return false;
1047 }
1048 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001049 }
1050
1051 return true;
1052}
1053
1054/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001055 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +00001056 * and refer to a contiguous block of granules aligned to @level - 1.
1057 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001058bool table_maps_assigned_empty_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001059{
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001060 return __table_maps_block(table, level, s2tte_is_assigned_empty,
1061 false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001062}
1063
1064/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001065 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001066 * refer to a contiguous block of granules aligned to @level - 1.
1067 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001068bool table_maps_assigned_ram_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001069{
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001070 return __table_maps_block(table, level, s2tte_is_assigned_ram, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001071}
1072
1073/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001074 * Returns true if
1075 * - all s2ttes in @table are assigned_ns s2ttes and
1076 * - they refer to a contiguous block of granules aligned to @level - 1 and
1077 * - all the s2tte attributes in @table controlled by the host are identical
AlexeiFedorov3a739332023-04-13 13:54:04 +01001078 *
1079 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001080 */
AlexeiFedorov3a739332023-04-13 13:54:04 +01001081bool table_maps_assigned_ns_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001082{
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001083 return __table_maps_block(table, level, s2tte_is_assigned_ns, true);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001084}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001085
1086/*
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001087 * Returns true if all s2ttes are assigned_destroyed and
1088 * refer to a contiguous block of granules aligned to @level - 1.
1089 */
1090bool table_maps_assigned_destroyed_block(unsigned long *table, long level)
1091{
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001092 return __table_maps_block(table, level, s2tte_is_assigned_destroyed,
1093 false);
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001094}
1095
1096/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001097 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001098 * skip the non-live entries (i.e., HIPAS=UNASSIGNED).
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001099 * In other words, the scanning stops when a live RTTE is encountered or we
1100 * reach the end of this RTT.
1101 *
1102 * For now an RTTE can be considered non-live if it doesn't have a PA.
1103 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1104 * in the RTTE.
1105 *
1106 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1107 * with RMI_ERROR_RTT).
1108 *
1109 * Returns:
1110 * - If the entry @wi.index is live, returns @addr.
1111 * - If none of the entries in the @s2tt are "live", returns the address of the
1112 * first entry in the next table.
1113 * - Otherwise, the address of the first live entry in @s2tt
1114 */
1115unsigned long skip_non_live_entries(unsigned long addr,
1116 unsigned long *s2tt,
1117 const struct rtt_walk *wi)
1118{
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001119 unsigned long i, index = wi->index;
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001120 long level = wi->last_level;
1121 unsigned long map_size;
1122
1123 /*
1124 * If the entry for the map_addr is live,
1125 * return @addr.
1126 */
1127 if (s2tte_is_live(s2tte_read(&s2tt[index]), level)) {
1128 return addr;
1129 }
1130
1131 /*
1132 * Align the address DOWN to the map_size, as expected for the @level,
1133 * so that we can compute the correct address by using the index.
1134 */
1135 map_size = s2tte_map_size(level);
1136 addr &= ~(map_size - 1UL);
1137
1138 /* Skip the "index" */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001139 for (i = index + 1UL; i < S2TTES_PER_S2TT; i++) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001140 unsigned long s2tte = s2tte_read(&s2tt[i]);
1141
1142 if (s2tte_is_live(s2tte, level)) {
1143 break;
1144 }
1145 }
1146
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001147 return (addr + ((i - index) * map_size));
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001148}