blob: fe604f4f9f4cea45a4ce27bf1afa1c079cd9ecc4 [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>
Soby Mathewb4c6df42022-11-09 11:13:29 +00008#include <granule.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +00009#include <ripas.h>
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010010#include <s2tt.h>
11#include <s2tt_pvt_defs.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000012#include <smc.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000013#include <stddef.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000014
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010015/* TODO: Fix this when introducing LPA2 support */
16COMPILER_ASSERT(S2TT_MIN_STARTING_LEVEL >= 0);
Soby Mathewb4c6df42022-11-09 11:13:29 +000017
18/*
19 * Invalidates S2 TLB entries from [ipa, ipa + size] region tagged with `vmid`.
20 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +000021static void stage2_tlbi_ipa(const struct s2tt_context *s2_ctx,
Soby Mathewb4c6df42022-11-09 11:13:29 +000022 unsigned long ipa,
23 unsigned long size)
24{
25 /*
26 * Notes:
27 *
28 * - This follows the description provided in the Arm ARM on
29 * "Invalidation of TLB entries from stage 2 translations".
30 *
31 * - @TODO: Provide additional information to this primitive so that
32 * we can utilize:
33 * - The TTL level hint, see FEAT_TTL,
34 * - Final level lookup only invalidation,
35 * - Address range invalidation.
36 */
37
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010038 assert(s2_ctx != NULL);
39
Soby Mathewb4c6df42022-11-09 11:13:29 +000040 /*
41 * Save the current content of vttb_el2.
42 */
43 unsigned long old_vttbr_el2 = read_vttbr_el2();
44
45 /*
46 * Make 'vmid' the `current vmid`. Note that the tlbi instructions
47 * bellow target the TLB entries that match the `current vmid`.
48 */
49 write_vttbr_el2(INPLACE(VTTBR_EL2_VMID, s2_ctx->vmid));
50 isb();
51
52 /*
53 * Invalidate entries in S2 TLB caches that
54 * match both `ipa` & the `current vmid`.
55 */
56 while (size != 0UL) {
57 tlbiipas2e1is(ipa >> 12);
58 size -= GRANULE_SIZE;
59 ipa += GRANULE_SIZE;
60 }
61 dsb(ish);
62
63 /*
64 * The architecture does not require TLB invalidation by IPA to affect
65 * combined Stage-1 + Stage-2 TLBs. Therefore we must invalidate all of
66 * Stage-1 (tagged with the `current vmid`) after invalidating Stage-2.
67 */
68 tlbivmalle1is();
69 dsb(ish);
70 isb();
71
72 /*
73 * Restore the old content of vttb_el2.
74 */
75 write_vttbr_el2(old_vttbr_el2);
76 isb();
77}
78
79/*
80 * Invalidate S2 TLB entries with "addr" IPA.
81 * Call this function after:
82 * 1. A L3 page desc has been removed.
83 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +000084void s2tt_invalidate_page(const struct s2tt_context *s2_ctx, unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +000085{
86 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
87}
88
89/*
90 * Invalidate S2 TLB entries with "addr" IPA.
91 * Call this function after:
92 * 1. A L2 block desc has been removed, or
93 * 2a. A L2 table desc has been removed, where
94 * 2b. All S2TTEs in L3 table that the L2 table desc was pointed to were invalid.
95 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +000096void s2tt_invalidate_block(const struct s2tt_context *s2_ctx, unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +000097{
98 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
99}
100
101/*
102 * Invalidate S2 TLB entries with "addr" IPA.
103 * Call this function after:
104 * 1a. A L2 table desc has been removed, where
105 * 1b. Some S2TTEs in the table that the L2 table desc was pointed to were valid.
106 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000107void s2tt_invalidate_pages_in_block(const struct s2tt_context *s2_ctx,
108 unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000109{
110 stage2_tlbi_ipa(s2_ctx, addr, BLOCK_L2_SIZE);
111}
112
113/*
114 * Return the index of the entry describing @addr in the translation table at
115 * level @level. This only works for non-concatenated page tables, so should
116 * not be called to get the index for the starting level.
117 *
118 * See the library pseudocode
119 * aarch64/translation/vmsa_addrcalc/AArch64.TTEntryAddress on which this is
120 * modeled.
121 */
122static unsigned long s2_addr_to_idx(unsigned long addr, long level)
123{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100124 unsigned int levels, lsb;
125
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100126 levels = (unsigned int)(S2TT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100127 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000128
129 addr >>= lsb;
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100130 addr &= (1UL << S2TTE_STRIDE) - 1UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000131 return addr;
132}
133
134/*
135 * Return the index of the entry describing @addr in the translation table
136 * starting level. This may return an index >= S2TTES_PER_S2TT when the
137 * combination of @start_level and @ipa_bits implies concatenated
138 * stage 2 tables.
139 *
140 * See the library pseudocode
141 * aarch64/translation/vmsa_addrcalc/AArch64.S2SLTTEntryAddress on which
142 * this is modeled.
143 */
144static unsigned long s2_sl_addr_to_idx(unsigned long addr, int start_level,
145 unsigned long ipa_bits)
146{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100147 unsigned int levels, lsb;
148
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100149 levels = (unsigned int)(S2TT_PAGE_LEVEL - start_level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100150 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000151
152 addr &= (1UL << ipa_bits) - 1UL;
153 addr >>= lsb;
154 return addr;
155}
156
AlexeiFedorov7641a812023-08-22 14:31:27 +0100157static unsigned long addr_level_mask(unsigned long addr, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000158{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100159 unsigned int levels, lsb, msb;
160
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100161 assert(level <= S2TT_PAGE_LEVEL);
162 assert(level >= S2TT_MIN_STARTING_LEVEL);
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100163
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100164 levels = (unsigned int)(S2TT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100165 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100166 msb = S2TTE_OA_BITS - 1U;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000167
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100168 return (addr & BIT_MASK_ULL(msb, lsb));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000169}
170
Soby Mathewb4c6df42022-11-09 11:13:29 +0000171static inline bool entry_is_table(unsigned long entry)
172{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100173 return ((entry & S2TT_DESC_TYPE_MASK) == S2TTE_L012_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000174}
175
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100176static unsigned long table_get_entry(struct granule *g_tbl,
177 unsigned long idx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000178{
179 unsigned long *table, entry;
180
181 table = granule_map(g_tbl, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100182 assert(table != NULL);
183
Soby Mathewb4c6df42022-11-09 11:13:29 +0000184 entry = s2tte_read(&table[idx]);
185 buffer_unmap(table);
186
187 return entry;
188}
189
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100190#define table_entry_to_phys(tte) addr_level_mask(tte, S2TT_PAGE_LEVEL)
191
192static struct granule *find_next_level_idx(struct granule *g_tbl,
193 unsigned long idx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000194{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100195 const unsigned long entry = table_get_entry(g_tbl, idx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000196
197 if (!entry_is_table(entry)) {
198 return NULL;
199 }
200
201 return addr_to_granule(table_entry_to_phys(entry));
202}
203
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100204static struct granule *find_lock_next_level(struct granule *g_tbl,
205 unsigned long map_addr,
206 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000207{
208 const unsigned long idx = s2_addr_to_idx(map_addr, level);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100209 struct granule *g = find_next_level_idx(g_tbl, idx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000210
211 if (g != NULL) {
212 granule_lock(g, GRANULE_STATE_RTT);
213 }
214
215 return g;
216}
217
218/*
219 * Walk an RTT until level @level using @map_addr.
220 * @g_root is the root (level 0) table and must be locked before the call.
221 * @start_level is the initial lookup level used for the stage 2 translation
222 * tables which may depend on the configuration of the realm, factoring in the
223 * IPA size of the realm and the desired starting level (within the limits
224 * defined by the Armv8 VMSA including options for stage 2 table concatenation).
225 * The function uses hand-over-hand locking to avoid race conditions and allow
226 * concurrent access to RTT tree which is not part of the current walk; when a
227 * next level table is reached it is locked before releasing previously locked
228 * table.
229 * The walk stops when either:
230 * - The entry found is a leaf entry (not an RTT Table entry), or
231 * - Level @level is reached.
232 *
233 * On return:
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100234 * - s2tt_walk::last_level is the last level that has been reached by the walk.
235 * - s2tt_walk.g_llt points to the TABLE granule at level @s2tt_walk::level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000236 * The granule is locked.
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100237 * - s2tt_walk::index is the entry index at s2tt_walk.g_llt for @map_addr.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000238 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100239void s2tt_walk_lock_unlock(struct granule *g_root,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000240 int start_level,
241 unsigned long ipa_bits,
242 unsigned long map_addr,
243 long level,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100244 struct s2tt_walk *wi)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000245{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100246 struct granule *g_tbls[NR_RTT_LEVELS] = { (struct granule *)NULL };
Soby Mathewb4c6df42022-11-09 11:13:29 +0000247 unsigned long sl_idx;
248 int i, last_level;
249
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100250 assert(start_level >= S2TT_MIN_STARTING_LEVEL);
251 assert(start_level <= S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000252 assert(level >= start_level);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100253 assert(level <= S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000254 assert(map_addr < (1UL << ipa_bits));
255 assert(wi != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100256 assert(g_root != NULL);
257 assert(ipa_bits <= s2tt_max_ipa_size());
Soby Mathewb4c6df42022-11-09 11:13:29 +0000258
259 /* Handle concatenated starting level (SL) tables */
260 sl_idx = s2_sl_addr_to_idx(map_addr, start_level, ipa_bits);
261 if (sl_idx >= S2TTES_PER_S2TT) {
AlexeiFedorov4faab852023-08-30 15:06:49 +0100262 unsigned int tt_num = (unsigned int)(sl_idx >> S2TTE_STRIDE);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100263 struct granule *g_concat_root;
264
265 assert(tt_num < S2TTE_MAX_CONCAT_TABLES);
266
267 g_concat_root = (struct granule *)((uintptr_t)g_root +
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100268 (tt_num * sizeof(struct granule)));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000269
270 granule_lock(g_concat_root, GRANULE_STATE_RTT);
271 granule_unlock(g_root);
272 g_root = g_concat_root;
273 }
274
275 g_tbls[start_level] = g_root;
276 for (i = start_level; i < level; i++) {
277 /*
278 * Lock next RTT level. Correct locking order is guaranteed
279 * because reference is obtained from a locked granule
280 * (previous level). Also, hand-over-hand locking/unlocking is
281 * used to avoid race conditions.
282 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100283 g_tbls[i + 1] = find_lock_next_level(g_tbls[i], map_addr, i);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000284 if (g_tbls[i + 1] == NULL) {
285 last_level = i;
286 goto out;
287 }
288 granule_unlock(g_tbls[i]);
289 }
290
AlexeiFedorov4faab852023-08-30 15:06:49 +0100291 last_level = (int)level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000292out:
293 wi->last_level = last_level;
294 wi->g_llt = g_tbls[last_level];
295 wi->index = s2_addr_to_idx(map_addr, last_level);
296}
297
298/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100299 * Creates an unassigned_empty s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000300 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100301unsigned long s2tte_create_unassigned_empty(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000302{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100303 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100304}
305
306/*
307 * Creates an unassigned_ram s2tte.
308 */
309unsigned long s2tte_create_unassigned_ram(void)
310{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100311 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000312}
313
314/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100315 * Creates an unassigned_destroyed s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000316 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100317unsigned long s2tte_create_unassigned_destroyed(void)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000318{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100319 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
320}
321
322/*
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100323 * Creates an unassigned_ns s2tte.
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100324 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100325unsigned long s2tte_create_unassigned_ns(void)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100326{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100327 return (S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED |
328 S2TTE_INVALID_UNPROTECTED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000329}
330
331/*
332 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100333 * RIPAS=@s2tte_ripas, at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000334 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100335static unsigned long s2tte_create_assigned(unsigned long pa, long level,
336 unsigned long s2tte_ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000337{
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100338 (void)level;
339
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100340 assert(level >= S2TT_MIN_BLOCK_LEVEL);
341 assert(level <= S2TT_PAGE_LEVEL);
342 assert(s2tte_ripas <= S2TTE_INVALID_RIPAS_DESTROYED);
343 assert(s2tte_is_addr_lvl_aligned(pa, level));
344
345 if (s2tte_ripas == S2TTE_INVALID_RIPAS_RAM) {
346 if (level == S2TT_PAGE_LEVEL) {
347 return (pa | S2TTE_PAGE);
348 }
349 return (pa | S2TTE_BLOCK);
350 }
351
352 return (pa | S2TTE_INVALID_HIPAS_ASSIGNED | s2tte_ripas);
353}
354
355/*
356 * Creates and invalid s2tte with output address @pa, HIPAS=ASSIGNED and
357 * RIPAS=DESTROYED at level @level.
358 */
359unsigned long s2tte_create_assigned_destroyed(unsigned long pa, long level)
360{
361 return s2tte_create_assigned(pa, level, S2TTE_INVALID_RIPAS_DESTROYED);
362}
363
364/*
365 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
366 * RIPAS=EMPTY at level @level.
367 */
368unsigned long s2tte_create_assigned_empty(unsigned long pa, long level)
369{
370 return s2tte_create_assigned(pa, level, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000371}
372
373/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100374 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000375 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100376unsigned long s2tte_create_assigned_ram(unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000377{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100378 return s2tte_create_assigned(pa, level, S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000379}
380
381/*
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100382 * Creates an assigned s2tte with output address @pa and the same
383 * RIPAS as passed on @s2tte.
384 */
385unsigned long s2tte_create_assigned_unchanged(unsigned long s2tte,
386 unsigned long pa,
387 long level)
388{
389 unsigned long current_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
390
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100391 return s2tte_create_assigned(pa, level, current_ripas);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000392}
393
394/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100395 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000396 *
397 * The following S2 TTE fields are provided through @s2tte argument:
398 * - The physical address
399 * - MemAttr
400 * - S2AP
401 * - Shareability
402 */
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100403unsigned long s2tte_create_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000404{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100405 unsigned long new_s2tte = s2tte & ~S2TT_DESC_TYPE_MASK;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100406
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100407 assert(level >= S2TT_MIN_BLOCK_LEVEL);
408 assert(level <= S2TT_PAGE_LEVEL);
409 assert((s2tte & S2TTE_NS_ATTR_RMM) == 0UL);
410
411 if (level == S2TT_PAGE_LEVEL) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100412 return (new_s2tte | S2TTE_PAGE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000413 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100414 return (new_s2tte | S2TTE_BLOCK_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000415}
416
417/*
418 * Validate the portion of NS S2TTE that is provided by the host.
419 */
420bool host_ns_s2tte_is_valid(unsigned long s2tte, long level)
421{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100422
Soby Mathewb4c6df42022-11-09 11:13:29 +0000423 unsigned long mask = addr_level_mask(~0UL, level) |
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100424 S2TTE_NS_ATTR_HOST_MASK;
425
426 assert(level >= S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000427
428 /*
429 * Test that all fields that are not controlled by the host are zero
430 * and that the output address is correctly aligned. Note that
431 * the host is permitted to map any physical address outside PAR.
432 */
433 if ((s2tte & ~mask) != 0UL) {
434 return false;
435 }
436
437 /*
438 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
439 */
440 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
441 return false;
442 }
443
444 /*
445 * Only one value masked by S2TTE_SH_MASK is invalid/reserved.
446 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100447 if ((s2tte & S2TTE_SH_MASK) != S2TTE_SH_IS) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000448 return false;
449 }
450
451 /*
452 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
453 */
454 return true;
455}
456
457/*
458 * Returns the portion of NS S2TTE that is set by the host.
459 */
460unsigned long host_ns_s2tte(unsigned long s2tte, long level)
461{
462 unsigned long mask = addr_level_mask(~0UL, level) |
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100463 S2TTE_NS_ATTR_HOST_MASK;
464 assert(level >= S2TT_MIN_BLOCK_LEVEL);
465
Soby Mathewb4c6df42022-11-09 11:13:29 +0000466 return (s2tte & mask);
467}
468
469/*
470 * Creates a table s2tte at level @level with output address @pa.
471 */
472unsigned long s2tte_create_table(unsigned long pa, long level)
473{
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100474 (void)level;
475
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100476 assert(level < S2TT_PAGE_LEVEL);
477 assert(level >= S2TT_MIN_STARTING_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000478 assert(GRANULE_ALIGNED(pa));
479
480 return (pa | S2TTE_TABLE);
481}
482
483/*
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100484 * Returns true if s2tte has defined ripas value, namely if it is one of:
485 * - unassigned_empty
486 * - unassigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100487 * - unassigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100488 * - assigned_empty
489 * - assigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100490 * - assigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100491 */
492bool s2tte_has_ripas(unsigned long s2tte, long level)
493{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100494 return (((s2tte & S2TTE_NS) == 0UL) && !s2tte_is_table(s2tte, level));
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100495}
496
497/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000498 * Returns true if @s2tte has HIPAS=@hipas.
499 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100500static inline bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000501{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100502 unsigned long desc_type = s2tte & S2TT_DESC_TYPE_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000503 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
504
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100505 return ((desc_type == S2TTE_INVALID) && (invalid_desc_hipas == hipas));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000506}
507
508/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100509 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000510 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100511static inline bool s2tte_has_unassigned_ripas(unsigned long s2tte,
512 unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000513{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100514 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
515 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
516}
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100517
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100518/*
519 * Returns true if @s2tte has HIPAS=ASSIGNED and RIPAS=@ripas.
520 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100521static inline bool s2tte_has_assigned_ripas(unsigned long s2tte,
522 unsigned long ripas)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100523{
524 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
525 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100526}
527
528/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100529 * Returns true if @s2tte has HIPAS=UNASSIGNED.
530 */
531bool s2tte_is_unassigned(unsigned long s2tte)
532{
533 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED);
534}
535
536/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100537 * Returns true if @s2tte is an unassigned_empty.
538 */
539bool s2tte_is_unassigned_empty(unsigned long s2tte)
540{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100541 return (((s2tte & S2TTE_NS) == 0UL) &&
542 s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100543}
544
545/*
546 * Returns true if @s2tte is an unassigned_ram.
547 */
548bool s2tte_is_unassigned_ram(unsigned long s2tte)
549{
550 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
551}
552
553/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100554 * Returns true if @s2tte is unassigned_ns.
555 */
556bool s2tte_is_unassigned_ns(unsigned long s2tte)
557{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100558 return (((s2tte & S2TTE_NS) != 0UL) &&
559 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000560}
561
562/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100563 * Returns true if @s2tte has RIPAS=DESTROYED.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000564 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100565bool s2tte_is_unassigned_destroyed(unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000566{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100567 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
568}
569
570/*
571 * Returns true if @s2tte is an assigned_destroyed.
572 */
573bool s2tte_is_assigned_destroyed(unsigned long s2tte, long level)
574{
575 (void)level;
576
577 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000578}
579
580/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100581 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000582 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100583bool s2tte_is_assigned_empty(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000584{
585 (void)level;
586
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100587 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000588}
589
590static bool s2tte_check(unsigned long s2tte, long level, unsigned long ns)
591{
592 unsigned long desc_type;
593
594 if ((s2tte & S2TTE_NS) != ns) {
595 return false;
596 }
597
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100598 desc_type = s2tte & S2TT_DESC_TYPE_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000599
600 /* Only pages at L3 and valid blocks at L2 allowed */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100601 if (((level == S2TT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
602 ((level == S2TT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK))) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000603 return true;
604 }
605
606 return false;
607}
608
609/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100610 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000611 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100612bool s2tte_is_assigned_ram(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000613{
614 return s2tte_check(s2tte, level, 0UL);
615}
616
617/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100618 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000619 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100620bool s2tte_is_assigned_ns(unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000621{
622 return s2tte_check(s2tte, level, S2TTE_NS);
623}
624
625/*
626 * Returns true if @s2tte is a table at level @level.
627 */
628bool s2tte_is_table(unsigned long s2tte, long level)
629{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100630 return ((level < S2TT_PAGE_LEVEL) &&
631 ((s2tte & S2TT_DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000632}
633
634/*
635 * Returns RIPAS of @s2tte.
636 *
637 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100638 * The s2tte, if valid, should correspond to RIPAS_RAM.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000639 */
640enum ripas s2tte_get_ripas(unsigned long s2tte)
641{
642 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
643
644 /*
645 * If valid s2tte descriptor is passed, then ensure S2AP[0]
646 * bit is 1 (S2AP is set to RW for lower EL), which corresponds
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100647 * to RIPAS_RAM (bits[6:5] = b01) on a valid descriptor.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000648 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100649 assert(((s2tte & S2TT_DESC_TYPE_MASK) == S2TTE_INVALID) ||
650 (desc_ripas == S2TTE_INVALID_RIPAS_RAM));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000651
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100652 assert(EXTRACT(S2TTE_INVALID_HIPAS, s2tte) <=
653 EXTRACT(S2TTE_INVALID_HIPAS, S2TTE_INVALID_HIPAS_ASSIGNED));
654
655 desc_ripas = desc_ripas >> S2TTE_INVALID_RIPAS_SHIFT;
656
657 assert(desc_ripas <= (unsigned int)RIPAS_DESTROYED);
658
659 return (enum ripas)desc_ripas;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000660}
661
662/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100663 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000664 *
665 * The granule is populated before it is made a table,
666 * hence, don't use s2tte_write for access.
667 */
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100668void s2tt_init_unassigned_empty(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000669{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100670 assert(s2tt != NULL);
671
672 unsigned long s2tte =
673 s2tte_create_unassigned_empty();
674
Soby Mathewb4c6df42022-11-09 11:13:29 +0000675 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100676 s2tt[i] = s2tte;
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100677 }
678
679 dsb(ish);
680}
681
682/*
683 * Populates @s2tt with unassigned_ram s2ttes.
684 *
685 * The granule is populated before it is made a table,
686 * hence, don't use s2tte_write for access.
687 */
688void s2tt_init_unassigned_ram(unsigned long *s2tt)
689{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100690 assert(s2tt != NULL);
691
692 unsigned long s2tte = s2tte_create_unassigned_ram();
693
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100694 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100695 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000696 }
697
698 dsb(ish);
699}
700
701/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100702 * Populates @s2tt with unassigned_ns s2ttes.
703 *
704 * The granule is populated before it is made a table,
705 * hence, don't use s2tte_write for access.
706 */
707void s2tt_init_unassigned_ns(unsigned long *s2tt)
708{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100709 assert(s2tt != NULL);
710
711 unsigned long s2tte = s2tte_create_unassigned_ns();
712
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100713 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100714 s2tt[i] = s2tte;
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100715 }
716
717 dsb(ish);
718}
719
720/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000721 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
722 *
723 * The granule is populated before it is made a table,
724 * hence, don't use s2tte_write for access.
725 */
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100726void s2tt_init_unassigned_destroyed(unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000727{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100728 assert(s2tt != NULL);
729
730 unsigned long s2tte =
731 s2tte_create_unassigned_destroyed();
732
Soby Mathewb4c6df42022-11-09 11:13:29 +0000733 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100734 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000735 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100736 dsb(ish);
737}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000738
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100739/*
740 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
741 * contiguous memory block starting at @pa, and mapped at level @level.
742 *
743 * The granule is populated before it is made a table,
744 * hence, don't use s2tte_write for access.
745 */
746void s2tt_init_assigned_destroyed(unsigned long *s2tt, unsigned long pa, long level)
747{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100748 assert(level >= S2TT_MIN_BLOCK_LEVEL);
749 assert(level <= S2TT_PAGE_LEVEL);
750 assert(s2tt != NULL);
751 assert(s2tte_is_addr_lvl_aligned(pa, level));
752
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100753 const unsigned long map_size = s2tte_map_size(level);
754
755 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
756 s2tt[i] = s2tte_create_assigned_destroyed(pa, level);
757 pa += map_size;
758 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000759 dsb(ish);
760}
761
Soby Mathewb4c6df42022-11-09 11:13:29 +0000762/*
763 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
764 * contiguous memory block starting at @pa, and mapped at level @level.
765 *
766 * The granule is populated before it is made a table,
767 * hence, don't use s2tte_write for access.
768 */
769void s2tt_init_assigned_empty(unsigned long *s2tt, unsigned long pa, long level)
770{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100771 assert(level >= S2TT_MIN_BLOCK_LEVEL);
772 assert(level <= S2TT_PAGE_LEVEL);
773 assert(s2tt != NULL);
774 assert(s2tte_is_addr_lvl_aligned(pa, level));
775
Soby Mathewb4c6df42022-11-09 11:13:29 +0000776 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000777
AlexeiFedorov3a739332023-04-13 13:54:04 +0100778 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000779 s2tt[i] = s2tte_create_assigned_empty(pa, level);
780 pa += map_size;
781 }
782 dsb(ish);
783}
784
785/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100786 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000787 * contiguous memory block starting at @pa, and mapped at level @level.
788 *
789 * The granule is populated before it is made a table,
790 * hence, don't use s2tte_write for access.
791 */
AlexeiFedorov3a739332023-04-13 13:54:04 +0100792void s2tt_init_assigned_ram(unsigned long *s2tt, unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000793{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100794 assert(level >= S2TT_MIN_BLOCK_LEVEL);
795 assert(level <= S2TT_PAGE_LEVEL);
796 assert(s2tt != NULL);
797 assert(s2tte_is_addr_lvl_aligned(pa, level));
798
Soby Mathewb4c6df42022-11-09 11:13:29 +0000799 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000800
AlexeiFedorov3a739332023-04-13 13:54:04 +0100801 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
802 s2tt[i] = s2tte_create_assigned_ram(pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000803 pa += map_size;
804 }
805 dsb(ish);
806}
807
808/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100809 * Populates @s2tt with NS attributes @attrs that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000810 * contiguous memory block starting at @pa, and mapped at level @level.
811 *
812 * The granule is populated before it is made a table,
813 * hence, don't use s2tte_write for access.
814 */
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100815void s2tt_init_assigned_ns(unsigned long *s2tt, unsigned long attrs,
816 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000817{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100818 assert(level >= S2TT_MIN_BLOCK_LEVEL);
819 assert(level <= S2TT_PAGE_LEVEL);
820 assert(s2tt != NULL);
821 assert(s2tte_is_addr_lvl_aligned(pa, level));
822
Soby Mathewb4c6df42022-11-09 11:13:29 +0000823 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000824
AlexeiFedorov3a739332023-04-13 13:54:04 +0100825 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100826 unsigned long s2tte = attrs & S2TTE_NS_ATTR_HOST_MASK;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100827
828 s2tt[i] = s2tte_create_assigned_ns(s2tte | pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000829 pa += map_size;
830 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100831
Soby Mathewb4c6df42022-11-09 11:13:29 +0000832 dsb(ish);
833}
834
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100835/*
836 * Returns true if s2tte has 'output address' field, namely, if it is one of:
837 * - assigned_empty
838 * - assigned_ram
839 * - assigned_ns
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100840 * - assigned_destroyed
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100841 * - table
842 */
AlexeiFedorov7641a812023-08-22 14:31:27 +0100843static bool s2tte_has_pa(unsigned long s2tte, long level)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100844{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100845 unsigned long desc_type = s2tte & S2TT_DESC_TYPE_MASK;
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100846
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100847 return ((desc_type != S2TTE_INVALID) || /* block, page or table */
848 s2tte_is_assigned_empty(s2tte, level) ||
849 s2tte_is_assigned_destroyed(s2tte, level));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100850}
851
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100852/*
853 * Returns true if s2tte is a live RTTE entry. i.e.,
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100854 * HIPAS is ASSIGNED.
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100855 *
856 * NOTE: For now, only the RTTE with PA are live.
857 * This could change with EXPORT/IMPORT support.
858 */
AlexeiFedorov7641a812023-08-22 14:31:27 +0100859static bool s2tte_is_live(unsigned long s2tte, long level)
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100860{
861 return s2tte_has_pa(s2tte, level);
862}
863
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100864/* Returns physical address of a S2TTE */
Soby Mathewb4c6df42022-11-09 11:13:29 +0000865unsigned long s2tte_pa(unsigned long s2tte, long level)
866{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100867 assert(level <= S2TT_PAGE_LEVEL);
868 assert(level >= S2TT_MIN_STARTING_LEVEL);
869
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100870 if (!s2tte_has_pa(s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000871 assert(false);
872 }
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100873
874 if (s2tte_is_table(s2tte, level)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100875 return addr_level_mask(s2tte, S2TT_PAGE_LEVEL);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100876 }
877
Soby Mathewb4c6df42022-11-09 11:13:29 +0000878 return addr_level_mask(s2tte, level);
879}
880
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100881bool s2tte_is_addr_lvl_aligned(unsigned long addr, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000882{
883 return (addr == addr_level_mask(addr, level));
884}
885
886typedef bool (*s2tte_type_checker)(unsigned long s2tte);
887
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100888static bool table_is_uniform_block(unsigned long *table,
889 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000890{
AlexeiFedorov377d81f2023-04-14 16:29:12 +0100891 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
892 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000893
894 if (!s2tte_is_x(s2tte)) {
895 return false;
896 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000897 }
898
899 return true;
900}
901
902/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100903 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000904 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100905bool s2tt_is_unassigned_empty_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000906{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100907 assert(table != NULL);
908
909 return table_is_uniform_block(table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100910}
911
912/*
913 * Returns true if all s2ttes in @table are unassigned_ram.
914 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100915bool s2tt_is_unassigned_ram_block(unsigned long *table)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100916{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100917 assert(table != NULL);
918
919 return table_is_uniform_block(table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000920}
921
922/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100923 * Returns true if all s2ttes in @table are unassigned_ns
924 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100925bool s2tt_is_unassigned_ns_block(unsigned long *table)
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100926{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100927 assert(table != NULL);
928
929 return table_is_uniform_block(table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100930}
931
932/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100933 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +0000934 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100935bool s2tt_is_unassigned_destroyed_block(unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000936{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100937 assert(table != NULL);
938
939 return table_is_uniform_block(table, s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000940}
941
942typedef bool (*s2tte_type_level_checker)(unsigned long s2tte, long level);
943
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100944static bool table_maps_block(unsigned long *table,
945 long level,
946 s2tte_type_level_checker s2tte_is_x,
947 bool check_ns_attrs)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000948{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100949 assert(table != NULL);
950
Soby Mathewb4c6df42022-11-09 11:13:29 +0000951 unsigned long base_pa;
952 unsigned long map_size = s2tte_map_size(level);
953 unsigned long s2tte = s2tte_read(&table[0]);
954 unsigned int i;
955
956 if (!s2tte_is_x(s2tte, level)) {
957 return false;
958 }
959
960 base_pa = s2tte_pa(s2tte, level);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100961 if (!s2tte_is_addr_lvl_aligned(base_pa, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000962 return false;
963 }
964
965 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
966 unsigned long expected_pa = base_pa + (i * map_size);
967
968 s2tte = s2tte_read(&table[i]);
969
970 if (!s2tte_is_x(s2tte, level)) {
971 return false;
972 }
973
974 if (s2tte_pa(s2tte, level) != expected_pa) {
975 return false;
976 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100977
978 if (check_ns_attrs) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100979 unsigned long ns_attrs =
980 s2tte & S2TTE_NS_ATTR_HOST_MASK;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100981
982 /*
983 * We match all the attributes in the S2TTE
984 * except for the AF bit.
985 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100986 if ((s2tte & S2TTE_NS_ATTR_HOST_MASK) != ns_attrs) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100987 return false;
988 }
989 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000990 }
991
992 return true;
993}
994
995/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100996 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +0000997 * and refer to a contiguous block of granules aligned to @level - 1.
998 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100999bool s2tt_maps_assigned_empty_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001000{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001001 return table_maps_block(table, level, s2tte_is_assigned_empty,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001002 false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001003}
1004
1005/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001006 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001007 * refer to a contiguous block of granules aligned to @level - 1.
1008 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001009bool s2tt_maps_assigned_ram_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001010{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001011 return table_maps_block(table, level, s2tte_is_assigned_ram, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001012}
1013
1014/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001015 * Returns true if
1016 * - all s2ttes in @table are assigned_ns s2ttes and
1017 * - they refer to a contiguous block of granules aligned to @level - 1 and
1018 * - all the s2tte attributes in @table controlled by the host are identical
AlexeiFedorov3a739332023-04-13 13:54:04 +01001019 *
1020 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001021 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001022bool s2tt_maps_assigned_ns_block(unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001023{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001024 return table_maps_block(table, level, s2tte_is_assigned_ns, true);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001025}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001026
1027/*
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001028 * Returns true if all s2ttes are assigned_destroyed and
1029 * refer to a contiguous block of granules aligned to @level - 1.
1030 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001031bool s2tt_maps_assigned_destroyed_block(unsigned long *table, long level)
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001032{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001033 return table_maps_block(table, level, s2tte_is_assigned_destroyed,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001034 false);
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001035}
1036
1037/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001038 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001039 * skip the non-live entries (i.e., HIPAS=UNASSIGNED).
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001040 * In other words, the scanning stops when a live RTTE is encountered or we
1041 * reach the end of this RTT.
1042 *
1043 * For now an RTTE can be considered non-live if it doesn't have a PA.
1044 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1045 * in the RTTE.
1046 *
1047 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1048 * with RMI_ERROR_RTT).
1049 *
1050 * Returns:
1051 * - If the entry @wi.index is live, returns @addr.
1052 * - If none of the entries in the @s2tt are "live", returns the address of the
1053 * first entry in the next table.
1054 * - Otherwise, the address of the first live entry in @s2tt
1055 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001056unsigned long s2tt_skip_non_live_entries(unsigned long addr,
1057 unsigned long *table,
1058 const struct s2tt_walk *wi)
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001059{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001060 assert(table != NULL);
1061 assert(wi != NULL);
1062 assert(wi->index <= S2TTES_PER_S2TT);
1063 assert(wi->last_level >= S2TT_MIN_STARTING_LEVEL);
1064 assert(wi->last_level <= S2TT_PAGE_LEVEL);
1065
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001066 unsigned long i, index = wi->index;
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001067 long level = wi->last_level;
1068 unsigned long map_size;
1069
1070 /*
1071 * If the entry for the map_addr is live,
1072 * return @addr.
1073 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001074 if (s2tte_is_live(s2tte_read(&table[index]), level)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001075 return addr;
1076 }
1077
1078 /*
1079 * Align the address DOWN to the map_size, as expected for the @level,
1080 * so that we can compute the correct address by using the index.
1081 */
1082 map_size = s2tte_map_size(level);
1083 addr &= ~(map_size - 1UL);
1084
1085 /* Skip the "index" */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001086 for (i = index + 1UL; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001087 unsigned long s2tte = s2tte_read(&table[i]);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001088
1089 if (s2tte_is_live(s2tte, level)) {
1090 break;
1091 }
1092 }
1093
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001094 return (addr + ((i - index) * map_size));
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001095}