blob: 6149eadebd52faf684f0f0c1e7e148236c7273d1 [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>
Soby Mathewb4c6df42022-11-09 11:13:29 +000010#include <granule.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000011#include <ripas.h>
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010012#include <s2tt.h>
13#include <s2tt_pvt_defs.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000014#include <smc.h>
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +000015#include <stdbool.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000016#include <stddef.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000017
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +000018/*
19 * Return a mask for the IPA field on a S2TTE
20 */
21static unsigned long s2tte_lvl_mask(long level, bool lpa2)
22{
23 assert(level <= S2TT_PAGE_LEVEL);
24 assert(level >= S2TT_MIN_STARTING_LEVEL_LPA2);
25
26 unsigned long mask;
27 unsigned long levels = (unsigned long)(S2TT_PAGE_LEVEL - level);
28 unsigned long lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
29
30 mask = BIT_MASK_ULL((S2TTE_OA_BITS - 1U), lsb);
31
32 if (lpa2 == true) {
33 mask |= (MASK(LPA2_S2TTE_51_50) | MASK(LPA2_OA_49_48));
34 }
35
36 return mask;
37}
38
39/*
40 * Extracts the PA mapped by an S2TTE, aligned to a given level.
41 */
42static unsigned long s2tte_to_pa(unsigned long s2tte, long level, bool lpa2)
43{
44 unsigned long pa = s2tte & s2tte_lvl_mask(level, lpa2);
45
46 if (lpa2 == true) {
47 pa &= ~MASK(LPA2_S2TTE_51_50);
48 pa |= INPLACE(LPA2_OA_51_50, EXTRACT(LPA2_S2TTE_51_50, s2tte));
49 }
50
51 return pa;
52}
Soby Mathewb4c6df42022-11-09 11:13:29 +000053
54/*
55 * Invalidates S2 TLB entries from [ipa, ipa + size] region tagged with `vmid`.
56 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +000057static void stage2_tlbi_ipa(const struct s2tt_context *s2_ctx,
Soby Mathewb4c6df42022-11-09 11:13:29 +000058 unsigned long ipa,
59 unsigned long size)
60{
61 /*
62 * Notes:
63 *
64 * - This follows the description provided in the Arm ARM on
65 * "Invalidation of TLB entries from stage 2 translations".
66 *
67 * - @TODO: Provide additional information to this primitive so that
68 * we can utilize:
69 * - The TTL level hint, see FEAT_TTL,
70 * - Final level lookup only invalidation,
71 * - Address range invalidation.
72 */
73
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010074 assert(s2_ctx != NULL);
75
Soby Mathewb4c6df42022-11-09 11:13:29 +000076 /*
77 * Save the current content of vttb_el2.
78 */
79 unsigned long old_vttbr_el2 = read_vttbr_el2();
80
81 /*
82 * Make 'vmid' the `current vmid`. Note that the tlbi instructions
83 * bellow target the TLB entries that match the `current vmid`.
84 */
85 write_vttbr_el2(INPLACE(VTTBR_EL2_VMID, s2_ctx->vmid));
86 isb();
87
88 /*
89 * Invalidate entries in S2 TLB caches that
90 * match both `ipa` & the `current vmid`.
91 */
92 while (size != 0UL) {
93 tlbiipas2e1is(ipa >> 12);
94 size -= GRANULE_SIZE;
95 ipa += GRANULE_SIZE;
96 }
97 dsb(ish);
98
99 /*
100 * The architecture does not require TLB invalidation by IPA to affect
101 * combined Stage-1 + Stage-2 TLBs. Therefore we must invalidate all of
102 * Stage-1 (tagged with the `current vmid`) after invalidating Stage-2.
103 */
104 tlbivmalle1is();
105 dsb(ish);
106 isb();
107
108 /*
109 * Restore the old content of vttb_el2.
110 */
111 write_vttbr_el2(old_vttbr_el2);
112 isb();
113}
114
115/*
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100116 * Returns true if @s2tte has HIPAS=@hipas.
117 */
118static inline bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
119{
120 bool invalid_desc = ((s2tte & S2TT_DESC_VALID_MASK) == S2TTE_INVALID);
121 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
122
123 return (invalid_desc && (invalid_desc_hipas == hipas));
124}
125
126/*
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000127 * Returns true if s2tte has 'output address' field, namely, if it is one of:
128 * - assigned_empty
129 * - assigned_ram
130 * - assigned_ns
131 * - assigned_destroyed
132 * - table
133 */
134static bool s2tte_has_pa(const struct s2tt_context *s2_ctx,
135 unsigned long s2tte, long level)
136{
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100137 (void)s2_ctx;
138 (void)level;
139 bool valid_desc = ((s2tte & S2TT_DESC_VALID_MASK) == S2TTE_VALID);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000140
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100141 return (valid_desc || /* block, page or table */
142 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED));
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/*
436 * Creates an invalid 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
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100445 assert(level >= S2TT_MIN_BLOCK_LEVEL);
446 assert(level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100447 assert(EXTRACT(S2TTE_INVALID_RIPAS, s2tte_ripas)
448 <= EXTRACT(S2TTE_INVALID_RIPAS, S2TTE_INVALID_RIPAS_DESTROYED));
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000449 assert(s2_ctx != NULL);
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100450 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000451
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100452 tte = pa_to_s2tte(pa, s2_ctx->enable_lpa2);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100453
454 if (s2tte_ripas == S2TTE_INVALID_RIPAS_RAM) {
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100455 unsigned long s2tte_page, s2tte_block;
456
457 if (s2_ctx->enable_lpa2) {
458 s2tte_page = S2TTE_PAGE_LPA2;
459 s2tte_block = S2TTE_BLOCK_LPA2;
460 } else {
461 s2tte_page = S2TTE_PAGE;
462 s2tte_block = S2TTE_BLOCK;
463 }
464
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100465 if (level == S2TT_PAGE_LEVEL) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000466 return (tte | s2tte_page);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100467 }
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000468 return (tte | s2tte_block);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100469 }
470
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000471 return (tte | S2TTE_INVALID_HIPAS_ASSIGNED | s2tte_ripas);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100472}
473
474/*
475 * Creates and invalid s2tte with output address @pa, HIPAS=ASSIGNED and
476 * RIPAS=DESTROYED at level @level.
477 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000478unsigned long s2tte_create_assigned_destroyed(const struct s2tt_context *s2_ctx,
479 unsigned long pa, long level)
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100480{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000481 return s2tte_create_assigned(s2_ctx, pa, level,
482 S2TTE_INVALID_RIPAS_DESTROYED);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100483}
484
485/*
486 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
487 * RIPAS=EMPTY at level @level.
488 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000489unsigned long s2tte_create_assigned_empty(const struct s2tt_context *s2_ctx,
490 unsigned long pa, long level)
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100491{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000492 return s2tte_create_assigned(s2_ctx, pa, level,
493 S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000494}
495
496/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100497 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000498 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000499unsigned long s2tte_create_assigned_ram(const struct s2tt_context *s2_ctx,
500 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000501{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000502 return s2tte_create_assigned(s2_ctx, pa, level,
503 S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000504}
505
506/*
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100507 * Creates an assigned s2tte with output address @pa and the same
508 * RIPAS as passed on @s2tte.
509 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000510unsigned long s2tte_create_assigned_unchanged(const struct s2tt_context *s2_ctx,
511 unsigned long s2tte,
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100512 unsigned long pa,
513 long level)
514{
515 unsigned long current_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
516
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000517 return s2tte_create_assigned(s2_ctx, pa, level, current_ripas);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000518}
519
520/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100521 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000522 *
523 * The following S2 TTE fields are provided through @s2tte argument:
524 * - The physical address
525 * - MemAttr
526 * - S2AP
Soby Mathewb4c6df42022-11-09 11:13:29 +0000527 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000528unsigned long s2tte_create_assigned_ns(const struct s2tt_context *s2_ctx,
529 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000530{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000531 /*
Soby Mathew217748d2024-10-02 11:02:19 +0100532 * We just mask out the DESC_TYPE below. We assume rest of the
533 * bits have been setup properly by the caller.
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000534 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100535 unsigned long new_s2tte = s2tte & ~S2TT_DESC_TYPE_MASK;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000536
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100537 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100538 assert(level >= S2TT_MIN_BLOCK_LEVEL);
539 assert(level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100540
Soby Mathew217748d2024-10-02 11:02:19 +0100541 /* The Shareability bits need to be added if FEAT_LPA2 is not enabled */
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100542 if (!s2_ctx->enable_lpa2) {
Soby Mathew217748d2024-10-02 11:02:19 +0100543 new_s2tte |= S2TTE_SH_IS;
544 }
545
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100546 if (level == S2TT_PAGE_LEVEL) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100547 return (new_s2tte | S2TTE_PAGE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000548 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100549 return (new_s2tte | S2TTE_BLOCK_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000550}
551
552/*
553 * Validate the portion of NS S2TTE that is provided by the host.
554 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000555bool host_ns_s2tte_is_valid(const struct s2tt_context *s2_ctx,
556 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000557{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000558 bool lpa2;
559 unsigned long mask;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100560
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000561 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100562 assert(level >= S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000563
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000564 lpa2 = s2_ctx->enable_lpa2;
565
Soby Mathew217748d2024-10-02 11:02:19 +0100566 mask = s2tte_lvl_mask(level, lpa2) | S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000567
Soby Mathewb4c6df42022-11-09 11:13:29 +0000568 /*
569 * Test that all fields that are not controlled by the host are zero
570 * and that the output address is correctly aligned. Note that
571 * the host is permitted to map any physical address outside PAR.
Shruti Gupta3530a712024-09-12 10:50:21 +0100572 * Note that this also checks for the case when FEAT_LPA2 is disabled
573 * for the Realm, then the PA in `s2tte` must be <= 48 bits wide.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000574 */
575 if ((s2tte & ~mask) != 0UL) {
576 return false;
577 }
578
579 /*
580 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
581 */
582 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
583 return false;
584 }
585
586 /*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000587 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
588 */
589 return true;
590}
591
592/*
593 * Returns the portion of NS S2TTE that is set by the host.
594 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000595unsigned long host_ns_s2tte(const struct s2tt_context *s2_ctx,
596 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000597{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000598 assert(s2_ctx != NULL);
599
Soby Mathew217748d2024-10-02 11:02:19 +0100600 unsigned long mask = s2tte_lvl_mask(level, s2_ctx->enable_lpa2)
601 | S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000602
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100603 assert(level >= S2TT_MIN_BLOCK_LEVEL);
604
Soby Mathewb4c6df42022-11-09 11:13:29 +0000605 return (s2tte & mask);
606}
607
608/*
609 * Creates a table s2tte at level @level with output address @pa.
610 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000611unsigned long s2tte_create_table(const struct s2tt_context *s2_ctx,
612 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000613{
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +0100614 __unused long min_starting_level;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000615
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100616 (void)level;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000617
618 assert(s2_ctx != NULL);
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +0100619
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100620 min_starting_level = s2_ctx->enable_lpa2 ?
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000621 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100622
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100623 assert(level < S2TT_PAGE_LEVEL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000624 assert(level >= min_starting_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000625 assert(GRANULE_ALIGNED(pa));
626
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000627 return (pa_to_s2tte(pa, s2_ctx->enable_lpa2) | S2TTE_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000628}
629
630/*
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100631 * Returns true if s2tte has defined RIPAS value, namely if it is one of:
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100632 * - unassigned_empty
633 * - unassigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100634 * - unassigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100635 * - assigned_empty
636 * - assigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100637 * - assigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100638 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000639bool s2tte_has_ripas(const struct s2tt_context *s2_ctx,
640 unsigned long s2tte, long level)
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100641{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000642 return (((s2tte & S2TTE_NS) == 0UL) && !s2tte_is_table(s2_ctx,
643 s2tte, level));
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100644}
645
646/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100647 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000648 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100649static inline bool s2tte_has_unassigned_ripas(unsigned long s2tte,
650 unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000651{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100652 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
653 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
654}
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100655
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100656/*
657 * Returns true if @s2tte has HIPAS=ASSIGNED and RIPAS=@ripas.
658 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100659static inline bool s2tte_has_assigned_ripas(unsigned long s2tte,
660 unsigned long ripas)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100661{
662 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
663 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100664}
665
666/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100667 * Returns true if @s2tte has HIPAS=UNASSIGNED.
668 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000669bool s2tte_is_unassigned(const struct s2tt_context *s2_ctx, unsigned long s2tte)
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100670{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000671 (void)s2_ctx;
672
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100673 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED);
674}
675
676/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100677 * Returns true if @s2tte is an unassigned_empty.
678 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000679bool s2tte_is_unassigned_empty(const struct s2tt_context *s2_ctx,
680 unsigned long s2tte)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100681{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000682 (void)s2_ctx;
683
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100684 return (((s2tte & S2TTE_NS) == 0UL) &&
685 s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100686}
687
688/*
689 * Returns true if @s2tte is an unassigned_ram.
690 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000691bool s2tte_is_unassigned_ram(const struct s2tt_context *s2_ctx,
692 unsigned long s2tte)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100693{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000694 (void)s2_ctx;
695
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100696 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
697}
698
699/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100700 * Returns true if @s2tte is unassigned_ns.
701 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000702bool s2tte_is_unassigned_ns(const struct s2tt_context *s2_ctx,
703 unsigned long s2tte)
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100704{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000705 (void)s2_ctx;
706
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100707 return (((s2tte & S2TTE_NS) != 0UL) &&
708 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000709}
710
711/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100712 * Returns true if @s2tte has RIPAS=DESTROYED.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000713 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000714bool s2tte_is_unassigned_destroyed(const struct s2tt_context *s2_ctx,
715 unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000716{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000717 (void)s2_ctx;
718
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100719 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
720}
721
722/*
723 * Returns true if @s2tte is an assigned_destroyed.
724 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000725bool s2tte_is_assigned_destroyed(const struct s2tt_context *s2_ctx,
726 unsigned long s2tte, long level)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100727{
728 (void)level;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000729 (void)s2_ctx;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100730
731 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000732}
733
734/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100735 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000736 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000737bool s2tte_is_assigned_empty(const struct s2tt_context *s2_ctx,
738 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000739{
740 (void)level;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000741 (void)s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000742
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100743 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000744}
745
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000746static bool s2tte_check(const struct s2tt_context *s2_ctx, unsigned long s2tte,
747 long level, unsigned long ns)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000748{
749 unsigned long desc_type;
750
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000751 (void)s2_ctx;
752
Soby Mathewb4c6df42022-11-09 11:13:29 +0000753 if ((s2tte & S2TTE_NS) != ns) {
754 return false;
755 }
756
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100757 desc_type = s2tte & S2TT_DESC_TYPE_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000758
Shruti Gupta3105c3f2024-02-26 14:06:11 +0000759 /* Only pages at L3 and valid blocks at L2 and L1 allowed */
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100760 if (level == S2TT_PAGE_LEVEL) {
761 return (desc_type == S2TTE_L3_PAGE);
762 }
763
764 if ((level >= S2TT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000765 return true;
766 }
767
768 return false;
769}
770
771/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100772 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000773 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000774bool s2tte_is_assigned_ram(const struct s2tt_context *s2_ctx,
775 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000776{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000777 return s2tte_check(s2_ctx, s2tte, level, 0UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000778}
779
780/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100781 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000782 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000783bool s2tte_is_assigned_ns(const struct s2tt_context *s2_ctx,
784 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000785{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000786 return s2tte_check(s2_ctx, s2tte, level, S2TTE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000787}
788
789/*
790 * Returns true if @s2tte is a table at level @level.
791 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000792bool s2tte_is_table(const struct s2tt_context *s2_ctx, unsigned long s2tte,
793 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000794{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000795 (void)s2_ctx;
796
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100797 return ((level < S2TT_PAGE_LEVEL) &&
798 ((s2tte & S2TT_DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000799}
800
801/*
802 * Returns RIPAS of @s2tte.
803 *
804 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100805 * The s2tte, if valid, should correspond to RIPAS_RAM.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000806 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000807enum ripas s2tte_get_ripas(const struct s2tt_context *s2_ctx, unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000808{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000809 (void)s2_ctx;
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100810 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
811 bool valid_desc = ((s2tte & S2TT_DESC_VALID_MASK) == S2TTE_VALID);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000812
Soby Mathewb4c6df42022-11-09 11:13:29 +0000813 /*
Javier Almansa Sobrinob802a0e2024-07-05 12:52:23 +0100814 * If a valid S2TTE descriptor is passed, the RIPAS corresponds to
815 * RIPAS_RAM.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000816 */
AlexeiFedorova018c2e2025-04-07 11:36:54 +0100817 if (valid_desc) {
818 __unused unsigned long desc_type = s2tte & S2TT_DESC_TYPE_MASK;
819
Javier Almansa Sobrinob802a0e2024-07-05 12:52:23 +0100820 assert((desc_type == S2TTE_L012_BLOCK) ||
821 (desc_type == S2TTE_L3_PAGE));
822 return RIPAS_RAM;
823 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000824
Javier Almansa Sobrinob802a0e2024-07-05 12:52:23 +0100825 assert(EXTRACT(S2TTE_INVALID_HIPAS, s2tte) <= RMI_ASSIGNED);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100826
827 desc_ripas = desc_ripas >> S2TTE_INVALID_RIPAS_SHIFT;
828
829 assert(desc_ripas <= (unsigned int)RIPAS_DESTROYED);
830
831 return (enum ripas)desc_ripas;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000832}
833
834/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100835 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000836 *
837 * The granule is populated before it is made a table,
838 * hence, don't use s2tte_write for access.
839 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000840void s2tt_init_unassigned_empty(const struct s2tt_context *s2_ctx,
841 unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000842{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100843 assert(s2tt != NULL);
844
845 unsigned long s2tte =
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000846 s2tte_create_unassigned_empty(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100847
Soby Mathewb4c6df42022-11-09 11:13:29 +0000848 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100849 s2tt[i] = s2tte;
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100850 }
851
852 dsb(ish);
853}
854
855/*
856 * Populates @s2tt with unassigned_ram s2ttes.
857 *
858 * The granule is populated before it is made a table,
859 * hence, don't use s2tte_write for access.
860 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000861void s2tt_init_unassigned_ram(const struct s2tt_context *s2_ctx,
862 unsigned long *s2tt)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100863{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100864 assert(s2tt != NULL);
865
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000866 unsigned long s2tte = s2tte_create_unassigned_ram(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100867
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100868 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100869 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000870 }
871
872 dsb(ish);
873}
874
875/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100876 * Populates @s2tt with unassigned_ns s2ttes.
877 *
878 * The granule is populated before it is made a table,
879 * hence, don't use s2tte_write for access.
880 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000881void s2tt_init_unassigned_ns(const struct s2tt_context *s2_ctx,
882 unsigned long *s2tt)
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100883{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100884 assert(s2tt != NULL);
885
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000886 unsigned long s2tte = s2tte_create_unassigned_ns(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100887
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100888 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100889 s2tt[i] = s2tte;
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100890 }
891
892 dsb(ish);
893}
894
895/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000896 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
897 *
898 * The granule is populated before it is made a table,
899 * hence, don't use s2tte_write for access.
900 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000901void s2tt_init_unassigned_destroyed(const struct s2tt_context *s2_ctx,
902 unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000903{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100904 assert(s2tt != NULL);
905
906 unsigned long s2tte =
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000907 s2tte_create_unassigned_destroyed(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100908
Soby Mathewb4c6df42022-11-09 11:13:29 +0000909 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100910 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000911 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100912 dsb(ish);
913}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000914
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100915/*
916 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
917 * contiguous memory block starting at @pa, and mapped at level @level.
918 *
919 * The granule is populated before it is made a table,
920 * hence, don't use s2tte_write for access.
921 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000922void s2tt_init_assigned_destroyed(const struct s2tt_context *s2_ctx,
923 unsigned long *s2tt, unsigned long pa,
924 long level)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100925{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000926 assert(s2tt != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100927 assert(level >= S2TT_MIN_BLOCK_LEVEL);
928 assert(level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000929 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100930
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100931 const unsigned long map_size = s2tte_map_size(level);
932
933 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000934 s2tt[i] = s2tte_create_assigned_destroyed(s2_ctx, pa, level);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100935 pa += map_size;
936 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000937 dsb(ish);
938}
939
Soby Mathewb4c6df42022-11-09 11:13:29 +0000940/*
941 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
942 * contiguous memory block starting at @pa, and mapped at level @level.
943 *
944 * The granule is populated before it is made a table,
945 * hence, don't use s2tte_write for access.
946 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000947void s2tt_init_assigned_empty(const struct s2tt_context *s2_ctx,
948 unsigned long *s2tt, unsigned long pa,
949 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000950{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100951 assert(level >= S2TT_MIN_BLOCK_LEVEL);
952 assert(level <= S2TT_PAGE_LEVEL);
953 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000954 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100955
Soby Mathewb4c6df42022-11-09 11:13:29 +0000956 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000957
AlexeiFedorov3a739332023-04-13 13:54:04 +0100958 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000959 s2tt[i] = s2tte_create_assigned_empty(s2_ctx, pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000960 pa += map_size;
961 }
962 dsb(ish);
963}
964
965/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100966 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000967 * contiguous memory block starting at @pa, and mapped at level @level.
968 *
969 * The granule is populated before it is made a table,
970 * hence, don't use s2tte_write for access.
971 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000972void s2tt_init_assigned_ram(const struct s2tt_context *s2_ctx,
973 unsigned long *s2tt, unsigned long pa,
974 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000975{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100976 assert(level >= S2TT_MIN_BLOCK_LEVEL);
977 assert(level <= S2TT_PAGE_LEVEL);
978 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000979 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100980
Soby Mathewb4c6df42022-11-09 11:13:29 +0000981 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000982
AlexeiFedorov3a739332023-04-13 13:54:04 +0100983 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000984 s2tt[i] = s2tte_create_assigned_ram(s2_ctx, pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000985 pa += map_size;
986 }
987 dsb(ish);
988}
989
990/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100991 * Populates @s2tt with NS attributes @attrs that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000992 * contiguous memory block starting at @pa, and mapped at level @level.
993 *
994 * The granule is populated before it is made a table,
995 * hence, don't use s2tte_write for access.
996 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000997void s2tt_init_assigned_ns(const struct s2tt_context *s2_ctx,
998 unsigned long *s2tt, unsigned long attrs,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100999 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001000{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001001 assert(level >= S2TT_MIN_BLOCK_LEVEL);
1002 assert(level <= S2TT_PAGE_LEVEL);
1003 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001004 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001005
Soby Mathewb4c6df42022-11-09 11:13:29 +00001006 const unsigned long map_size = s2tte_map_size(level);
Soby Mathew217748d2024-10-02 11:02:19 +01001007
1008 attrs &= S2TTE_NS_ATTR_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001009
AlexeiFedorov3a739332023-04-13 13:54:04 +01001010 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001011 s2tt[i] = s2tte_create_assigned_ns(s2_ctx,
Soby Mathew217748d2024-10-02 11:02:19 +01001012 attrs | pa_to_s2tte(pa, s2_ctx->enable_lpa2),
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001013 level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001014 pa += map_size;
1015 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001016
Soby Mathewb4c6df42022-11-09 11:13:29 +00001017 dsb(ish);
1018}
1019
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001020/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001021 * Returns true if s2tte is a live RTTE entry. i.e.,
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001022 * HIPAS is ASSIGNED.
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001023 *
1024 * NOTE: For now, only the RTTE with PA are live.
1025 * This could change with EXPORT/IMPORT support.
1026 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001027static bool s2tte_is_live(const struct s2tt_context *s2_ctx,
1028 unsigned long s2tte, long level)
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001029{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001030 return s2tte_has_pa(s2_ctx, s2tte, level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001031}
1032
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001033/* Returns physical address of a S2TTE */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001034unsigned long s2tte_pa(const struct s2tt_context *s2_ctx, unsigned long s2tte,
1035 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001036{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001037 bool lpa2;
1038 unsigned long pa;
1039 __unused long min_starting_level;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001040
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001041 assert(s2_ctx != NULL);
1042
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +01001043 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001044 min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1045 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1046 assert(level >= min_starting_level);
1047 assert(level <= S2TT_PAGE_LEVEL);
1048 assert(s2tte_has_pa(s2_ctx, s2tte, level));
1049
1050 lpa2 = s2_ctx->enable_lpa2;
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001051
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001052 if (s2tte_is_table(s2_ctx, s2tte, level)) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001053 pa = table_entry_to_phys(s2tte, lpa2);
1054 } else {
1055 pa = s2tte_to_pa(s2tte, level, lpa2);
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001056 }
1057
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001058 return pa;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001059}
1060
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001061bool s2tte_is_addr_lvl_aligned(const struct s2tt_context *s2_ctx,
1062 unsigned long addr, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001063{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001064 assert(s2_ctx != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001065
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +01001066 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001067 __unused long min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1068 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1069 unsigned long levels = (unsigned long)(S2TT_PAGE_LEVEL - level);
1070 unsigned long lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
1071 unsigned long s2tte_oa_bits = (s2_ctx->enable_lpa2 == true) ?
1072 S2TTE_OA_BITS_LPA2 : S2TTE_OA_BITS;
1073
1074 assert(level <= S2TT_PAGE_LEVEL);
1075 assert(level >= min_starting_level);
1076
1077 return (addr == (addr & BIT_MASK_ULL((s2tte_oa_bits - 1U), lsb)));
Soby Mathewb4c6df42022-11-09 11:13:29 +00001078}
1079
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001080typedef bool (*s2tte_type_checker)(const struct s2tt_context *s2_ctx,
1081 unsigned long s2tte);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001082
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001083static bool table_is_uniform_block(const struct s2tt_context *s2_ctx,
1084 unsigned long *table,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001085 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001086{
AlexeiFedorov377d81f2023-04-14 16:29:12 +01001087 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
1088 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001089
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001090 if (!s2tte_is_x(s2_ctx, s2tte)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001091 return false;
1092 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001093 }
1094
1095 return true;
1096}
1097
1098/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001099 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001100 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001101bool s2tt_is_unassigned_empty_block(const struct s2tt_context *s2_ctx,
1102 unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001103{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001104 assert(table != NULL);
1105
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001106 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001107}
1108
1109/*
1110 * Returns true if all s2ttes in @table are unassigned_ram.
1111 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001112bool s2tt_is_unassigned_ram_block(const struct s2tt_context *s2_ctx,
1113 unsigned long *table)
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001114{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001115 assert(table != NULL);
1116
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001117 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001118}
1119
1120/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001121 * Returns true if all s2ttes in @table are unassigned_ns
1122 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001123bool s2tt_is_unassigned_ns_block(const struct s2tt_context *s2_ctx,
1124 unsigned long *table)
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001125{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001126 assert(table != NULL);
1127
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001128 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001129}
1130
1131/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001132 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +00001133 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001134bool s2tt_is_unassigned_destroyed_block(const struct s2tt_context *s2_ctx,
1135 unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001136{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001137 assert(table != NULL);
1138
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001139 return table_is_uniform_block(s2_ctx, table,
1140 s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001141}
1142
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001143typedef bool (*s2tte_type_level_checker)(const struct s2tt_context *s2_ctx,
1144 unsigned long s2tte, long level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001145
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001146static bool table_maps_block(const struct s2tt_context *s2_ctx,
1147 unsigned long *table,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001148 long level,
1149 s2tte_type_level_checker s2tte_is_x,
1150 bool check_ns_attrs)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001151{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001152 assert(table != NULL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001153 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001154
Soby Mathew217748d2024-10-02 11:02:19 +01001155 unsigned long base_pa;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001156 unsigned long map_size = s2tte_map_size(level);
1157 unsigned long s2tte = s2tte_read(&table[0]);
Javier Almansa Sobrino8865ec32024-04-18 10:50:03 +01001158 unsigned long s2tt_ns_attrs;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001159 unsigned int i;
1160
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +01001161 if (s2_ctx->enable_lpa2 == true) {
1162 assert(level >= S2TT_MIN_STARTING_LEVEL_LPA2);
1163 } else {
1164 assert(level >= S2TT_MIN_STARTING_LEVEL);
1165 }
1166
1167 assert(level <= S2TT_PAGE_LEVEL);
1168
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001169 if (!s2tte_is_x(s2_ctx, s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001170 return false;
1171 }
1172
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001173 base_pa = s2tte_pa(s2_ctx, s2tte, level);
1174 if (!s2tte_is_addr_lvl_aligned(s2_ctx, base_pa, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001175 return false;
1176 }
1177
Soby Mathew217748d2024-10-02 11:02:19 +01001178 s2tt_ns_attrs = s2tte & S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001179
Soby Mathewb4c6df42022-11-09 11:13:29 +00001180 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
1181 unsigned long expected_pa = base_pa + (i * map_size);
1182
1183 s2tte = s2tte_read(&table[i]);
1184
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001185 if (!s2tte_is_x(s2_ctx, s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001186 return false;
1187 }
1188
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001189 if (s2tte_pa(s2_ctx, s2tte, level) != expected_pa) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001190 return false;
1191 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001192
1193 if (check_ns_attrs) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001194 unsigned long ns_attrs =
Soby Mathew217748d2024-10-02 11:02:19 +01001195 s2tte & S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001196
1197 /*
1198 * We match all the attributes in the S2TTE
1199 * except for the AF bit.
1200 */
Javier Almansa Sobrino8865ec32024-04-18 10:50:03 +01001201 if (s2tt_ns_attrs != ns_attrs) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001202 return false;
1203 }
1204 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001205 }
1206
1207 return true;
1208}
1209
1210/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001211 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +00001212 * and refer to a contiguous block of granules aligned to @level - 1.
1213 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001214bool s2tt_maps_assigned_empty_block(const struct s2tt_context *s2_ctx,
1215 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001216{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001217 return table_maps_block(s2_ctx, table, level,
1218 s2tte_is_assigned_empty, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001219}
1220
1221/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001222 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001223 * refer to a contiguous block of granules aligned to @level - 1.
1224 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001225bool s2tt_maps_assigned_ram_block(const struct s2tt_context *s2_ctx,
1226 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001227{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001228 return table_maps_block(s2_ctx, table, level,
1229 s2tte_is_assigned_ram, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001230}
1231
1232/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001233 * Returns true if
1234 * - all s2ttes in @table are assigned_ns s2ttes and
1235 * - they refer to a contiguous block of granules aligned to @level - 1 and
1236 * - all the s2tte attributes in @table controlled by the host are identical
AlexeiFedorov3a739332023-04-13 13:54:04 +01001237 *
1238 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001239 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001240bool s2tt_maps_assigned_ns_block(const struct s2tt_context *s2_ctx,
1241 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001242{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001243 return table_maps_block(s2_ctx, table, level,
1244 s2tte_is_assigned_ns, true);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001245}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001246
1247/*
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001248 * Returns true if all s2ttes are assigned_destroyed and
1249 * refer to a contiguous block of granules aligned to @level - 1.
1250 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001251bool s2tt_maps_assigned_destroyed_block(const struct s2tt_context *s2_ctx,
1252 unsigned long *table, long level)
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001253{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001254 return table_maps_block(s2_ctx, table, level,
1255 s2tte_is_assigned_destroyed, false);
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001256}
1257
1258/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001259 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001260 * skip the non-live entries (i.e., HIPAS=UNASSIGNED).
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001261 * In other words, the scanning stops when a live RTTE is encountered or we
1262 * reach the end of this RTT.
1263 *
1264 * For now an RTTE can be considered non-live if it doesn't have a PA.
1265 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1266 * in the RTTE.
1267 *
1268 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1269 * with RMI_ERROR_RTT).
1270 *
1271 * Returns:
1272 * - If the entry @wi.index is live, returns @addr.
1273 * - If none of the entries in the @s2tt are "live", returns the address of the
1274 * first entry in the next table.
1275 * - Otherwise, the address of the first live entry in @s2tt
1276 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001277unsigned long s2tt_skip_non_live_entries(const struct s2tt_context *s2_ctx,
1278 unsigned long addr,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001279 unsigned long *table,
1280 const struct s2tt_walk *wi)
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001281{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001282 assert(table != NULL);
1283 assert(wi != NULL);
1284 assert(wi->index <= S2TTES_PER_S2TT);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001285 assert(wi->last_level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001286 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001287
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001288 unsigned long i, index = wi->index;
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001289 long level = wi->last_level;
1290 unsigned long map_size;
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +01001291
1292 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001293 __unused long min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1294 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1295
1296 assert(wi->last_level >= min_starting_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001297
1298 /*
1299 * If the entry for the map_addr is live,
1300 * return @addr.
1301 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001302 if (s2tte_is_live(s2_ctx, s2tte_read(&table[index]), level)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001303 return addr;
1304 }
1305
1306 /*
1307 * Align the address DOWN to the map_size, as expected for the @level,
1308 * so that we can compute the correct address by using the index.
1309 */
1310 map_size = s2tte_map_size(level);
1311 addr &= ~(map_size - 1UL);
1312
1313 /* Skip the "index" */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001314 for (i = index + 1UL; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001315 unsigned long s2tte = s2tte_read(&table[i]);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001316
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001317 if (s2tte_is_live(s2_ctx, s2tte, level)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001318 break;
1319 }
1320 }
1321
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001322 return (addr + ((i - index) * map_size));
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001323}