blob: 130ffb1bafe34feb369d3b6786a2b063e3eaddf9 [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>
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010014#include <s2tt.h>
15#include <s2tt_pvt_defs.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000016#include <smc.h>
17#include <status.h>
18#include <stddef.h>
19#include <string.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000020
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010021/* TODO: Fix this when introducing LPA2 support */
22COMPILER_ASSERT(S2TT_MIN_STARTING_LEVEL >= 0);
Soby Mathewb4c6df42022-11-09 11:13:29 +000023
24/*
25 * Invalidates S2 TLB entries from [ipa, ipa + size] region tagged with `vmid`.
26 */
27static void stage2_tlbi_ipa(const struct realm_s2_context *s2_ctx,
28 unsigned long ipa,
29 unsigned long size)
30{
31 /*
32 * Notes:
33 *
34 * - This follows the description provided in the Arm ARM on
35 * "Invalidation of TLB entries from stage 2 translations".
36 *
37 * - @TODO: Provide additional information to this primitive so that
38 * we can utilize:
39 * - The TTL level hint, see FEAT_TTL,
40 * - Final level lookup only invalidation,
41 * - Address range invalidation.
42 */
43
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010044 assert(s2_ctx != NULL);
45
Soby Mathewb4c6df42022-11-09 11:13:29 +000046 /*
47 * Save the current content of vttb_el2.
48 */
49 unsigned long old_vttbr_el2 = read_vttbr_el2();
50
51 /*
52 * Make 'vmid' the `current vmid`. Note that the tlbi instructions
53 * bellow target the TLB entries that match the `current vmid`.
54 */
55 write_vttbr_el2(INPLACE(VTTBR_EL2_VMID, s2_ctx->vmid));
56 isb();
57
58 /*
59 * Invalidate entries in S2 TLB caches that
60 * match both `ipa` & the `current vmid`.
61 */
62 while (size != 0UL) {
63 tlbiipas2e1is(ipa >> 12);
64 size -= GRANULE_SIZE;
65 ipa += GRANULE_SIZE;
66 }
67 dsb(ish);
68
69 /*
70 * The architecture does not require TLB invalidation by IPA to affect
71 * combined Stage-1 + Stage-2 TLBs. Therefore we must invalidate all of
72 * Stage-1 (tagged with the `current vmid`) after invalidating Stage-2.
73 */
74 tlbivmalle1is();
75 dsb(ish);
76 isb();
77
78 /*
79 * Restore the old content of vttb_el2.
80 */
81 write_vttbr_el2(old_vttbr_el2);
82 isb();
83}
84
85/*
86 * Invalidate S2 TLB entries with "addr" IPA.
87 * Call this function after:
88 * 1. A L3 page desc has been removed.
89 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010090void s2tt_invalidate_page(const struct realm_s2_context *s2_ctx, unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +000091{
92 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
93}
94
95/*
96 * Invalidate S2 TLB entries with "addr" IPA.
97 * Call this function after:
98 * 1. A L2 block desc has been removed, or
99 * 2a. A L2 table desc has been removed, where
100 * 2b. All S2TTEs in L3 table that the L2 table desc was pointed to were invalid.
101 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100102void s2tt_invalidate_block(const struct realm_s2_context *s2_ctx, unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000103{
104 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
105}
106
107/*
108 * Invalidate S2 TLB entries with "addr" IPA.
109 * Call this function after:
110 * 1a. A L2 table desc has been removed, where
111 * 1b. Some S2TTEs in the table that the L2 table desc was pointed to were valid.
112 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100113void s2tt_invalidate_pages_in_block(const struct realm_s2_context *s2_ctx, unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000114{
115 stage2_tlbi_ipa(s2_ctx, addr, BLOCK_L2_SIZE);
116}
117
118/*
119 * Return the index of the entry describing @addr in the translation table at
120 * level @level. This only works for non-concatenated page tables, so should
121 * not be called to get the index for the starting level.
122 *
123 * See the library pseudocode
124 * aarch64/translation/vmsa_addrcalc/AArch64.TTEntryAddress on which this is
125 * modeled.
126 */
127static unsigned long s2_addr_to_idx(unsigned long addr, long level)
128{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100129 unsigned int levels, lsb;
130
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100131 levels = (unsigned int)(S2TT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100132 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000133
134 addr >>= lsb;
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100135 addr &= (1UL << S2TTE_STRIDE) - 1UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000136 return addr;
137}
138
139/*
140 * Return the index of the entry describing @addr in the translation table
141 * starting level. This may return an index >= S2TTES_PER_S2TT when the
142 * combination of @start_level and @ipa_bits implies concatenated
143 * stage 2 tables.
144 *
145 * See the library pseudocode
146 * aarch64/translation/vmsa_addrcalc/AArch64.S2SLTTEntryAddress on which
147 * this is modeled.
148 */
149static unsigned long s2_sl_addr_to_idx(unsigned long addr, int start_level,
150 unsigned long ipa_bits)
151{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100152 unsigned int levels, lsb;
153
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100154 levels = (unsigned int)(S2TT_PAGE_LEVEL - start_level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100155 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000156
157 addr &= (1UL << ipa_bits) - 1UL;
158 addr >>= lsb;
159 return addr;
160}
161
AlexeiFedorov7641a812023-08-22 14:31:27 +0100162static unsigned long addr_level_mask(unsigned long addr, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000163{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100164 unsigned int levels, lsb, msb;
165
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100166 assert(level <= S2TT_PAGE_LEVEL);
167 assert(level >= S2TT_MIN_STARTING_LEVEL);
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100168
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100169 levels = (unsigned int)(S2TT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100170 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100171 msb = S2TTE_OA_BITS - 1U;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000172
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100173 return (addr & BIT_MASK_ULL(msb, lsb));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000174}
175
Soby Mathewb4c6df42022-11-09 11:13:29 +0000176static inline bool entry_is_table(unsigned long entry)
177{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100178 return ((entry & S2TT_DESC_TYPE_MASK) == S2TTE_L012_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000179}
180
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100181static unsigned long table_get_entry(struct granule *g_tbl,
182 unsigned long idx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000183{
184 unsigned long *table, entry;
185
186 table = granule_map(g_tbl, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100187 assert(table != NULL);
188
Soby Mathewb4c6df42022-11-09 11:13:29 +0000189 entry = s2tte_read(&table[idx]);
190 buffer_unmap(table);
191
192 return entry;
193}
194
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100195#define table_entry_to_phys(tte) addr_level_mask(tte, S2TT_PAGE_LEVEL)
196
197static struct granule *find_next_level_idx(struct granule *g_tbl,
198 unsigned long idx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000199{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100200 const unsigned long entry = table_get_entry(g_tbl, idx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000201
202 if (!entry_is_table(entry)) {
203 return NULL;
204 }
205
206 return addr_to_granule(table_entry_to_phys(entry));
207}
208
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100209static struct granule *find_lock_next_level(struct granule *g_tbl,
210 unsigned long map_addr,
211 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000212{
213 const unsigned long idx = s2_addr_to_idx(map_addr, level);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100214 struct granule *g = find_next_level_idx(g_tbl, idx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000215
216 if (g != NULL) {
217 granule_lock(g, GRANULE_STATE_RTT);
218 }
219
220 return g;
221}
222
223/*
224 * Walk an RTT until level @level using @map_addr.
225 * @g_root is the root (level 0) table and must be locked before the call.
226 * @start_level is the initial lookup level used for the stage 2 translation
227 * tables which may depend on the configuration of the realm, factoring in the
228 * IPA size of the realm and the desired starting level (within the limits
229 * defined by the Armv8 VMSA including options for stage 2 table concatenation).
230 * The function uses hand-over-hand locking to avoid race conditions and allow
231 * concurrent access to RTT tree which is not part of the current walk; when a
232 * next level table is reached it is locked before releasing previously locked
233 * table.
234 * The walk stops when either:
235 * - The entry found is a leaf entry (not an RTT Table entry), or
236 * - Level @level is reached.
237 *
238 * On return:
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100239 * - s2tt_walk::last_level is the last level that has been reached by the walk.
240 * - s2tt_walk.g_llt points to the TABLE granule at level @s2tt_walk::level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000241 * The granule is locked.
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100242 * - s2tt_walk::index is the entry index at s2tt_walk.g_llt for @map_addr.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000243 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100244void s2tt_walk_lock_unlock(struct granule *g_root,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000245 int start_level,
246 unsigned long ipa_bits,
247 unsigned long map_addr,
248 long level,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100249 struct s2tt_walk *wi)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000250{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100251 struct granule *g_tbls[NR_RTT_LEVELS] = { (struct granule *)NULL };
Soby Mathewb4c6df42022-11-09 11:13:29 +0000252 unsigned long sl_idx;
253 int i, last_level;
254
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100255 assert(start_level >= S2TT_MIN_STARTING_LEVEL);
256 assert(start_level <= S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000257 assert(level >= start_level);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100258 assert(level <= S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000259 assert(map_addr < (1UL << ipa_bits));
260 assert(wi != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100261 assert(g_root != NULL);
262 assert(ipa_bits <= s2tt_max_ipa_size());
Soby Mathewb4c6df42022-11-09 11:13:29 +0000263
264 /* Handle concatenated starting level (SL) tables */
265 sl_idx = s2_sl_addr_to_idx(map_addr, start_level, ipa_bits);
266 if (sl_idx >= S2TTES_PER_S2TT) {
AlexeiFedorov4faab852023-08-30 15:06:49 +0100267 unsigned int tt_num = (unsigned int)(sl_idx >> S2TTE_STRIDE);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100268 struct granule *g_concat_root;
269
270 assert(tt_num < S2TTE_MAX_CONCAT_TABLES);
271
272 g_concat_root = (struct granule *)((uintptr_t)g_root +
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100273 (tt_num * sizeof(struct granule)));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000274
275 granule_lock(g_concat_root, GRANULE_STATE_RTT);
276 granule_unlock(g_root);
277 g_root = g_concat_root;
278 }
279
280 g_tbls[start_level] = g_root;
281 for (i = start_level; i < level; i++) {
282 /*
283 * Lock next RTT level. Correct locking order is guaranteed
284 * because reference is obtained from a locked granule
285 * (previous level). Also, hand-over-hand locking/unlocking is
286 * used to avoid race conditions.
287 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100288 g_tbls[i + 1] = find_lock_next_level(g_tbls[i], map_addr, i);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000289 if (g_tbls[i + 1] == NULL) {
290 last_level = i;
291 goto out;
292 }
293 granule_unlock(g_tbls[i]);
294 }
295
AlexeiFedorov4faab852023-08-30 15:06:49 +0100296 last_level = (int)level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000297out:
298 wi->last_level = last_level;
299 wi->g_llt = g_tbls[last_level];
300 wi->index = s2_addr_to_idx(map_addr, last_level);
301}
302
303/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100304 * Creates an unassigned_empty s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000305 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100306unsigned long s2tte_create_unassigned_empty(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000307{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100308 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100309}
310
311/*
312 * Creates an unassigned_ram s2tte.
313 */
314unsigned long s2tte_create_unassigned_ram(void)
315{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100316 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000317}
318
319/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100320 * Creates an unassigned_destroyed s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000321 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100322unsigned long s2tte_create_unassigned_destroyed(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000323{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100324 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
325}
326
327/*
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100328 * Creates an unassigned_ns s2tte.
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100329 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100330unsigned long s2tte_create_unassigned_ns(void)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100331{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100332 return (S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED |
333 S2TTE_INVALID_UNPROTECTED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000334}
335
336/*
337 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100338 * RIPAS=@s2tte_ripas, at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000339 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100340static unsigned long s2tte_create_assigned(unsigned long pa, long level,
341 unsigned long s2tte_ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000342{
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100343 (void)level;
344
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100345 assert(level >= S2TT_MIN_BLOCK_LEVEL);
346 assert(level <= S2TT_PAGE_LEVEL);
347 assert(s2tte_ripas <= S2TTE_INVALID_RIPAS_DESTROYED);
348 assert(s2tte_is_addr_lvl_aligned(pa, level));
349
350 if (s2tte_ripas == S2TTE_INVALID_RIPAS_RAM) {
351 if (level == S2TT_PAGE_LEVEL) {
352 return (pa | S2TTE_PAGE);
353 }
354 return (pa | S2TTE_BLOCK);
355 }
356
357 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | s2tte_ripas);
358}
359
360/*
361 * Creates and invalid s2tte with output address @pa, HIPAS=ASSIGNED and
362 * RIPAS=DESTROYED at level @level.
363 */
364unsigned long s2tte_create_assigned_destroyed(unsigned long pa, long level)
365{
366 return s2tte_create_assigned(pa, level, S2TTE_INVALID_RIPAS_DESTROYED);
367}
368
369/*
370 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
371 * RIPAS=EMPTY at level @level.
372 */
373unsigned long s2tte_create_assigned_empty(unsigned long pa, long level)
374{
375 return s2tte_create_assigned(pa, level, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000376}
377
378/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100379 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000380 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100381unsigned long s2tte_create_assigned_ram(unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000382{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100383 return s2tte_create_assigned(pa, level, S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000384}
385
386/*
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100387 * Creates an assigned s2tte with output address @pa and the same
388 * RIPAS as passed on @s2tte.
389 */
390unsigned long s2tte_create_assigned_unchanged(unsigned long s2tte,
391 unsigned long pa,
392 long level)
393{
394 unsigned long current_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
395
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100396 return s2tte_create_assigned(pa, level, current_ripas);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000397}
398
399/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100400 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000401 *
402 * The following S2 TTE fields are provided through @s2tte argument:
403 * - The physical address
404 * - MemAttr
405 * - S2AP
406 * - Shareability
407 */
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100408unsigned long s2tte_create_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000409{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100410 unsigned long new_s2tte = s2tte & ~S2TT_DESC_TYPE_MASK;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100411
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100412 assert(level >= S2TT_MIN_BLOCK_LEVEL);
413 assert(level <= S2TT_PAGE_LEVEL);
414 assert((s2tte & S2TTE_NS_ATTR_RMM) == 0UL);
415
416 if (level == S2TT_PAGE_LEVEL) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100417 return (new_s2tte | S2TTE_PAGE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000418 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100419 return (new_s2tte | S2TTE_BLOCK_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000420}
421
422/*
423 * Validate the portion of NS S2TTE that is provided by the host.
424 */
425bool host_ns_s2tte_is_valid(unsigned long s2tte, long level)
426{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100427
Soby Mathewb4c6df42022-11-09 11:13:29 +0000428 unsigned long mask = addr_level_mask(~0UL, level) |
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100429 S2TTE_NS_ATTR_HOST_MASK;
430
431 assert(level >= S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000432
433 /*
434 * Test that all fields that are not controlled by the host are zero
435 * and that the output address is correctly aligned. Note that
436 * the host is permitted to map any physical address outside PAR.
437 */
438 if ((s2tte & ~mask) != 0UL) {
439 return false;
440 }
441
442 /*
443 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
444 */
445 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
446 return false;
447 }
448
449 /*
450 * Only one value masked by S2TTE_SH_MASK is invalid/reserved.
451 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100452 if ((s2tte & S2TTE_SH_MASK) != S2TTE_SH_IS) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000453 return false;
454 }
455
456 /*
457 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
458 */
459 return true;
460}
461
462/*
463 * Returns the portion of NS S2TTE that is set by the host.
464 */
465unsigned long host_ns_s2tte(unsigned long s2tte, long level)
466{
467 unsigned long mask = addr_level_mask(~0UL, level) |
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100468 S2TTE_NS_ATTR_HOST_MASK;
469 assert(level >= S2TT_MIN_BLOCK_LEVEL);
470
Soby Mathewb4c6df42022-11-09 11:13:29 +0000471 return (s2tte & mask);
472}
473
474/*
475 * Creates a table s2tte at level @level with output address @pa.
476 */
477unsigned long s2tte_create_table(unsigned long pa, long level)
478{
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100479 (void)level;
480
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100481 assert(level < S2TT_PAGE_LEVEL);
482 assert(level >= S2TT_MIN_STARTING_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000483 assert(GRANULE_ALIGNED(pa));
484
485 return (pa | S2TTE_TABLE);
486}
487
488/*
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100489 * Returns true if s2tte has defined ripas value, namely if it is one of:
490 * - unassigned_empty
491 * - unassigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100492 * - unassigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100493 * - assigned_empty
494 * - assigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100495 * - assigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100496 */
497bool s2tte_has_ripas(unsigned long s2tte, long level)
498{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100499 return (((s2tte & S2TTE_NS) == 0UL) && !s2tte_is_table(s2tte, level));
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100500}
501
502/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000503 * Returns true if @s2tte has HIPAS=@hipas.
504 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100505static inline bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000506{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100507 unsigned long desc_type = s2tte & S2TT_DESC_TYPE_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000508 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
509
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100510 return ((desc_type == S2TTE_INVALID) && (invalid_desc_hipas == hipas));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000511}
512
513/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100514 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000515 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100516static inline bool s2tte_has_unassigned_ripas(unsigned long s2tte,
517 unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000518{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100519 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
520 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
521}
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100522
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100523/*
524 * Returns true if @s2tte has HIPAS=ASSIGNED and RIPAS=@ripas.
525 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100526static inline bool s2tte_has_assigned_ripas(unsigned long s2tte,
527 unsigned long ripas)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100528{
529 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
530 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100531}
532
533/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100534 * Returns true if @s2tte has HIPAS=UNASSIGNED.
535 */
536bool s2tte_is_unassigned(unsigned long s2tte)
537{
538 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED);
539}
540
541/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100542 * Returns true if @s2tte is an unassigned_empty.
543 */
544bool s2tte_is_unassigned_empty(unsigned long s2tte)
545{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100546 return (((s2tte & S2TTE_NS) == 0UL) &&
547 s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100548}
549
550/*
551 * Returns true if @s2tte is an unassigned_ram.
552 */
553bool s2tte_is_unassigned_ram(unsigned long s2tte)
554{
555 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
556}
557
558/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100559 * Returns true if @s2tte is unassigned_ns.
560 */
561bool s2tte_is_unassigned_ns(unsigned long s2tte)
562{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100563 return (((s2tte & S2TTE_NS) != 0UL) &&
564 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000565}
566
567/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100568 * Returns true if @s2tte has RIPAS=DESTROYED.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000569 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100570bool s2tte_is_unassigned_destroyed(unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000571{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100572 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
573}
574
575/*
576 * Returns true if @s2tte is an assigned_destroyed.
577 */
578bool s2tte_is_assigned_destroyed(unsigned long s2tte, long level)
579{
580 (void)level;
581
582 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000583}
584
585/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100586 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000587 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100588bool s2tte_is_assigned_empty(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000589{
590 (void)level;
591
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100592 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000593}
594
595static bool s2tte_check(unsigned long s2tte, long level, unsigned long ns)
596{
597 unsigned long desc_type;
598
599 if ((s2tte & S2TTE_NS) != ns) {
600 return false;
601 }
602
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100603 desc_type = s2tte & S2TT_DESC_TYPE_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000604
605 /* Only pages at L3 and valid blocks at L2 allowed */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100606 if (((level == S2TT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
607 ((level == S2TT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK))) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000608 return true;
609 }
610
611 return false;
612}
613
614/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100615 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000616 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100617bool s2tte_is_assigned_ram(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000618{
619 return s2tte_check(s2tte, level, 0UL);
620}
621
622/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100623 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000624 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100625bool s2tte_is_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000626{
627 return s2tte_check(s2tte, level, S2TTE_NS);
628}
629
630/*
631 * Returns true if @s2tte is a table at level @level.
632 */
633bool s2tte_is_table(unsigned long s2tte, long level)
634{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100635 return ((level < S2TT_PAGE_LEVEL) &&
636 ((s2tte & S2TT_DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000637}
638
639/*
640 * Returns RIPAS of @s2tte.
641 *
642 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100643 * The s2tte, if valid, should correspond to RIPAS_RAM.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000644 */
645enum ripas s2tte_get_ripas(unsigned long s2tte)
646{
647 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
648
649 /*
650 * If valid s2tte descriptor is passed, then ensure S2AP[0]
651 * bit is 1 (S2AP is set to RW for lower EL), which corresponds
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100652 * to RIPAS_RAM (bits[6:5] = b01) on a valid descriptor.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000653 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100654 assert(((s2tte & S2TT_DESC_TYPE_MASK) == S2TTE_INVALID) ||
655 (desc_ripas == S2TTE_INVALID_RIPAS_RAM));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000656
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100657 assert(EXTRACT(S2TTE_INVALID_HIPAS, s2tte) <=
658 EXTRACT(S2TTE_INVALID_HIPAS, S2TTE_INVALID_HIPAS_ASSIGNED));
659
660 desc_ripas = desc_ripas >> S2TTE_INVALID_RIPAS_SHIFT;
661
662 assert(desc_ripas <= (unsigned int)RIPAS_DESTROYED);
663
664 return (enum ripas)desc_ripas;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000665}
666
667/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100668 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000669 *
670 * The granule is populated before it is made a table,
671 * hence, don't use s2tte_write for access.
672 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100673void s2tt_init_unassigned_empty(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000674{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100675 assert(s2tt != NULL);
676
677 unsigned long s2tte =
678 s2tte_create_unassigned_empty();
679
Soby Mathewb4c6df42022-11-09 11:13:29 +0000680 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100681 s2tt[i] = s2tte;
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100682 }
683
684 dsb(ish);
685}
686
687/*
688 * Populates @s2tt with unassigned_ram s2ttes.
689 *
690 * The granule is populated before it is made a table,
691 * hence, don't use s2tte_write for access.
692 */
693void s2tt_init_unassigned_ram(unsigned long *s2tt)
694{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100695 assert(s2tt != NULL);
696
697 unsigned long s2tte = s2tte_create_unassigned_ram();
698
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100699 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100700 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000701 }
702
703 dsb(ish);
704}
705
706/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100707 * Populates @s2tt with unassigned_ns s2ttes.
708 *
709 * The granule is populated before it is made a table,
710 * hence, don't use s2tte_write for access.
711 */
712void s2tt_init_unassigned_ns(unsigned long *s2tt)
713{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100714 assert(s2tt != NULL);
715
716 unsigned long s2tte = s2tte_create_unassigned_ns();
717
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100718 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100719 s2tt[i] = s2tte;
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100720 }
721
722 dsb(ish);
723}
724
725/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000726 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
727 *
728 * The granule is populated before it is made a table,
729 * hence, don't use s2tte_write for access.
730 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100731void s2tt_init_unassigned_destroyed(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000732{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100733 assert(s2tt != NULL);
734
735 unsigned long s2tte =
736 s2tte_create_unassigned_destroyed();
737
Soby Mathewb4c6df42022-11-09 11:13:29 +0000738 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100739 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000740 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100741 dsb(ish);
742}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000743
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100744/*
745 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
746 * contiguous memory block starting at @pa, and mapped at level @level.
747 *
748 * The granule is populated before it is made a table,
749 * hence, don't use s2tte_write for access.
750 */
751void s2tt_init_assigned_destroyed(unsigned long *s2tt, unsigned long pa, long level)
752{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100753 assert(level >= S2TT_MIN_BLOCK_LEVEL);
754 assert(level <= S2TT_PAGE_LEVEL);
755 assert(s2tt != NULL);
756 assert(s2tte_is_addr_lvl_aligned(pa, level));
757
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100758 const unsigned long map_size = s2tte_map_size(level);
759
760 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
761 s2tt[i] = s2tte_create_assigned_destroyed(pa, level);
762 pa += map_size;
763 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000764 dsb(ish);
765}
766
Soby Mathewb4c6df42022-11-09 11:13:29 +0000767/*
768 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
769 * contiguous memory block starting at @pa, and mapped at level @level.
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_assigned_empty(unsigned long *s2tt, unsigned long pa, long level)
775{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100776 assert(level >= S2TT_MIN_BLOCK_LEVEL);
777 assert(level <= S2TT_PAGE_LEVEL);
778 assert(s2tt != NULL);
779 assert(s2tte_is_addr_lvl_aligned(pa, level));
780
Soby Mathewb4c6df42022-11-09 11:13:29 +0000781 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000782
AlexeiFedorov3a739332023-04-13 13:54:04 +0100783 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000784 s2tt[i] = s2tte_create_assigned_empty(pa, level);
785 pa += map_size;
786 }
787 dsb(ish);
788}
789
790/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100791 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000792 * contiguous memory block starting at @pa, and mapped at level @level.
793 *
794 * The granule is populated before it is made a table,
795 * hence, don't use s2tte_write for access.
796 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100797void s2tt_init_assigned_ram(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000798{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100799 assert(level >= S2TT_MIN_BLOCK_LEVEL);
800 assert(level <= S2TT_PAGE_LEVEL);
801 assert(s2tt != NULL);
802 assert(s2tte_is_addr_lvl_aligned(pa, level));
803
Soby Mathewb4c6df42022-11-09 11:13:29 +0000804 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000805
AlexeiFedorov3a739332023-04-13 13:54:04 +0100806 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
807 s2tt[i] = s2tte_create_assigned_ram(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000808 pa += map_size;
809 }
810 dsb(ish);
811}
812
813/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100814 * Populates @s2tt with NS attributes @attrs that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000815 * 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 */
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100820void s2tt_init_assigned_ns(unsigned long *s2tt, unsigned long attrs,
821 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000822{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100823 assert(level >= S2TT_MIN_BLOCK_LEVEL);
824 assert(level <= S2TT_PAGE_LEVEL);
825 assert(s2tt != NULL);
826 assert(s2tte_is_addr_lvl_aligned(pa, level));
827
Soby Mathewb4c6df42022-11-09 11:13:29 +0000828 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000829
AlexeiFedorov3a739332023-04-13 13:54:04 +0100830 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100831 unsigned long s2tte = attrs & S2TTE_NS_ATTR_HOST_MASK;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100832
833 s2tt[i] = s2tte_create_assigned_ns(s2tte | pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000834 pa += map_size;
835 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100836
Soby Mathewb4c6df42022-11-09 11:13:29 +0000837 dsb(ish);
838}
839
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100840/*
841 * Returns true if s2tte has 'output address' field, namely, if it is one of:
842 * - assigned_empty
843 * - assigned_ram
844 * - assigned_ns
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100845 * - assigned_destroyed
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100846 * - table
847 */
AlexeiFedorov7641a812023-08-22 14:31:27 +0100848static bool s2tte_has_pa(unsigned long s2tte, long level)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100849{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100850 unsigned long desc_type = s2tte & S2TT_DESC_TYPE_MASK;
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100851
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100852 return ((desc_type != S2TTE_INVALID) || /* block, page or table */
853 s2tte_is_assigned_empty(s2tte, level) ||
854 s2tte_is_assigned_destroyed(s2tte, level));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100855}
856
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100857/*
858 * Returns true if s2tte is a live RTTE entry. i.e.,
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100859 * HIPAS is ASSIGNED.
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100860 *
861 * NOTE: For now, only the RTTE with PA are live.
862 * This could change with EXPORT/IMPORT support.
863 */
AlexeiFedorov7641a812023-08-22 14:31:27 +0100864static bool s2tte_is_live(unsigned long s2tte, long level)
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100865{
866 return s2tte_has_pa(s2tte, level);
867}
868
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100869/* Returns physical address of a S2TTE */
Soby Mathewb4c6df42022-11-09 11:13:29 +0000870unsigned long s2tte_pa(unsigned long s2tte, long level)
871{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100872 assert(level <= S2TT_PAGE_LEVEL);
873 assert(level >= S2TT_MIN_STARTING_LEVEL);
874
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100875 if (!s2tte_has_pa(s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000876 assert(false);
877 }
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100878
879 if (s2tte_is_table(s2tte, level)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100880 return addr_level_mask(s2tte, S2TT_PAGE_LEVEL);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100881 }
882
Soby Mathewb4c6df42022-11-09 11:13:29 +0000883 return addr_level_mask(s2tte, level);
884}
885
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100886bool s2tte_is_addr_lvl_aligned(unsigned long addr, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000887{
888 return (addr == addr_level_mask(addr, level));
889}
890
891typedef bool (*s2tte_type_checker)(unsigned long s2tte);
892
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100893static bool table_is_uniform_block(unsigned long *table,
894 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000895{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100896 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
897 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000898
899 if (!s2tte_is_x(s2tte)) {
900 return false;
901 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000902 }
903
904 return true;
905}
906
907/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100908 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000909 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100910bool s2tt_is_unassigned_empty_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000911{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100912 assert(table != NULL);
913
914 return table_is_uniform_block(table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100915}
916
917/*
918 * Returns true if all s2ttes in @table are unassigned_ram.
919 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100920bool s2tt_is_unassigned_ram_block(unsigned long *table)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100921{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100922 assert(table != NULL);
923
924 return table_is_uniform_block(table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000925}
926
927/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100928 * Returns true if all s2ttes in @table are unassigned_ns
929 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100930bool s2tt_is_unassigned_ns_block(unsigned long *table)
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100931{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100932 assert(table != NULL);
933
934 return table_is_uniform_block(table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100935}
936
937/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100938 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +0000939 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100940bool s2tt_is_unassigned_destroyed_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000941{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100942 assert(table != NULL);
943
944 return table_is_uniform_block(table, s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000945}
946
947typedef bool (*s2tte_type_level_checker)(unsigned long s2tte, long level);
948
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100949static bool table_maps_block(unsigned long *table,
950 long level,
951 s2tte_type_level_checker s2tte_is_x,
952 bool check_ns_attrs)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000953{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100954 assert(table != NULL);
955
Soby Mathewb4c6df42022-11-09 11:13:29 +0000956 unsigned long base_pa;
957 unsigned long map_size = s2tte_map_size(level);
958 unsigned long s2tte = s2tte_read(&table[0]);
959 unsigned int i;
960
961 if (!s2tte_is_x(s2tte, level)) {
962 return false;
963 }
964
965 base_pa = s2tte_pa(s2tte, level);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100966 if (!s2tte_is_addr_lvl_aligned(base_pa, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000967 return false;
968 }
969
970 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
971 unsigned long expected_pa = base_pa + (i * map_size);
972
973 s2tte = s2tte_read(&table[i]);
974
975 if (!s2tte_is_x(s2tte, level)) {
976 return false;
977 }
978
979 if (s2tte_pa(s2tte, level) != expected_pa) {
980 return false;
981 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100982
983 if (check_ns_attrs) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100984 unsigned long ns_attrs =
985 s2tte & S2TTE_NS_ATTR_HOST_MASK;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100986
987 /*
988 * We match all the attributes in the S2TTE
989 * except for the AF bit.
990 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100991 if ((s2tte & S2TTE_NS_ATTR_HOST_MASK) != ns_attrs) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100992 return false;
993 }
994 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000995 }
996
997 return true;
998}
999
1000/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001001 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +00001002 * and refer to a contiguous block of granules aligned to @level - 1.
1003 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001004bool s2tt_maps_assigned_empty_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001005{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001006 return table_maps_block(table, level, s2tte_is_assigned_empty,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001007 false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001008}
1009
1010/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001011 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001012 * refer to a contiguous block of granules aligned to @level - 1.
1013 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001014bool s2tt_maps_assigned_ram_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001015{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001016 return table_maps_block(table, level, s2tte_is_assigned_ram, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001017}
1018
1019/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001020 * Returns true if
1021 * - all s2ttes in @table are assigned_ns s2ttes and
1022 * - they refer to a contiguous block of granules aligned to @level - 1 and
1023 * - all the s2tte attributes in @table controlled by the host are identical
AlexeiFedorov3a739332023-04-13 13:54:04 +01001024 *
1025 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001026 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001027bool s2tt_maps_assigned_ns_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001028{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001029 return table_maps_block(table, level, s2tte_is_assigned_ns, true);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001030}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001031
1032/*
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001033 * Returns true if all s2ttes are assigned_destroyed and
1034 * refer to a contiguous block of granules aligned to @level - 1.
1035 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001036bool s2tt_maps_assigned_destroyed_block(unsigned long *table, long level)
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001037{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001038 return table_maps_block(table, level, s2tte_is_assigned_destroyed,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001039 false);
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001040}
1041
1042/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001043 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001044 * skip the non-live entries (i.e., HIPAS=UNASSIGNED).
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001045 * In other words, the scanning stops when a live RTTE is encountered or we
1046 * reach the end of this RTT.
1047 *
1048 * For now an RTTE can be considered non-live if it doesn't have a PA.
1049 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1050 * in the RTTE.
1051 *
1052 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1053 * with RMI_ERROR_RTT).
1054 *
1055 * Returns:
1056 * - If the entry @wi.index is live, returns @addr.
1057 * - If none of the entries in the @s2tt are "live", returns the address of the
1058 * first entry in the next table.
1059 * - Otherwise, the address of the first live entry in @s2tt
1060 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001061unsigned long s2tt_skip_non_live_entries(unsigned long addr,
1062 unsigned long *table,
1063 const struct s2tt_walk *wi)
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001064{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001065 assert(table != NULL);
1066 assert(wi != NULL);
1067 assert(wi->index <= S2TTES_PER_S2TT);
1068 assert(wi->last_level >= S2TT_MIN_STARTING_LEVEL);
1069 assert(wi->last_level <= S2TT_PAGE_LEVEL);
1070
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001071 unsigned long i, index = wi->index;
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001072 long level = wi->last_level;
1073 unsigned long map_size;
1074
1075 /*
1076 * If the entry for the map_addr is live,
1077 * return @addr.
1078 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001079 if (s2tte_is_live(s2tte_read(&table[index]), level)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001080 return addr;
1081 }
1082
1083 /*
1084 * Align the address DOWN to the map_size, as expected for the @level,
1085 * so that we can compute the correct address by using the index.
1086 */
1087 map_size = s2tte_map_size(level);
1088 addr &= ~(map_size - 1UL);
1089
1090 /* Skip the "index" */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001091 for (i = index + 1UL; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001092 unsigned long s2tte = s2tte_read(&table[i]);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001093
1094 if (s2tte_is_live(s2tte, level)) {
1095 break;
1096 }
1097 }
1098
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001099 return (addr + ((i - index) * map_size));
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001100}