blob: 6b9692bdba385dada5dad6e353161ce169b5fb0e [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>
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00007#include <assert.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +00008#include <bitmap.h>
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00009#include <buffer.h>
AlexeiFedorovd2e93932025-01-13 17:24:37 +000010#include <dev_granule.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000011#include <granule.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000012#include <ripas.h>
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010013#include <s2tt.h>
14#include <s2tt_pvt_defs.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000015#include <smc.h>
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +000016#include <stdbool.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000017#include <stddef.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000018
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +000019/*
20 * Return a mask for the IPA field on a S2TTE
21 */
22static unsigned long s2tte_lvl_mask(long level, bool lpa2)
23{
24 assert(level <= S2TT_PAGE_LEVEL);
25 assert(level >= S2TT_MIN_STARTING_LEVEL_LPA2);
26
27 unsigned long mask;
28 unsigned long levels = (unsigned long)(S2TT_PAGE_LEVEL - level);
29 unsigned long lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
30
31 mask = BIT_MASK_ULL((S2TTE_OA_BITS - 1U), lsb);
32
33 if (lpa2 == true) {
34 mask |= (MASK(LPA2_S2TTE_51_50) | MASK(LPA2_OA_49_48));
35 }
36
37 return mask;
38}
39
40/*
41 * Extracts the PA mapped by an S2TTE, aligned to a given level.
42 */
43static unsigned long s2tte_to_pa(unsigned long s2tte, long level, bool lpa2)
44{
45 unsigned long pa = s2tte & s2tte_lvl_mask(level, lpa2);
46
47 if (lpa2 == true) {
48 pa &= ~MASK(LPA2_S2TTE_51_50);
49 pa |= INPLACE(LPA2_OA_51_50, EXTRACT(LPA2_S2TTE_51_50, s2tte));
50 }
51
52 return pa;
53}
Soby Mathewb4c6df42022-11-09 11:13:29 +000054
55/*
56 * Invalidates S2 TLB entries from [ipa, ipa + size] region tagged with `vmid`.
57 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +000058static void stage2_tlbi_ipa(const struct s2tt_context *s2_ctx,
Soby Mathewb4c6df42022-11-09 11:13:29 +000059 unsigned long ipa,
60 unsigned long size)
61{
62 /*
63 * Notes:
64 *
65 * - This follows the description provided in the Arm ARM on
66 * "Invalidation of TLB entries from stage 2 translations".
67 *
68 * - @TODO: Provide additional information to this primitive so that
69 * we can utilize:
70 * - The TTL level hint, see FEAT_TTL,
71 * - Final level lookup only invalidation,
72 * - Address range invalidation.
73 */
74
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010075 assert(s2_ctx != NULL);
76
Soby Mathewb4c6df42022-11-09 11:13:29 +000077 /*
78 * Save the current content of vttb_el2.
79 */
80 unsigned long old_vttbr_el2 = read_vttbr_el2();
81
82 /*
83 * Make 'vmid' the `current vmid`. Note that the tlbi instructions
84 * bellow target the TLB entries that match the `current vmid`.
85 */
86 write_vttbr_el2(INPLACE(VTTBR_EL2_VMID, s2_ctx->vmid));
87 isb();
88
89 /*
90 * Invalidate entries in S2 TLB caches that
91 * match both `ipa` & the `current vmid`.
92 */
93 while (size != 0UL) {
94 tlbiipas2e1is(ipa >> 12);
95 size -= GRANULE_SIZE;
96 ipa += GRANULE_SIZE;
97 }
98 dsb(ish);
99
100 /*
101 * The architecture does not require TLB invalidation by IPA to affect
102 * combined Stage-1 + Stage-2 TLBs. Therefore we must invalidate all of
103 * Stage-1 (tagged with the `current vmid`) after invalidating Stage-2.
104 */
105 tlbivmalle1is();
106 dsb(ish);
107 isb();
108
109 /*
110 * Restore the old content of vttb_el2.
111 */
112 write_vttbr_el2(old_vttbr_el2);
113 isb();
114}
115
116/*
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100117 * Returns true if @s2tte has HIPAS=@hipas.
118 */
119static inline bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
120{
121 bool invalid_desc = ((s2tte & S2TT_DESC_VALID_MASK) == S2TTE_INVALID);
122 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
123
124 return (invalid_desc && (invalid_desc_hipas == hipas));
125}
126
127/*
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000128 * Returns true if s2tte has 'output address' field, namely, if it is one of:
AlexeiFedorovd2e93932025-01-13 17:24:37 +0000129 * - valid TTE
130 * - HIPAS = assigned
131 * - HIPAS = assigned_dev
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000132 */
133static bool s2tte_has_pa(const struct s2tt_context *s2_ctx,
134 unsigned long s2tte, long level)
135{
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100136 (void)s2_ctx;
137 (void)level;
138 bool valid_desc = ((s2tte & S2TT_DESC_VALID_MASK) == S2TTE_VALID);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000139
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100140 return (valid_desc || /* block, page or table */
AlexeiFedorovd2e93932025-01-13 17:24:37 +0000141 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED) ||
142 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED_DEV));
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000143}
144
145/*
146 * Creates a TTE containing only the PA.
147 * This function expects 'pa' to be aligned and bounded.
148 */
149static unsigned long pa_to_s2tte(unsigned long pa, bool lpa2)
150{
151 unsigned long tte = pa;
152
153 if (lpa2 == true) {
154 tte &= ~MASK(LPA2_OA_51_50);
155 tte |= INPLACE(LPA2_S2TTE_51_50, EXTRACT(LPA2_OA_51_50, pa));
156 }
157
158 return tte;
159}
160
161/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000162 * Invalidate S2 TLB entries with "addr" IPA.
163 * Call this function after:
164 * 1. A L3 page desc has been removed.
165 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000166void s2tt_invalidate_page(const struct s2tt_context *s2_ctx, unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000167{
168 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
169}
170
171/*
172 * Invalidate S2 TLB entries with "addr" IPA.
173 * Call this function after:
174 * 1. A L2 block desc has been removed, or
175 * 2a. A L2 table desc has been removed, where
176 * 2b. All S2TTEs in L3 table that the L2 table desc was pointed to were invalid.
177 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000178void s2tt_invalidate_block(const struct s2tt_context *s2_ctx, unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000179{
180 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
181}
182
183/*
184 * Invalidate S2 TLB entries with "addr" IPA.
185 * Call this function after:
186 * 1a. A L2 table desc has been removed, where
187 * 1b. Some S2TTEs in the table that the L2 table desc was pointed to were valid.
188 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000189void s2tt_invalidate_pages_in_block(const struct s2tt_context *s2_ctx,
190 unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000191{
192 stage2_tlbi_ipa(s2_ctx, addr, BLOCK_L2_SIZE);
193}
194
195/*
196 * Return the index of the entry describing @addr in the translation table at
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000197 * level @level. This only works for non-concatenated page tables, so should
Soby Mathewb4c6df42022-11-09 11:13:29 +0000198 * not be called to get the index for the starting level.
199 *
200 * See the library pseudocode
201 * aarch64/translation/vmsa_addrcalc/AArch64.TTEntryAddress on which this is
202 * modeled.
203 */
204static unsigned long s2_addr_to_idx(unsigned long addr, long level)
205{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100206 unsigned int levels, lsb;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000207 unsigned int s2tte_stride = (level < S2TT_MIN_STARTING_LEVEL) ?
208 S2TTE_STRIDE_LM1 : S2TTE_STRIDE;
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100209
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100210 levels = (unsigned int)(S2TT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100211 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000212
213 addr >>= lsb;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000214 addr &= (1UL << s2tte_stride) - 1UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000215 return addr;
216}
217
218/*
219 * Return the index of the entry describing @addr in the translation table
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000220 * starting level. This may return an index >= S2TTES_PER_S2TT when the
Soby Mathewb4c6df42022-11-09 11:13:29 +0000221 * combination of @start_level and @ipa_bits implies concatenated
222 * stage 2 tables.
223 *
224 * See the library pseudocode
225 * aarch64/translation/vmsa_addrcalc/AArch64.S2SLTTEntryAddress on which
226 * this is modeled.
227 */
228static unsigned long s2_sl_addr_to_idx(unsigned long addr, int start_level,
229 unsigned long ipa_bits)
230{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100231 unsigned int levels, lsb;
232
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100233 levels = (unsigned int)(S2TT_PAGE_LEVEL - start_level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100234 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000235
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000236 addr &= ((1UL << ipa_bits) - 1UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000237 addr >>= lsb;
238 return addr;
239}
240
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000241static bool entry_is_table(unsigned long entry)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000242{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100243 return ((entry & S2TT_DESC_TYPE_MASK) == S2TTE_L012_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000244}
245
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000246static unsigned long table_get_entry(const struct s2tt_context *s2_ctx,
247 struct granule *g_tbl,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100248 unsigned long idx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000249{
250 unsigned long *table, entry;
251
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000252 (void)s2_ctx;
253
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000254 table = buffer_granule_map(g_tbl, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100255 assert(table != NULL);
256
Soby Mathewb4c6df42022-11-09 11:13:29 +0000257 entry = s2tte_read(&table[idx]);
258 buffer_unmap(table);
259
260 return entry;
261}
262
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000263#define table_entry_to_phys(tte, lpa2) \
264 s2tte_to_pa(tte, S2TT_PAGE_LEVEL, lpa2)
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100265
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000266static struct granule *find_next_level_idx(const struct s2tt_context *s2_ctx,
267 struct granule *g_tbl,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100268 unsigned long idx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000269{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000270 assert(s2_ctx != NULL);
271
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000272 const unsigned long entry = table_get_entry(s2_ctx, g_tbl, idx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000273
274 if (!entry_is_table(entry)) {
275 return NULL;
276 }
277
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000278 return addr_to_granule(table_entry_to_phys(entry, s2_ctx->enable_lpa2));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000279}
280
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000281static struct granule *find_lock_next_level(const struct s2tt_context *s2_ctx,
282 struct granule *g_tbl,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100283 unsigned long map_addr,
284 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000285{
286 const unsigned long idx = s2_addr_to_idx(map_addr, level);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000287 struct granule *g = find_next_level_idx(s2_ctx, g_tbl, idx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000288
289 if (g != NULL) {
290 granule_lock(g, GRANULE_STATE_RTT);
291 }
292
293 return g;
294}
295
296/*
297 * Walk an RTT until level @level using @map_addr.
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000298 * @g_root is the root (level 0/-1) table and must be locked before the call.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000299 * @start_level is the initial lookup level used for the stage 2 translation
300 * tables which may depend on the configuration of the realm, factoring in the
301 * IPA size of the realm and the desired starting level (within the limits
302 * defined by the Armv8 VMSA including options for stage 2 table concatenation).
303 * The function uses hand-over-hand locking to avoid race conditions and allow
304 * concurrent access to RTT tree which is not part of the current walk; when a
305 * next level table is reached it is locked before releasing previously locked
306 * table.
307 * The walk stops when either:
308 * - The entry found is a leaf entry (not an RTT Table entry), or
309 * - Level @level is reached.
310 *
311 * On return:
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100312 * - s2tt_walk::last_level is the last level that has been reached by the walk.
313 * - s2tt_walk.g_llt points to the TABLE granule at level @s2tt_walk::level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000314 * The granule is locked.
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000315 * - s2tt_walk::index is the entry index at s2tt_walk.g_llt for @map_addr.i
316 *
317 * NOTE: This function expects that the root table on the s2 context is
318 * already locked.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000319 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000320void s2tt_walk_lock_unlock(const struct s2tt_context *s2_ctx,
321 unsigned long map_addr,
322 long level,
323 struct s2tt_walk *wi)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000324{
Aliyha Ajmal7f9ee6e2024-10-10 10:44:17 +0100325 /* coverity[misra_c_2012_rule_11_9_violation:SUPRESS] */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000326 struct granule *g_tbls[NR_RTT_LEVELS_LPA2] = { (struct granule *)NULL };
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000327 struct granule *g_root;
328 unsigned long sl_idx, ipa_bits;
329 int i, start_level, last_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000330
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000331 assert(s2_ctx != NULL);
332
333 start_level = s2_ctx->s2_starting_level;
334 ipa_bits = s2_ctx->ipa_bits;
335
Soby Mathewb4c6df42022-11-09 11:13:29 +0000336 assert(level >= start_level);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100337 assert(level <= S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000338 assert(map_addr < (1UL << ipa_bits));
339 assert(wi != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000340
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100341 if (s2_ctx->enable_lpa2 == true) {
342 assert(ipa_bits <= S2TTE_OA_BITS_LPA2);
343 } else {
344 assert(ipa_bits <= S2TTE_OA_BITS);
345 }
346
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000347 g_root = s2_ctx->g_rtt;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000348
349 /* Handle concatenated starting level (SL) tables */
350 sl_idx = s2_sl_addr_to_idx(map_addr, start_level, ipa_bits);
351 if (sl_idx >= S2TTES_PER_S2TT) {
AlexeiFedorov4faab852023-08-30 15:06:49 +0100352 unsigned int tt_num = (unsigned int)(sl_idx >> S2TTE_STRIDE);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100353 struct granule *g_concat_root;
354
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100355 assert(tt_num < s2_ctx->num_root_rtts);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100356
357 g_concat_root = (struct granule *)((uintptr_t)g_root +
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000358 (tt_num * sizeof(struct granule)));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000359
360 granule_lock(g_concat_root, GRANULE_STATE_RTT);
361 granule_unlock(g_root);
362 g_root = g_concat_root;
363 }
364
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000365 /* 'start_level' can be '-1', so add 1 when used as an index */
366 g_tbls[start_level + 1] = g_root;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000367 for (i = start_level; i < level; i++) {
368 /*
369 * Lock next RTT level. Correct locking order is guaranteed
370 * because reference is obtained from a locked granule
371 * (previous level). Also, hand-over-hand locking/unlocking is
372 * used to avoid race conditions.
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000373 *
374 * Note that as 'start_level' can be -1, we add '1' to the
375 * index 'i' to compensate for the negative value when we
376 * use it to index then 'g_tbls' list.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000377 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000378 g_tbls[i + 1 + 1] = find_lock_next_level(s2_ctx, g_tbls[i + 1],
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000379 map_addr, i);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000380 if (g_tbls[i + 1 + 1] == NULL) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000381 last_level = i;
382 goto out;
383 }
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000384 granule_unlock(g_tbls[i + 1]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000385 }
386
AlexeiFedorov4faab852023-08-30 15:06:49 +0100387 last_level = (int)level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000388out:
389 wi->last_level = last_level;
AlexeiFedorove956db32024-04-04 14:36:21 +0100390 /* coverity[deref_overflow:SUPPRESS] */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000391 wi->g_llt = g_tbls[last_level + 1];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000392 wi->index = s2_addr_to_idx(map_addr, last_level);
393}
394
395/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100396 * Creates an unassigned_empty s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000397 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000398unsigned long s2tte_create_unassigned_empty(const struct s2tt_context *s2_ctx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000399{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000400 (void)s2_ctx;
401
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100402 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100403}
404
405/*
406 * Creates an unassigned_ram s2tte.
407 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000408unsigned long s2tte_create_unassigned_ram(const struct s2tt_context *s2_ctx)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100409{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000410 (void)s2_ctx;
411
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100412 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000413}
414
415/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100416 * Creates an unassigned_destroyed s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000417 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000418unsigned long s2tte_create_unassigned_destroyed(const struct s2tt_context *s2_ctx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000419{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000420 (void)s2_ctx;
421
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100422 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
423}
424
425/*
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100426 * Creates an unassigned_ns s2tte.
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100427 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000428unsigned long s2tte_create_unassigned_ns(const struct s2tt_context *s2_ctx)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100429{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000430 (void)s2_ctx;
431
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100432 return (S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000433}
434
435/*
AlexeiFedorovd2e93932025-01-13 17:24:37 +0000436 * Creates s2tte with output address @pa, HIPAS=ASSIGNED and
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100437 * RIPAS=@s2tte_ripas, at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000438 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000439static unsigned long s2tte_create_assigned(const struct s2tt_context *s2_ctx,
440 unsigned long pa, long level,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100441 unsigned long s2tte_ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000442{
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100443 unsigned long tte;
444
AlexeiFedorovd2e93932025-01-13 17:24:37 +0000445 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100446 assert(level >= S2TT_MIN_BLOCK_LEVEL);
447 assert(level <= S2TT_PAGE_LEVEL);
AlexeiFedorovd2e93932025-01-13 17:24:37 +0000448 assert(s2tte_ripas <= S2TTE_INVALID_RIPAS_DESTROYED);
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100449 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000450
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100451 tte = pa_to_s2tte(pa, s2_ctx->enable_lpa2);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100452
453 if (s2tte_ripas == S2TTE_INVALID_RIPAS_RAM) {
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100454 unsigned long s2tte_page, s2tte_block;
455
456 if (s2_ctx->enable_lpa2) {
457 s2tte_page = S2TTE_PAGE_LPA2;
458 s2tte_block = S2TTE_BLOCK_LPA2;
459 } else {
460 s2tte_page = S2TTE_PAGE;
461 s2tte_block = S2TTE_BLOCK;
462 }
463
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100464 if (level == S2TT_PAGE_LEVEL) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000465 return (tte | s2tte_page);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100466 }
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000467 return (tte | s2tte_block);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100468 }
469
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000470 return (tte | S2TTE_INVALID_HIPAS_ASSIGNED | s2tte_ripas);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100471}
472
473/*
474 * Creates and invalid s2tte with output address @pa, HIPAS=ASSIGNED and
475 * RIPAS=DESTROYED at level @level.
476 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000477unsigned long s2tte_create_assigned_destroyed(const struct s2tt_context *s2_ctx,
478 unsigned long pa, long level)
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100479{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000480 return s2tte_create_assigned(s2_ctx, pa, level,
481 S2TTE_INVALID_RIPAS_DESTROYED);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100482}
483
484/*
485 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
486 * RIPAS=EMPTY at level @level.
487 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000488unsigned long s2tte_create_assigned_empty(const struct s2tt_context *s2_ctx,
489 unsigned long pa, long level)
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100490{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000491 return s2tte_create_assigned(s2_ctx, pa, level,
492 S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000493}
494
495/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100496 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000497 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000498unsigned long s2tte_create_assigned_ram(const struct s2tt_context *s2_ctx,
499 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000500{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000501 return s2tte_create_assigned(s2_ctx, pa, level,
502 S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000503}
504
505/*
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100506 * Creates an assigned s2tte with output address @pa and the same
507 * RIPAS as passed on @s2tte.
508 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000509unsigned long s2tte_create_assigned_unchanged(const struct s2tt_context *s2_ctx,
510 unsigned long s2tte,
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100511 unsigned long pa,
512 long level)
513{
514 unsigned long current_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
515
AlexeiFedorovd2e93932025-01-13 17:24:37 +0000516 assert((s2tte & S2TT_DESC_VALID_MASK) == S2TTE_INVALID);
517
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000518 return s2tte_create_assigned(s2_ctx, pa, level, current_ripas);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000519}
520
521/*
AlexeiFedorovd2e93932025-01-13 17:24:37 +0000522 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED_DEV and
523 * RIPAS=@s2tte_ripas, at level @level.
524 * This function is only called for @s2tte_ripas values corresponding to
525 * RIPAS_EMPTY and RIPAS_DESTROYED.
526 */
527static unsigned long s2tte_create_assigned_dev(const struct s2tt_context *s2_ctx,
528 unsigned long pa, long level,
529 unsigned long s2tte_ripas)
530{
531 (void)level;
532 unsigned long tte;
533
534 assert(s2_ctx != NULL);
535 assert(level >= S2TT_MIN_DEV_BLOCK_LEVEL);
536 assert((s2tte_ripas == S2TTE_INVALID_RIPAS_EMPTY) ||
537 (s2tte_ripas == S2TTE_INVALID_RIPAS_DESTROYED));
538 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
539
540 tte = pa_to_s2tte(pa, s2_ctx->enable_lpa2);
541
542 return (tte | S2TTE_INVALID_HIPAS_ASSIGNED_DEV | s2tte_ripas);
543}
544
545/*
546 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED_DEV
547 * and RIPAS=EMPTY, at level @level.
548 */
549unsigned long s2tte_create_assigned_dev_empty(const struct s2tt_context *s2_ctx,
550 unsigned long pa, long level)
551{
552 return s2tte_create_assigned_dev(s2_ctx, pa, level,
553 S2TTE_INVALID_RIPAS_EMPTY);
554}
555
556/*
557 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED_DEV and
558 * RIPAS=DESTROYED, at level @level.
559 */
560unsigned long s2tte_create_assigned_dev_destroyed(const struct s2tt_context *s2_ctx,
561 unsigned long pa, long level)
562{
563 return s2tte_create_assigned_dev(s2_ctx, pa, level,
564 S2TTE_INVALID_RIPAS_DESTROYED);
565}
566
567/*
568 * Creates an dev_assigned s2tte with output address @pa and the same
569 * RIPAS as passed on @s2tte.
570 */
571unsigned long s2tte_create_assigned_dev_unchanged(const struct s2tt_context *s2_ctx,
572 unsigned long s2tte,
573 unsigned long pa,
574 long level)
575{
576 unsigned long current_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
577
578 assert((s2tte & S2TT_DESC_VALID_MASK) == S2TTE_INVALID);
579
580 return s2tte_create_assigned_dev(s2_ctx, pa, level, current_ripas);
581}
582
583/*
584 * Creates a valid assigned_dev_dev s2tte at @level with attributes passed in
585 * @attr.
586 */
587static unsigned long create_assigned_dev_dev_attr(unsigned long s2tte,
588 unsigned long attr, long level,
589 bool lpa2)
590{
591 unsigned long pa, new_s2tte;
592
593 assert(level >= S2TT_MIN_DEV_BLOCK_LEVEL);
594
595 pa = s2tte_to_pa(s2tte, level, lpa2);
596
597 new_s2tte = attr | pa_to_s2tte(pa, lpa2);
598
599 if (level == S2TT_PAGE_LEVEL) {
600 return (new_s2tte | S2TTE_L3_PAGE);
601 }
602
603 return (new_s2tte | S2TTE_L012_BLOCK);
604}
605
606/*
607 * Creates a valid assigned_dev_dev s2tte at @level with attributes passed in
608 * @s2tte.
609 */
610unsigned long s2tte_create_assigned_dev_dev(const struct s2tt_context *s2_ctx,
611 unsigned long s2tte, long level)
612{
613 unsigned long s2tte_mask = (S2TTE_DEV_ATTRS_MASK | S2TTE_MEMATTR_MASK);
614 unsigned long attr;
615 bool lpa2;
616
617 assert(s2_ctx != NULL);
618
619 lpa2 = s2_ctx->enable_lpa2;
620
621 /* Add Shareability bits if FEAT_LPA2 is not enabled */
622 if (!lpa2) {
623 s2tte_mask |= S2TTE_SH_MASK;
624 }
625
626 /* Get attributes */
627 attr = s2tte & s2tte_mask;
628
629 return create_assigned_dev_dev_attr(s2tte, attr, level, lpa2);
630}
631
632/*
633 * Creates a valid assigned_dev_dev s2tte at @level with attributes based on
634 * device coherency passed in @type.
635 */
636unsigned long s2tte_create_assigned_dev_dev_coh_type(const struct s2tt_context *s2_ctx,
637 unsigned long s2tte, long level,
638 enum dev_coh_type type)
639{
640 unsigned long attr;
641 bool lpa2;
642
643 assert(s2_ctx != NULL);
644 assert(type < DEV_MEM_MAX);
645
646 lpa2 = s2_ctx->enable_lpa2;
647
648 if (type == DEV_MEM_COHERENT) {
649 /* Coherent device */
650 attr = S2TTE_DEV_COH_ATTRS;
651
652 /* Add Shareability bits if FEAT_LPA2 is not enabled */
653 if (!lpa2) {
654 attr |= S2TTE_SH_IS; /* Inner Shareable */
655 }
656 } else {
657 /* Non-coherent device */
658 attr = S2TTE_DEV_NCOH_ATTRS;
659
660 /* Add Shareability bits if FEAT_LPA2 is not enabled */
661 if (!lpa2) {
662 attr |= S2TTE_SH_OS; /* Outer Shareable */
663 }
664 }
665
666 return create_assigned_dev_dev_attr(s2tte, attr, level, lpa2);
667}
668
669/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100670 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000671 *
672 * The following S2 TTE fields are provided through @s2tte argument:
673 * - The physical address
674 * - MemAttr
675 * - S2AP
Soby Mathewb4c6df42022-11-09 11:13:29 +0000676 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000677unsigned long s2tte_create_assigned_ns(const struct s2tt_context *s2_ctx,
678 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000679{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000680 /*
Soby Mathew217748d2024-10-02 11:02:19 +0100681 * We just mask out the DESC_TYPE below. We assume rest of the
682 * bits have been setup properly by the caller.
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000683 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100684 unsigned long new_s2tte = s2tte & ~S2TT_DESC_TYPE_MASK;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000685
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100686 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100687 assert(level >= S2TT_MIN_BLOCK_LEVEL);
688 assert(level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100689
Soby Mathew217748d2024-10-02 11:02:19 +0100690 /* The Shareability bits need to be added if FEAT_LPA2 is not enabled */
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100691 if (!s2_ctx->enable_lpa2) {
Soby Mathew217748d2024-10-02 11:02:19 +0100692 new_s2tte |= S2TTE_SH_IS;
693 }
694
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100695 if (level == S2TT_PAGE_LEVEL) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100696 return (new_s2tte | S2TTE_PAGE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000697 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100698 return (new_s2tte | S2TTE_BLOCK_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000699}
700
701/*
702 * Validate the portion of NS S2TTE that is provided by the host.
703 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000704bool host_ns_s2tte_is_valid(const struct s2tt_context *s2_ctx,
705 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000706{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000707 bool lpa2;
708 unsigned long mask;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100709
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000710 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100711 assert(level >= S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000712
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000713 lpa2 = s2_ctx->enable_lpa2;
714
Soby Mathew217748d2024-10-02 11:02:19 +0100715 mask = s2tte_lvl_mask(level, lpa2) | S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000716
Soby Mathewb4c6df42022-11-09 11:13:29 +0000717 /*
718 * Test that all fields that are not controlled by the host are zero
719 * and that the output address is correctly aligned. Note that
720 * the host is permitted to map any physical address outside PAR.
Shruti Gupta3530a712024-09-12 10:50:21 +0100721 * Note that this also checks for the case when FEAT_LPA2 is disabled
722 * for the Realm, then the PA in `s2tte` must be <= 48 bits wide.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000723 */
724 if ((s2tte & ~mask) != 0UL) {
725 return false;
726 }
727
728 /*
729 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
730 */
731 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
732 return false;
733 }
734
735 /*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000736 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
737 */
738 return true;
739}
740
741/*
742 * Returns the portion of NS S2TTE that is set by the host.
743 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000744unsigned long host_ns_s2tte(const struct s2tt_context *s2_ctx,
745 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000746{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000747 assert(s2_ctx != NULL);
748
Soby Mathew217748d2024-10-02 11:02:19 +0100749 unsigned long mask = s2tte_lvl_mask(level, s2_ctx->enable_lpa2)
750 | S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000751
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100752 assert(level >= S2TT_MIN_BLOCK_LEVEL);
753
Soby Mathewb4c6df42022-11-09 11:13:29 +0000754 return (s2tte & mask);
755}
756
757/*
758 * Creates a table s2tte at level @level with output address @pa.
759 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000760unsigned long s2tte_create_table(const struct s2tt_context *s2_ctx,
761 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000762{
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100763 (void)level;
AlexeiFedorovd2e93932025-01-13 17:24:37 +0000764 __unused long min_starting_level;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000765
766 assert(s2_ctx != NULL);
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +0100767
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100768 min_starting_level = s2_ctx->enable_lpa2 ?
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000769 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100770
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100771 assert(level < S2TT_PAGE_LEVEL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000772 assert(level >= min_starting_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000773 assert(GRANULE_ALIGNED(pa));
774
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000775 return (pa_to_s2tte(pa, s2_ctx->enable_lpa2) | S2TTE_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000776}
777
778/*
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100779 * Returns true if s2tte has defined RIPAS value, namely if it is one of:
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100780 * - unassigned_empty
781 * - unassigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100782 * - unassigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100783 * - assigned_empty
784 * - assigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100785 * - assigned_destroyed
AlexeiFedorovf8923202025-05-16 18:41:13 +0100786 * - assigned_dev
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100787 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000788bool s2tte_has_ripas(const struct s2tt_context *s2_ctx,
789 unsigned long s2tte, long level)
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100790{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000791 return (((s2tte & S2TTE_NS) == 0UL) && !s2tte_is_table(s2_ctx,
792 s2tte, level));
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100793}
794
795/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100796 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000797 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100798static inline bool s2tte_has_unassigned_ripas(unsigned long s2tte,
799 unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000800{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100801 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
802 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
803}
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100804
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100805/*
806 * Returns true if @s2tte has HIPAS=ASSIGNED and RIPAS=@ripas.
807 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100808static inline bool s2tte_has_assigned_ripas(unsigned long s2tte,
809 unsigned long ripas)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100810{
AlexeiFedorovd2e93932025-01-13 17:24:37 +0000811 assert((s2tte & S2TT_DESC_VALID_MASK) == S2TTE_INVALID);
812 assert(ripas != S2TTE_INVALID_RIPAS_RAM);
813
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100814 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
815 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100816}
817
818/*
AlexeiFedorovd2e93932025-01-13 17:24:37 +0000819 * Returns true if @s2tte has HIPAS=ASSIGNED_DEV and RIPAS=@ripas.
820 */
821static bool s2tte_has_assigned_dev_ripas(unsigned long s2tte, unsigned long ripas)
822{
823 assert((s2tte & S2TT_DESC_VALID_MASK) == S2TTE_INVALID);
824 assert(ripas != S2TTE_INVALID_RIPAS_DEV);
825
826 return ((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
827 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED_DEV);
828}
829
830/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100831 * Returns true if @s2tte has HIPAS=UNASSIGNED.
832 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000833bool s2tte_is_unassigned(const struct s2tt_context *s2_ctx, unsigned long s2tte)
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100834{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000835 (void)s2_ctx;
836
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100837 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED);
838}
839
840/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100841 * Returns true if @s2tte is an unassigned_empty.
842 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000843bool s2tte_is_unassigned_empty(const struct s2tt_context *s2_ctx,
844 unsigned long s2tte)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100845{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000846 (void)s2_ctx;
847
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100848 return (((s2tte & S2TTE_NS) == 0UL) &&
849 s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100850}
851
852/*
853 * Returns true if @s2tte is an unassigned_ram.
854 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000855bool s2tte_is_unassigned_ram(const struct s2tt_context *s2_ctx,
856 unsigned long s2tte)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100857{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000858 (void)s2_ctx;
859
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100860 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
861}
862
863/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100864 * Returns true if @s2tte is unassigned_ns.
865 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000866bool s2tte_is_unassigned_ns(const struct s2tt_context *s2_ctx,
867 unsigned long s2tte)
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100868{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000869 (void)s2_ctx;
870
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100871 return (((s2tte & S2TTE_NS) != 0UL) &&
872 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000873}
874
875/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100876 * Returns true if @s2tte has RIPAS=DESTROYED.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000877 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000878bool s2tte_is_unassigned_destroyed(const struct s2tt_context *s2_ctx,
879 unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000880{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000881 (void)s2_ctx;
882
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100883 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
884}
885
886/*
887 * Returns true if @s2tte is an assigned_destroyed.
888 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000889bool s2tte_is_assigned_destroyed(const struct s2tt_context *s2_ctx,
890 unsigned long s2tte, long level)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100891{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000892 (void)s2_ctx;
AlexeiFedorovd2e93932025-01-13 17:24:37 +0000893 (void)level;
894
895 if ((s2tte & S2TT_DESC_VALID_MASK) != S2TTE_INVALID) {
896 return false;
897 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100898
899 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000900}
901
902/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100903 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000904 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000905bool s2tte_is_assigned_empty(const struct s2tt_context *s2_ctx,
906 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000907{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000908 (void)s2_ctx;
AlexeiFedorovd2e93932025-01-13 17:24:37 +0000909 (void)level;
910
911 if ((s2tte & S2TT_DESC_VALID_MASK) != S2TTE_INVALID) {
912 return false;
913 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000914
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100915 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000916}
917
AlexeiFedorovf8923202025-05-16 18:41:13 +0100918static bool s2tte_check_assigned_ram_or_ns(const struct s2tt_context *s2_ctx,
919 unsigned long s2tte, long level,
920 unsigned long ns)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000921{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000922 (void)s2_ctx;
AlexeiFedorovf8923202025-05-16 18:41:13 +0100923 unsigned long attr, desc_type;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000924
Soby Mathewb4c6df42022-11-09 11:13:29 +0000925 if ((s2tte & S2TTE_NS) != ns) {
926 return false;
927 }
928
AlexeiFedorovf8923202025-05-16 18:41:13 +0100929 attr = s2tte & (S2TTE_DEV_ATTRS_MASK | S2TTE_MEMATTR_MASK);
930
931 /* Return false for device memory */
932 if ((attr == S2TTE_DEV_COH_ATTRS) || (attr == S2TTE_DEV_NCOH_ATTRS)) {
933 return false;
934 }
935
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100936 desc_type = s2tte & S2TT_DESC_TYPE_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000937
Shruti Gupta3105c3f2024-02-26 14:06:11 +0000938 /* Only pages at L3 and valid blocks at L2 and L1 allowed */
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100939 if (level == S2TT_PAGE_LEVEL) {
940 return (desc_type == S2TTE_L3_PAGE);
941 }
942
943 if ((level >= S2TT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000944 return true;
945 }
946
947 return false;
948}
949
950/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100951 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000952 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000953bool s2tte_is_assigned_ram(const struct s2tt_context *s2_ctx,
954 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000955{
AlexeiFedorovf8923202025-05-16 18:41:13 +0100956 return s2tte_check_assigned_ram_or_ns(s2_ctx, s2tte, level, 0UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000957}
958
959/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100960 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000961 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000962bool s2tte_is_assigned_ns(const struct s2tt_context *s2_ctx,
963 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000964{
AlexeiFedorovf8923202025-05-16 18:41:13 +0100965 return s2tte_check_assigned_ram_or_ns(s2_ctx, s2tte, level, S2TTE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000966}
967
968/*
AlexeiFedorovd2e93932025-01-13 17:24:37 +0000969 * Returns true if @s2tte has HIPAS=ASSIGNED_DEV and RIPAS=RIPAS_DEV.
970 */
971bool s2tte_is_assigned_dev_dev(const struct s2tt_context *s2_ctx,
972 unsigned long s2tte, long level)
973{
974 unsigned long attr;
975 unsigned long desc_type = s2tte & S2TT_DESC_TYPE_MASK;
976 bool lpa2;
977
978 assert(s2_ctx != NULL);
979
980 /* Only pages at L3 and valid blocks at L2 allowed */
981 if (!(((level == S2TT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
982 ((level == S2TT_MIN_DEV_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK)))) {
983 return false;
984 }
985
986 attr = s2tte & (S2TTE_DEV_ATTRS_MASK | S2TTE_MEMATTR_MASK);
987 lpa2 = s2_ctx->enable_lpa2;
988
989 /*
990 * Check that NS, XN, S2AP, AF and MemAttr[3:0] match with provided
991 * attributes. When LPA2 is not enabled, assert if shareability
992 * attrubutes are not set correctly.
993 */
994 if (attr == S2TTE_DEV_COH_ATTRS) {
995 if (!lpa2) {
996 /* Coherent device, Inner Shareable */
997 assert((s2tte & S2TTE_SH_MASK) == S2TTE_SH_IS);
998 }
999 return true;
1000 } else if (attr == S2TTE_DEV_NCOH_ATTRS) {
1001 if (!lpa2) {
1002 /* Non-coherent device, Outer Shareable */
1003 assert((s2tte & S2TTE_SH_MASK) == S2TTE_SH_OS);
1004 }
1005 return true;
1006 }
1007 return false;
1008}
1009
1010/*
1011 * Returns true if @s2tte has HIPAS=ASSIGNED_DEV and RIPAS=RIPAS_EMPTY.
1012 */
1013bool s2tte_is_assigned_dev_empty(const struct s2tt_context *s2_ctx,
1014 unsigned long s2tte, long level)
1015{
1016 (void)s2_ctx;
1017 (void)level;
1018
1019 if ((s2tte & S2TT_DESC_VALID_MASK) != S2TTE_INVALID) {
1020 return false;
1021 }
1022
1023 return s2tte_has_assigned_dev_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
1024}
1025
1026/*
1027 * Returns true if @s2tte is an dev_assigned_destroyed.
1028 */
1029bool s2tte_is_assigned_dev_destroyed(const struct s2tt_context *s2_ctx,
1030 unsigned long s2tte, long level)
1031{
1032 (void)s2_ctx;
1033 (void)level;
1034
1035 if ((s2tte & S2TT_DESC_VALID_MASK) != S2TTE_INVALID) {
1036 return false;
1037 }
1038
1039 return s2tte_has_assigned_dev_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
1040}
1041
1042/*
Soby Mathewb4c6df42022-11-09 11:13:29 +00001043 * Returns true if @s2tte is a table at level @level.
1044 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001045bool s2tte_is_table(const struct s2tt_context *s2_ctx, unsigned long s2tte,
1046 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001047{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001048 (void)s2_ctx;
1049
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001050 return ((level < S2TT_PAGE_LEVEL) &&
1051 ((s2tte & S2TT_DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +00001052}
1053
1054/*
1055 * Returns RIPAS of @s2tte.
1056 *
AlexeiFedorovf8923202025-05-16 18:41:13 +01001057 * Caller should ensure that HIPAS=UNASSIGNED, ASSIGNED or ASSIGNED_DEV
1058 * The s2tte, if valid, should correspond to RIPAS_RAM or RIPAS_DEV.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001059 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001060enum ripas s2tte_get_ripas(const struct s2tt_context *s2_ctx, unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001061{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001062 (void)s2_ctx;
AlexeiFedorov479c9fb2025-05-29 16:57:41 +01001063 __unused unsigned long desc_hipas;
1064 enum ripas desc_ripas;
AlexeiFedorova018c2e2025-04-07 11:36:54 +01001065 bool valid_desc = ((s2tte & S2TT_DESC_VALID_MASK) == S2TTE_VALID);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001066
Soby Mathewb4c6df42022-11-09 11:13:29 +00001067 /*
Javier Almansa Sobrinob802a0e2024-07-05 12:52:23 +01001068 * If a valid S2TTE descriptor is passed, the RIPAS corresponds to
AlexeiFedorovf8923202025-05-16 18:41:13 +01001069 * RIPAS_RAM or RIPAS_DEV.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001070 */
AlexeiFedorova018c2e2025-04-07 11:36:54 +01001071 if (valid_desc) {
1072 __unused unsigned long desc_type = s2tte & S2TT_DESC_TYPE_MASK;
AlexeiFedorovf8923202025-05-16 18:41:13 +01001073 unsigned long attr = s2tte & (S2TTE_DEV_ATTRS_MASK |
1074 S2TTE_MEMATTR_MASK);
AlexeiFedorova018c2e2025-04-07 11:36:54 +01001075
Javier Almansa Sobrinob802a0e2024-07-05 12:52:23 +01001076 assert((desc_type == S2TTE_L012_BLOCK) ||
1077 (desc_type == S2TTE_L3_PAGE));
AlexeiFedorovf8923202025-05-16 18:41:13 +01001078 /*
1079 * For device memory check that NS, XN, S2AP, AF and MemAttr[3:0]
1080 * match with S2TTE_DEV_COH_ATTRS or S2TTE_DEV_NCOH_ATTRS
1081 * attributes.
1082 * Assume that shareability attrubutes are set correctly.
1083 */
1084 if ((attr == S2TTE_DEV_COH_ATTRS) ||
1085 (attr == S2TTE_DEV_NCOH_ATTRS)) {
1086 return RIPAS_DEV;
1087 }
Javier Almansa Sobrinob802a0e2024-07-05 12:52:23 +01001088 return RIPAS_RAM;
1089 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001090
AlexeiFedorov479c9fb2025-05-29 16:57:41 +01001091 desc_hipas = EXTRACT(S2TTE_INVALID_HIPAS, s2tte);
1092
AlexeiFedorovf8923202025-05-16 18:41:13 +01001093 /* Only HIPAS=UNASSIGNED, ASSIGNED or ASSIGNED_DEV are valid */
AlexeiFedorov479c9fb2025-05-29 16:57:41 +01001094 assert((desc_hipas <= RMI_ASSIGNED_DEV) && (desc_hipas != RMI_TABLE));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001095
AlexeiFedorov479c9fb2025-05-29 16:57:41 +01001096 desc_ripas = (enum ripas)EXTRACT(S2TTE_INVALID_RIPAS, s2tte);
1097 assert(desc_ripas <= RIPAS_DESTROYED);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001098
AlexeiFedorov479c9fb2025-05-29 16:57:41 +01001099 return desc_ripas;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001100}
1101
1102/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001103 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001104 *
1105 * The granule is populated before it is made a table,
1106 * hence, don't use s2tte_write for access.
1107 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001108void s2tt_init_unassigned_empty(const struct s2tt_context *s2_ctx,
1109 unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001110{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001111 unsigned long s2tte =
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001112 s2tte_create_unassigned_empty(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001113
AlexeiFedorovd2e93932025-01-13 17:24:37 +00001114 assert(s2tt != NULL);
1115
Soby Mathewb4c6df42022-11-09 11:13:29 +00001116 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001117 s2tt[i] = s2tte;
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001118 }
1119
1120 dsb(ish);
1121}
1122
1123/*
1124 * Populates @s2tt with unassigned_ram s2ttes.
1125 *
1126 * The granule is populated before it is made a table,
1127 * hence, don't use s2tte_write for access.
1128 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001129void s2tt_init_unassigned_ram(const struct s2tt_context *s2_ctx,
1130 unsigned long *s2tt)
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001131{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001132 unsigned long s2tte = s2tte_create_unassigned_ram(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001133
AlexeiFedorovd2e93932025-01-13 17:24:37 +00001134 assert(s2tt != NULL);
1135
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001136 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001137 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001138 }
1139
1140 dsb(ish);
1141}
1142
1143/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001144 * Populates @s2tt with unassigned_ns s2ttes.
1145 *
1146 * The granule is populated before it is made a table,
1147 * hence, don't use s2tte_write for access.
1148 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001149void s2tt_init_unassigned_ns(const struct s2tt_context *s2_ctx,
1150 unsigned long *s2tt)
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001151{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001152 unsigned long s2tte = s2tte_create_unassigned_ns(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001153
AlexeiFedorovd2e93932025-01-13 17:24:37 +00001154 assert(s2tt != NULL);
1155
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001156 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001157 s2tt[i] = s2tte;
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001158 }
1159
1160 dsb(ish);
1161}
1162
1163/*
Soby Mathewb4c6df42022-11-09 11:13:29 +00001164 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
1165 *
1166 * The granule is populated before it is made a table,
1167 * hence, don't use s2tte_write for access.
1168 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001169void s2tt_init_unassigned_destroyed(const struct s2tt_context *s2_ctx,
1170 unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001171{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001172 unsigned long s2tte =
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001173 s2tte_create_unassigned_destroyed(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001174
AlexeiFedorovd2e93932025-01-13 17:24:37 +00001175 assert(s2tt != NULL);
1176
Soby Mathewb4c6df42022-11-09 11:13:29 +00001177 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001178 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001179 }
AlexeiFedorovd2e93932025-01-13 17:24:37 +00001180
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001181 dsb(ish);
1182}
Soby Mathewb4c6df42022-11-09 11:13:29 +00001183
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001184/*
1185 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
1186 * contiguous memory block starting at @pa, and mapped at level @level.
1187 *
1188 * The granule is populated before it is made a table,
1189 * hence, don't use s2tte_write for access.
1190 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001191void s2tt_init_assigned_destroyed(const struct s2tt_context *s2_ctx,
1192 unsigned long *s2tt, unsigned long pa,
1193 long level)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001194{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001195 assert(s2tt != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001196 assert(level >= S2TT_MIN_BLOCK_LEVEL);
1197 assert(level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001198 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001199
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001200 const unsigned long map_size = s2tte_map_size(level);
1201
1202 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001203 s2tt[i] = s2tte_create_assigned_destroyed(s2_ctx, pa, level);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001204 pa += map_size;
1205 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001206 dsb(ish);
1207}
1208
Soby Mathewb4c6df42022-11-09 11:13:29 +00001209/*
1210 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
1211 * contiguous memory block starting at @pa, and mapped at level @level.
1212 *
1213 * The granule is populated before it is made a table,
1214 * hence, don't use s2tte_write for access.
1215 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001216void s2tt_init_assigned_empty(const struct s2tt_context *s2_ctx,
1217 unsigned long *s2tt, unsigned long pa,
1218 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001219{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001220 assert(level >= S2TT_MIN_BLOCK_LEVEL);
1221 assert(level <= S2TT_PAGE_LEVEL);
1222 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001223 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001224
Soby Mathewb4c6df42022-11-09 11:13:29 +00001225 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001226
AlexeiFedorov3a739332023-04-13 13:54:04 +01001227 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001228 s2tt[i] = s2tte_create_assigned_empty(s2_ctx, pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001229 pa += map_size;
1230 }
1231 dsb(ish);
1232}
1233
1234/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001235 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +00001236 * contiguous memory block starting at @pa, and mapped at level @level.
1237 *
1238 * The granule is populated before it is made a table,
1239 * hence, don't use s2tte_write for access.
1240 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001241void s2tt_init_assigned_ram(const struct s2tt_context *s2_ctx,
1242 unsigned long *s2tt, unsigned long pa,
1243 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001244{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001245 assert(level >= S2TT_MIN_BLOCK_LEVEL);
1246 assert(level <= S2TT_PAGE_LEVEL);
1247 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001248 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001249
Soby Mathewb4c6df42022-11-09 11:13:29 +00001250 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001251
AlexeiFedorov3a739332023-04-13 13:54:04 +01001252 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001253 s2tt[i] = s2tte_create_assigned_ram(s2_ctx, pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001254 pa += map_size;
1255 }
1256 dsb(ish);
1257}
1258
1259/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001260 * Populates @s2tt with NS attributes @attrs that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +00001261 * contiguous memory block starting at @pa, and mapped at level @level.
1262 *
1263 * The granule is populated before it is made a table,
1264 * hence, don't use s2tte_write for access.
1265 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001266void s2tt_init_assigned_ns(const struct s2tt_context *s2_ctx,
1267 unsigned long *s2tt, unsigned long attrs,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001268 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001269{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001270 assert(level >= S2TT_MIN_BLOCK_LEVEL);
1271 assert(level <= S2TT_PAGE_LEVEL);
1272 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001273 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001274
Soby Mathewb4c6df42022-11-09 11:13:29 +00001275 const unsigned long map_size = s2tte_map_size(level);
Soby Mathew217748d2024-10-02 11:02:19 +01001276
1277 attrs &= S2TTE_NS_ATTR_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001278
AlexeiFedorov3a739332023-04-13 13:54:04 +01001279 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001280 s2tt[i] = s2tte_create_assigned_ns(s2_ctx,
Soby Mathew217748d2024-10-02 11:02:19 +01001281 attrs | pa_to_s2tte(pa, s2_ctx->enable_lpa2),
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001282 level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001283 pa += map_size;
1284 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001285
Soby Mathewb4c6df42022-11-09 11:13:29 +00001286 dsb(ish);
1287}
1288
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001289/*
AlexeiFedorovd2e93932025-01-13 17:24:37 +00001290 * Populates @s2tt with HIPAS=ASSIGNED_DEV, RIPAS=EMPTY s2ttes that refer to a
1291 * contiguous memory block starting at @pa, and mapped at level @level.
1292 *
1293 * The granule is populated before it is made a table,
1294 * hence, don't use s2tte_write for access.
1295 */
1296void s2tt_init_assigned_dev_empty(const struct s2tt_context *s2_ctx,
1297 unsigned long *s2tt, unsigned long pa, long level)
1298{
1299 const unsigned long map_size = s2tte_map_size(level);
1300
1301 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
1302 s2tt[i] = s2tte_create_assigned_dev_empty(s2_ctx, pa, level);
1303 pa += map_size;
1304 }
1305
1306 dsb(ish);
1307}
1308
1309/*
1310 * Populates @s2tt with HIPAS=ASSIGNED_DEV, RIPAS=DESTROYED s2ttes that refer to a
1311 * contiguous memory block starting at @pa, and mapped at level @level.
1312 *
1313 * The granule is populated before it is made a table,
1314 * hence, don't use s2tte_write for access.
1315 */
1316void s2tt_init_assigned_dev_destroyed(const struct s2tt_context *s2_ctx,
1317 unsigned long *s2tt, unsigned long pa, long level)
1318{
1319 const unsigned long map_size = s2tte_map_size(level);
1320
1321 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
1322 s2tt[i] = s2tte_create_assigned_dev_destroyed(s2_ctx, pa, level);
1323 pa += map_size;
1324 }
1325
1326 dsb(ish);
1327}
1328
1329/*
1330 * Populates @s2tt with assigned_dev_dev s2ttes that refer to a
1331 * contiguous memory block starting at @pa, and mapped at level @level.
1332 *
1333 * The granule is populated before it is made a table,
1334 * hence, don't use s2tte_write for access.
1335 */
1336void s2tt_init_assigned_dev_dev(const struct s2tt_context *s2_ctx,
1337 unsigned long *s2tt, unsigned long s2tte,
1338 unsigned long pa, long level)
1339{
1340 const unsigned long map_size = s2tte_map_size(level);
1341 unsigned long s2tte_mask = (S2TTE_DEV_ATTRS_MASK | S2TTE_MEMATTR_MASK);
1342
1343 assert(s2_ctx != NULL);
1344 assert(level >= S2TT_MIN_DEV_BLOCK_LEVEL);
1345
1346 /* Add Shareability bits if FEAT_LPA2 is not enabled */
1347 if (!s2_ctx->enable_lpa2) {
1348 s2tte_mask |= S2TTE_SH_MASK;
1349 }
1350
1351 s2tte &= s2tte_mask;
1352
1353 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
1354 s2tt[i] = s2tte_create_assigned_dev_dev(s2_ctx, s2tte | pa, level);
1355 pa += map_size;
1356 }
1357
1358 dsb(ish);
1359}
1360
1361/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001362 * Returns true if s2tte is a live RTTE entry. i.e.,
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001363 * HIPAS is ASSIGNED.
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001364 *
1365 * NOTE: For now, only the RTTE with PA are live.
1366 * This could change with EXPORT/IMPORT support.
1367 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001368static bool s2tte_is_live(const struct s2tt_context *s2_ctx,
1369 unsigned long s2tte, long level)
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001370{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001371 return s2tte_has_pa(s2_ctx, s2tte, level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001372}
1373
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001374/* Returns physical address of a S2TTE */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001375unsigned long s2tte_pa(const struct s2tt_context *s2_ctx, unsigned long s2tte,
1376 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001377{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001378 bool lpa2;
1379 unsigned long pa;
1380 __unused long min_starting_level;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001381
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001382 assert(s2_ctx != NULL);
1383
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +01001384 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001385 min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1386 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1387 assert(level >= min_starting_level);
1388 assert(level <= S2TT_PAGE_LEVEL);
1389 assert(s2tte_has_pa(s2_ctx, s2tte, level));
1390
1391 lpa2 = s2_ctx->enable_lpa2;
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001392
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001393 if (s2tte_is_table(s2_ctx, s2tte, level)) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001394 pa = table_entry_to_phys(s2tte, lpa2);
1395 } else {
1396 pa = s2tte_to_pa(s2tte, level, lpa2);
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001397 }
1398
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001399 return pa;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001400}
1401
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001402bool s2tte_is_addr_lvl_aligned(const struct s2tt_context *s2_ctx,
1403 unsigned long addr, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001404{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001405 assert(s2_ctx != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001406
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +01001407 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001408 __unused long min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1409 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1410 unsigned long levels = (unsigned long)(S2TT_PAGE_LEVEL - level);
1411 unsigned long lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
1412 unsigned long s2tte_oa_bits = (s2_ctx->enable_lpa2 == true) ?
1413 S2TTE_OA_BITS_LPA2 : S2TTE_OA_BITS;
1414
1415 assert(level <= S2TT_PAGE_LEVEL);
1416 assert(level >= min_starting_level);
1417
1418 return (addr == (addr & BIT_MASK_ULL((s2tte_oa_bits - 1U), lsb)));
Soby Mathewb4c6df42022-11-09 11:13:29 +00001419}
1420
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001421typedef bool (*s2tte_type_checker)(const struct s2tt_context *s2_ctx,
1422 unsigned long s2tte);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001423
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001424static bool table_is_uniform_block(const struct s2tt_context *s2_ctx,
1425 unsigned long *table,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001426 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001427{
AlexeiFedorov377d81f2023-04-14 16:29:12 +01001428 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
1429 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001430
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001431 if (!s2tte_is_x(s2_ctx, s2tte)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001432 return false;
1433 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001434 }
1435
1436 return true;
1437}
1438
1439/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001440 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001441 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001442bool s2tt_is_unassigned_empty_block(const struct s2tt_context *s2_ctx,
1443 unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001444{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001445 assert(table != NULL);
1446
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001447 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001448}
1449
1450/*
1451 * Returns true if all s2ttes in @table are unassigned_ram.
1452 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001453bool s2tt_is_unassigned_ram_block(const struct s2tt_context *s2_ctx,
1454 unsigned long *table)
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001455{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001456 assert(table != NULL);
1457
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001458 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001459}
1460
1461/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001462 * Returns true if all s2ttes in @table are unassigned_ns
1463 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001464bool s2tt_is_unassigned_ns_block(const struct s2tt_context *s2_ctx,
1465 unsigned long *table)
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001466{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001467 assert(table != NULL);
1468
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001469 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001470}
1471
1472/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001473 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +00001474 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001475bool s2tt_is_unassigned_destroyed_block(const struct s2tt_context *s2_ctx,
1476 unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001477{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001478 assert(table != NULL);
1479
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001480 return table_is_uniform_block(s2_ctx, table,
1481 s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001482}
1483
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001484typedef bool (*s2tte_type_level_checker)(const struct s2tt_context *s2_ctx,
1485 unsigned long s2tte, long level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001486
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001487static bool table_maps_block(const struct s2tt_context *s2_ctx,
1488 unsigned long *table,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001489 long level,
1490 s2tte_type_level_checker s2tte_is_x,
1491 bool check_ns_attrs)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001492{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001493 assert(table != NULL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001494 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001495
Soby Mathew217748d2024-10-02 11:02:19 +01001496 unsigned long base_pa;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001497 unsigned long map_size = s2tte_map_size(level);
1498 unsigned long s2tte = s2tte_read(&table[0]);
Javier Almansa Sobrino8865ec32024-04-18 10:50:03 +01001499 unsigned long s2tt_ns_attrs;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001500 unsigned int i;
1501
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +01001502 if (s2_ctx->enable_lpa2 == true) {
1503 assert(level >= S2TT_MIN_STARTING_LEVEL_LPA2);
1504 } else {
1505 assert(level >= S2TT_MIN_STARTING_LEVEL);
1506 }
1507
1508 assert(level <= S2TT_PAGE_LEVEL);
1509
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001510 if (!s2tte_is_x(s2_ctx, s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001511 return false;
1512 }
1513
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001514 base_pa = s2tte_pa(s2_ctx, s2tte, level);
1515 if (!s2tte_is_addr_lvl_aligned(s2_ctx, base_pa, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001516 return false;
1517 }
1518
Soby Mathew217748d2024-10-02 11:02:19 +01001519 s2tt_ns_attrs = s2tte & S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001520
Soby Mathewb4c6df42022-11-09 11:13:29 +00001521 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
1522 unsigned long expected_pa = base_pa + (i * map_size);
1523
1524 s2tte = s2tte_read(&table[i]);
1525
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001526 if (!s2tte_is_x(s2_ctx, s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001527 return false;
1528 }
1529
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001530 if (s2tte_pa(s2_ctx, s2tte, level) != expected_pa) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001531 return false;
1532 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001533
1534 if (check_ns_attrs) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001535 unsigned long ns_attrs =
Soby Mathew217748d2024-10-02 11:02:19 +01001536 s2tte & S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001537
1538 /*
1539 * We match all the attributes in the S2TTE
1540 * except for the AF bit.
1541 */
Javier Almansa Sobrino8865ec32024-04-18 10:50:03 +01001542 if (s2tt_ns_attrs != ns_attrs) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001543 return false;
1544 }
1545 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001546 }
1547
1548 return true;
1549}
1550
1551/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001552 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +00001553 * and refer to a contiguous block of granules aligned to @level - 1.
1554 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001555bool s2tt_maps_assigned_empty_block(const struct s2tt_context *s2_ctx,
1556 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001557{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001558 return table_maps_block(s2_ctx, table, level,
1559 s2tte_is_assigned_empty, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001560}
1561
1562/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001563 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001564 * refer to a contiguous block of granules aligned to @level - 1.
1565 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001566bool s2tt_maps_assigned_ram_block(const struct s2tt_context *s2_ctx,
1567 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001568{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001569 return table_maps_block(s2_ctx, table, level,
1570 s2tte_is_assigned_ram, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001571}
1572
1573/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001574 * Returns true if
1575 * - all s2ttes in @table are assigned_ns s2ttes and
1576 * - they refer to a contiguous block of granules aligned to @level - 1 and
1577 * - all the s2tte attributes in @table controlled by the host are identical
AlexeiFedorov3a739332023-04-13 13:54:04 +01001578 *
1579 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001580 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001581bool s2tt_maps_assigned_ns_block(const struct s2tt_context *s2_ctx,
1582 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001583{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001584 return table_maps_block(s2_ctx, table, level,
1585 s2tte_is_assigned_ns, true);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001586}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001587
1588/*
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001589 * Returns true if all s2ttes are assigned_destroyed and
1590 * refer to a contiguous block of granules aligned to @level - 1.
1591 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001592bool s2tt_maps_assigned_destroyed_block(const struct s2tt_context *s2_ctx,
1593 unsigned long *table, long level)
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001594{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001595 return table_maps_block(s2_ctx, table, level,
1596 s2tte_is_assigned_destroyed, false);
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001597}
1598
1599/*
AlexeiFedorovd2e93932025-01-13 17:24:37 +00001600 * Returns true if all s2ttes are assigned_dev_empty and
1601 * refer to a contiguous block of granules aligned to @level - 1.
1602 */
1603bool s2tt_maps_assigned_dev_empty_block(const struct s2tt_context *s2_ctx,
1604 unsigned long *table, long level)
1605{
1606 return table_maps_block(s2_ctx, table, level,
1607 s2tte_is_assigned_dev_empty, false);
1608}
1609
1610/*
1611 * Returns true if all s2ttes are assigned_dev_destroyed and
1612 * refer to a contiguous block of granules aligned to @level - 1.
1613 */
1614bool s2tt_maps_assigned_dev_destroyed_block(const struct s2tt_context *s2_ctx,
1615 unsigned long *table, long level)
1616{
1617 return table_maps_block(s2_ctx, table, level,
1618 s2tte_is_assigned_dev_destroyed, false);
1619}
1620
1621/*
1622 * Returns true if all s2ttes are assigned_dev_dev and
1623 * refer to a contiguous block of granules aligned to @level - 1.
1624 */
1625bool s2tt_maps_assigned_dev_dev_block(const struct s2tt_context *s2_ctx,
1626 unsigned long *table, long level)
1627{
1628 return table_maps_block(s2_ctx, table, level,
1629 s2tte_is_assigned_dev_dev, false);
1630}
1631
1632/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001633 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001634 * skip the non-live entries (i.e., HIPAS=UNASSIGNED).
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001635 * In other words, the scanning stops when a live RTTE is encountered or we
1636 * reach the end of this RTT.
1637 *
1638 * For now an RTTE can be considered non-live if it doesn't have a PA.
1639 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1640 * in the RTTE.
1641 *
1642 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1643 * with RMI_ERROR_RTT).
1644 *
1645 * Returns:
1646 * - If the entry @wi.index is live, returns @addr.
1647 * - If none of the entries in the @s2tt are "live", returns the address of the
1648 * first entry in the next table.
1649 * - Otherwise, the address of the first live entry in @s2tt
1650 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001651unsigned long s2tt_skip_non_live_entries(const struct s2tt_context *s2_ctx,
1652 unsigned long addr,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001653 unsigned long *table,
1654 const struct s2tt_walk *wi)
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001655{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001656 assert(table != NULL);
1657 assert(wi != NULL);
1658 assert(wi->index <= S2TTES_PER_S2TT);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001659 assert(wi->last_level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001660 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001661
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001662 unsigned long i, index = wi->index;
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001663 long level = wi->last_level;
1664 unsigned long map_size;
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +01001665
1666 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001667 __unused long min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1668 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1669
1670 assert(wi->last_level >= min_starting_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001671
1672 /*
1673 * If the entry for the map_addr is live,
1674 * return @addr.
1675 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001676 if (s2tte_is_live(s2_ctx, s2tte_read(&table[index]), level)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001677 return addr;
1678 }
1679
1680 /*
1681 * Align the address DOWN to the map_size, as expected for the @level,
1682 * so that we can compute the correct address by using the index.
1683 */
1684 map_size = s2tte_map_size(level);
1685 addr &= ~(map_size - 1UL);
1686
1687 /* Skip the "index" */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001688 for (i = index + 1UL; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001689 unsigned long s2tte = s2tte_read(&table[i]);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001690
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001691 if (s2tte_is_live(s2_ctx, s2tte, level)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001692 break;
1693 }
1694 }
1695
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001696 return (addr + ((i - index) * map_size));
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001697}