blob: dd611b38bcd2fdae21cb53b0c2ac5ca534e8d8fa [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/*
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000116 * Returns true if s2tte has 'output address' field, namely, if it is one of:
117 * - assigned_empty
118 * - assigned_ram
119 * - assigned_ns
120 * - assigned_destroyed
121 * - table
122 */
123static bool s2tte_has_pa(const struct s2tt_context *s2_ctx,
124 unsigned long s2tte, long level)
125{
126 unsigned long desc_type = s2tte & S2TT_DESC_TYPE_MASK;
127
128 return ((desc_type != S2TTE_INVALID) || /* block, page or table */
129 s2tte_is_assigned_empty(s2_ctx, s2tte, level) ||
130 s2tte_is_assigned_destroyed(s2_ctx, s2tte, level));
131}
132
133/*
134 * Creates a TTE containing only the PA.
135 * This function expects 'pa' to be aligned and bounded.
136 */
137static unsigned long pa_to_s2tte(unsigned long pa, bool lpa2)
138{
139 unsigned long tte = pa;
140
141 if (lpa2 == true) {
142 tte &= ~MASK(LPA2_OA_51_50);
143 tte |= INPLACE(LPA2_S2TTE_51_50, EXTRACT(LPA2_OA_51_50, pa));
144 }
145
146 return tte;
147}
148
149/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000150 * Invalidate S2 TLB entries with "addr" IPA.
151 * Call this function after:
152 * 1. A L3 page desc has been removed.
153 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000154void s2tt_invalidate_page(const struct s2tt_context *s2_ctx, unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000155{
156 stage2_tlbi_ipa(s2_ctx, addr, GRANULE_SIZE);
157}
158
159/*
160 * Invalidate S2 TLB entries with "addr" IPA.
161 * Call this function after:
162 * 1. A L2 block desc has been removed, or
163 * 2a. A L2 table desc has been removed, where
164 * 2b. All S2TTEs in L3 table that the L2 table desc was pointed to were invalid.
165 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000166void s2tt_invalidate_block(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 * 1a. A L2 table desc has been removed, where
175 * 1b. Some S2TTEs in the table that the L2 table desc was pointed to were valid.
176 */
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000177void s2tt_invalidate_pages_in_block(const struct s2tt_context *s2_ctx,
178 unsigned long addr)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000179{
180 stage2_tlbi_ipa(s2_ctx, addr, BLOCK_L2_SIZE);
181}
182
183/*
184 * Return the index of the entry describing @addr in the translation table at
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000185 * level @level. This only works for non-concatenated page tables, so should
Soby Mathewb4c6df42022-11-09 11:13:29 +0000186 * not be called to get the index for the starting level.
187 *
188 * See the library pseudocode
189 * aarch64/translation/vmsa_addrcalc/AArch64.TTEntryAddress on which this is
190 * modeled.
191 */
192static unsigned long s2_addr_to_idx(unsigned long addr, long level)
193{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100194 unsigned int levels, lsb;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000195 unsigned int s2tte_stride = (level < S2TT_MIN_STARTING_LEVEL) ?
196 S2TTE_STRIDE_LM1 : S2TTE_STRIDE;
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100197
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100198 levels = (unsigned int)(S2TT_PAGE_LEVEL - level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100199 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000200
201 addr >>= lsb;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000202 addr &= (1UL << s2tte_stride) - 1UL;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000203 return addr;
204}
205
206/*
207 * Return the index of the entry describing @addr in the translation table
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000208 * starting level. This may return an index >= S2TTES_PER_S2TT when the
Soby Mathewb4c6df42022-11-09 11:13:29 +0000209 * combination of @start_level and @ipa_bits implies concatenated
210 * stage 2 tables.
211 *
212 * See the library pseudocode
213 * aarch64/translation/vmsa_addrcalc/AArch64.S2SLTTEntryAddress on which
214 * this is modeled.
215 */
216static unsigned long s2_sl_addr_to_idx(unsigned long addr, int start_level,
217 unsigned long ipa_bits)
218{
AlexeiFedorovbb1f1c82023-08-25 10:44:49 +0100219 unsigned int levels, lsb;
220
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100221 levels = (unsigned int)(S2TT_PAGE_LEVEL - start_level);
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100222 lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000223
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000224 addr &= ((1UL << ipa_bits) - 1UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000225 addr >>= lsb;
226 return addr;
227}
228
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000229static bool entry_is_table(unsigned long entry)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000230{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100231 return ((entry & S2TT_DESC_TYPE_MASK) == S2TTE_L012_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000232}
233
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000234static unsigned long table_get_entry(const struct s2tt_context *s2_ctx,
235 struct granule *g_tbl,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100236 unsigned long idx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000237{
238 unsigned long *table, entry;
239
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000240 (void)s2_ctx;
241
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000242 table = buffer_granule_map(g_tbl, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100243 assert(table != NULL);
244
Soby Mathewb4c6df42022-11-09 11:13:29 +0000245 entry = s2tte_read(&table[idx]);
246 buffer_unmap(table);
247
248 return entry;
249}
250
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000251#define table_entry_to_phys(tte, lpa2) \
252 s2tte_to_pa(tte, S2TT_PAGE_LEVEL, lpa2)
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100253
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000254static struct granule *find_next_level_idx(const struct s2tt_context *s2_ctx,
255 struct granule *g_tbl,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100256 unsigned long idx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000257{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000258 assert(s2_ctx != NULL);
259
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000260 const unsigned long entry = table_get_entry(s2_ctx, g_tbl, idx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000261
262 if (!entry_is_table(entry)) {
263 return NULL;
264 }
265
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000266 return addr_to_granule(table_entry_to_phys(entry, s2_ctx->enable_lpa2));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000267}
268
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000269static struct granule *find_lock_next_level(const struct s2tt_context *s2_ctx,
270 struct granule *g_tbl,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100271 unsigned long map_addr,
272 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000273{
274 const unsigned long idx = s2_addr_to_idx(map_addr, level);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000275 struct granule *g = find_next_level_idx(s2_ctx, g_tbl, idx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000276
277 if (g != NULL) {
278 granule_lock(g, GRANULE_STATE_RTT);
279 }
280
281 return g;
282}
283
284/*
285 * Walk an RTT until level @level using @map_addr.
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000286 * @g_root is the root (level 0/-1) table and must be locked before the call.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000287 * @start_level is the initial lookup level used for the stage 2 translation
288 * tables which may depend on the configuration of the realm, factoring in the
289 * IPA size of the realm and the desired starting level (within the limits
290 * defined by the Armv8 VMSA including options for stage 2 table concatenation).
291 * The function uses hand-over-hand locking to avoid race conditions and allow
292 * concurrent access to RTT tree which is not part of the current walk; when a
293 * next level table is reached it is locked before releasing previously locked
294 * table.
295 * The walk stops when either:
296 * - The entry found is a leaf entry (not an RTT Table entry), or
297 * - Level @level is reached.
298 *
299 * On return:
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100300 * - s2tt_walk::last_level is the last level that has been reached by the walk.
301 * - s2tt_walk.g_llt points to the TABLE granule at level @s2tt_walk::level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000302 * The granule is locked.
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000303 * - s2tt_walk::index is the entry index at s2tt_walk.g_llt for @map_addr.i
304 *
305 * NOTE: This function expects that the root table on the s2 context is
306 * already locked.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000307 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000308void s2tt_walk_lock_unlock(const struct s2tt_context *s2_ctx,
309 unsigned long map_addr,
310 long level,
311 struct s2tt_walk *wi)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000312{
Aliyha Ajmal7f9ee6e2024-10-10 10:44:17 +0100313 /* coverity[misra_c_2012_rule_11_9_violation:SUPRESS] */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000314 struct granule *g_tbls[NR_RTT_LEVELS_LPA2] = { (struct granule *)NULL };
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000315 struct granule *g_root;
316 unsigned long sl_idx, ipa_bits;
317 int i, start_level, last_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000318
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000319 assert(s2_ctx != NULL);
320
321 start_level = s2_ctx->s2_starting_level;
322 ipa_bits = s2_ctx->ipa_bits;
323
Soby Mathewb4c6df42022-11-09 11:13:29 +0000324 assert(level >= start_level);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100325 assert(level <= S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000326 assert(map_addr < (1UL << ipa_bits));
327 assert(wi != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000328
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100329 if (s2_ctx->enable_lpa2 == true) {
330 assert(ipa_bits <= S2TTE_OA_BITS_LPA2);
331 } else {
332 assert(ipa_bits <= S2TTE_OA_BITS);
333 }
334
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000335 g_root = s2_ctx->g_rtt;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000336
337 /* Handle concatenated starting level (SL) tables */
338 sl_idx = s2_sl_addr_to_idx(map_addr, start_level, ipa_bits);
339 if (sl_idx >= S2TTES_PER_S2TT) {
AlexeiFedorov4faab852023-08-30 15:06:49 +0100340 unsigned int tt_num = (unsigned int)(sl_idx >> S2TTE_STRIDE);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100341 struct granule *g_concat_root;
342
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100343 assert(tt_num < s2_ctx->num_root_rtts);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100344
345 g_concat_root = (struct granule *)((uintptr_t)g_root +
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000346 (tt_num * sizeof(struct granule)));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000347
348 granule_lock(g_concat_root, GRANULE_STATE_RTT);
349 granule_unlock(g_root);
350 g_root = g_concat_root;
351 }
352
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000353 /* 'start_level' can be '-1', so add 1 when used as an index */
354 g_tbls[start_level + 1] = g_root;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000355 for (i = start_level; i < level; i++) {
356 /*
357 * Lock next RTT level. Correct locking order is guaranteed
358 * because reference is obtained from a locked granule
359 * (previous level). Also, hand-over-hand locking/unlocking is
360 * used to avoid race conditions.
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000361 *
362 * Note that as 'start_level' can be -1, we add '1' to the
363 * index 'i' to compensate for the negative value when we
364 * use it to index then 'g_tbls' list.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000365 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000366 g_tbls[i + 1 + 1] = find_lock_next_level(s2_ctx, g_tbls[i + 1],
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000367 map_addr, i);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000368 if (g_tbls[i + 1 + 1] == NULL) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000369 last_level = i;
370 goto out;
371 }
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000372 granule_unlock(g_tbls[i + 1]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000373 }
374
AlexeiFedorov4faab852023-08-30 15:06:49 +0100375 last_level = (int)level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000376out:
377 wi->last_level = last_level;
AlexeiFedorove956db32024-04-04 14:36:21 +0100378 /* coverity[deref_overflow:SUPPRESS] */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000379 wi->g_llt = g_tbls[last_level + 1];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000380 wi->index = s2_addr_to_idx(map_addr, last_level);
381}
382
383/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100384 * Creates an unassigned_empty s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000385 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000386unsigned long s2tte_create_unassigned_empty(const struct s2tt_context *s2_ctx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000387{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000388 (void)s2_ctx;
389
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100390 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100391}
392
393/*
394 * Creates an unassigned_ram s2tte.
395 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000396unsigned long s2tte_create_unassigned_ram(const struct s2tt_context *s2_ctx)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100397{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000398 (void)s2_ctx;
399
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100400 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000401}
402
403/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100404 * Creates an unassigned_destroyed s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000405 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000406unsigned long s2tte_create_unassigned_destroyed(const struct s2tt_context *s2_ctx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000407{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000408 (void)s2_ctx;
409
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100410 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
411}
412
413/*
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100414 * Creates an unassigned_ns s2tte.
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100415 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000416unsigned long s2tte_create_unassigned_ns(const struct s2tt_context *s2_ctx)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100417{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000418 (void)s2_ctx;
419
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100420 return (S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000421}
422
423/*
424 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100425 * RIPAS=@s2tte_ripas, at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000426 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000427static unsigned long s2tte_create_assigned(const struct s2tt_context *s2_ctx,
428 unsigned long pa, long level,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100429 unsigned long s2tte_ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000430{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100431 assert(level >= S2TT_MIN_BLOCK_LEVEL);
432 assert(level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100433 assert(EXTRACT(S2TTE_INVALID_RIPAS, s2tte_ripas)
434 <= EXTRACT(S2TTE_INVALID_RIPAS, S2TTE_INVALID_RIPAS_DESTROYED));
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000435 assert(s2_ctx != NULL);
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100436 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000437
438 unsigned long tte = pa_to_s2tte(pa, s2_ctx->enable_lpa2);
439 unsigned long s2tte_page, s2tte_block;
440
441 if (s2_ctx->enable_lpa2 == true) {
442 s2tte_page = S2TTE_PAGE_LPA2;
443 s2tte_block = S2TTE_BLOCK_LPA2;
444 } else {
445 s2tte_page = S2TTE_PAGE;
446 s2tte_block = S2TTE_BLOCK;
447 }
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100448
449 if (s2tte_ripas == S2TTE_INVALID_RIPAS_RAM) {
450 if (level == S2TT_PAGE_LEVEL) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000451 return (tte | s2tte_page);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100452 }
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000453 return (tte | s2tte_block);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100454 }
455
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000456 return (tte | S2TTE_INVALID_HIPAS_ASSIGNED | s2tte_ripas);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100457}
458
459/*
460 * Creates and invalid s2tte with output address @pa, HIPAS=ASSIGNED and
461 * RIPAS=DESTROYED at level @level.
462 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000463unsigned long s2tte_create_assigned_destroyed(const struct s2tt_context *s2_ctx,
464 unsigned long pa, long level)
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100465{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000466 return s2tte_create_assigned(s2_ctx, pa, level,
467 S2TTE_INVALID_RIPAS_DESTROYED);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100468}
469
470/*
471 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
472 * RIPAS=EMPTY at level @level.
473 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000474unsigned long s2tte_create_assigned_empty(const struct s2tt_context *s2_ctx,
475 unsigned long pa, long level)
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100476{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000477 return s2tte_create_assigned(s2_ctx, pa, level,
478 S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000479}
480
481/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100482 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000483 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000484unsigned long s2tte_create_assigned_ram(const struct s2tt_context *s2_ctx,
485 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000486{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000487 return s2tte_create_assigned(s2_ctx, pa, level,
488 S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000489}
490
491/*
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100492 * Creates an assigned s2tte with output address @pa and the same
493 * RIPAS as passed on @s2tte.
494 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000495unsigned long s2tte_create_assigned_unchanged(const struct s2tt_context *s2_ctx,
496 unsigned long s2tte,
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100497 unsigned long pa,
498 long level)
499{
500 unsigned long current_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
501
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000502 return s2tte_create_assigned(s2_ctx, pa, level, current_ripas);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000503}
504
505/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100506 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000507 *
508 * The following S2 TTE fields are provided through @s2tte argument:
509 * - The physical address
510 * - MemAttr
511 * - S2AP
Soby Mathewb4c6df42022-11-09 11:13:29 +0000512 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000513unsigned long s2tte_create_assigned_ns(const struct s2tt_context *s2_ctx,
514 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000515{
Soby Mathew217748d2024-10-02 11:02:19 +0100516 assert(s2_ctx != NULL);
517
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000518 /*
Soby Mathew217748d2024-10-02 11:02:19 +0100519 * We just mask out the DESC_TYPE below. We assume rest of the
520 * bits have been setup properly by the caller.
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000521 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100522 unsigned long new_s2tte = s2tte & ~S2TT_DESC_TYPE_MASK;
Soby Mathew217748d2024-10-02 11:02:19 +0100523 bool lpa2 = s2_ctx->enable_lpa2;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000524
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100525 assert(level >= S2TT_MIN_BLOCK_LEVEL);
526 assert(level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100527
Soby Mathew217748d2024-10-02 11:02:19 +0100528 /* The Shareability bits need to be added if FEAT_LPA2 is not enabled */
529 if (!lpa2) {
530 new_s2tte |= S2TTE_SH_IS;
531 }
532
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100533 if (level == S2TT_PAGE_LEVEL) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100534 return (new_s2tte | S2TTE_PAGE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000535 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100536 return (new_s2tte | S2TTE_BLOCK_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000537}
538
539/*
540 * Validate the portion of NS S2TTE that is provided by the host.
541 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000542bool host_ns_s2tte_is_valid(const struct s2tt_context *s2_ctx,
543 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000544{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000545 bool lpa2;
546 unsigned long mask;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100547
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000548 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100549 assert(level >= S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000550
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000551 lpa2 = s2_ctx->enable_lpa2;
552
Soby Mathew217748d2024-10-02 11:02:19 +0100553 mask = s2tte_lvl_mask(level, lpa2) | S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000554
Soby Mathewb4c6df42022-11-09 11:13:29 +0000555 /*
556 * Test that all fields that are not controlled by the host are zero
557 * and that the output address is correctly aligned. Note that
558 * the host is permitted to map any physical address outside PAR.
Shruti Gupta3530a712024-09-12 10:50:21 +0100559 * Note that this also checks for the case when FEAT_LPA2 is disabled
560 * for the Realm, then the PA in `s2tte` must be <= 48 bits wide.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000561 */
562 if ((s2tte & ~mask) != 0UL) {
563 return false;
564 }
565
566 /*
567 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
568 */
569 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
570 return false;
571 }
572
573 /*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000574 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
575 */
576 return true;
577}
578
579/*
580 * Returns the portion of NS S2TTE that is set by the host.
581 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000582unsigned long host_ns_s2tte(const struct s2tt_context *s2_ctx,
583 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000584{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000585 assert(s2_ctx != NULL);
586
Soby Mathew217748d2024-10-02 11:02:19 +0100587 unsigned long mask = s2tte_lvl_mask(level, s2_ctx->enable_lpa2)
588 | S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000589
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100590 assert(level >= S2TT_MIN_BLOCK_LEVEL);
591
Soby Mathewb4c6df42022-11-09 11:13:29 +0000592 return (s2tte & mask);
593}
594
595/*
596 * Creates a table s2tte at level @level with output address @pa.
597 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000598unsigned long s2tte_create_table(const struct s2tt_context *s2_ctx,
599 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000600{
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +0100601 __unused long min_starting_level;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000602
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100603 (void)level;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000604
605 assert(s2_ctx != NULL);
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +0100606
607 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000608 min_starting_level = (s2_ctx->enable_lpa2 == true) ?
609 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100610
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100611 assert(level < S2TT_PAGE_LEVEL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000612 assert(level >= min_starting_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000613 assert(GRANULE_ALIGNED(pa));
614
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000615 return (pa_to_s2tte(pa, s2_ctx->enable_lpa2) | S2TTE_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000616}
617
618/*
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100619 * Returns true if s2tte has defined ripas value, namely if it is one of:
620 * - unassigned_empty
621 * - unassigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100622 * - unassigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100623 * - assigned_empty
624 * - assigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100625 * - assigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100626 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000627bool s2tte_has_ripas(const struct s2tt_context *s2_ctx,
628 unsigned long s2tte, long level)
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100629{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000630 return (((s2tte & S2TTE_NS) == 0UL) && !s2tte_is_table(s2_ctx,
631 s2tte, level));
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100632}
633
634/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000635 * Returns true if @s2tte has HIPAS=@hipas.
636 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100637static inline bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000638{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100639 unsigned long desc_type = s2tte & S2TT_DESC_TYPE_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000640 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
641
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100642 return ((desc_type == S2TTE_INVALID) && (invalid_desc_hipas == hipas));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000643}
644
645/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100646 * Returns true if @s2tte has HIPAS=UNASSIGNED and RIPAS=@ripas.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000647 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100648static inline bool s2tte_has_unassigned_ripas(unsigned long s2tte,
649 unsigned long ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000650{
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100651 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
652 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
653}
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100654
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100655/*
656 * Returns true if @s2tte has HIPAS=ASSIGNED and RIPAS=@ripas.
657 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100658static inline bool s2tte_has_assigned_ripas(unsigned long s2tte,
659 unsigned long ripas)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100660{
661 return (((s2tte & S2TTE_INVALID_RIPAS_MASK) == ripas) &&
662 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_ASSIGNED));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100663}
664
665/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100666 * Returns true if @s2tte has HIPAS=UNASSIGNED.
667 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000668bool s2tte_is_unassigned(const struct s2tt_context *s2_ctx, unsigned long s2tte)
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100669{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000670 (void)s2_ctx;
671
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100672 return s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED);
673}
674
675/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100676 * Returns true if @s2tte is an unassigned_empty.
677 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000678bool s2tte_is_unassigned_empty(const struct s2tt_context *s2_ctx,
679 unsigned long s2tte)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100680{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000681 (void)s2_ctx;
682
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100683 return (((s2tte & S2TTE_NS) == 0UL) &&
684 s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY));
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100685}
686
687/*
688 * Returns true if @s2tte is an unassigned_ram.
689 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000690bool s2tte_is_unassigned_ram(const struct s2tt_context *s2_ctx,
691 unsigned long s2tte)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100692{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000693 (void)s2_ctx;
694
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100695 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_RAM);
696}
697
698/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100699 * Returns true if @s2tte is unassigned_ns.
700 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000701bool s2tte_is_unassigned_ns(const struct s2tt_context *s2_ctx,
702 unsigned long s2tte)
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100703{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000704 (void)s2_ctx;
705
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100706 return (((s2tte & S2TTE_NS) != 0UL) &&
707 s2tte_has_hipas(s2tte, S2TTE_INVALID_HIPAS_UNASSIGNED));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000708}
709
710/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100711 * Returns true if @s2tte has RIPAS=DESTROYED.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000712 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000713bool s2tte_is_unassigned_destroyed(const struct s2tt_context *s2_ctx,
714 unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000715{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000716 (void)s2_ctx;
717
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100718 return s2tte_has_unassigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
719}
720
721/*
722 * Returns true if @s2tte is an assigned_destroyed.
723 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000724bool s2tte_is_assigned_destroyed(const struct s2tt_context *s2_ctx,
725 unsigned long s2tte, long level)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100726{
727 (void)level;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000728 (void)s2_ctx;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100729
730 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_DESTROYED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000731}
732
733/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100734 * Returns true if @s2tte is an assigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000735 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000736bool s2tte_is_assigned_empty(const struct s2tt_context *s2_ctx,
737 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000738{
739 (void)level;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000740 (void)s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000741
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100742 return s2tte_has_assigned_ripas(s2tte, S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000743}
744
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000745static bool s2tte_check(const struct s2tt_context *s2_ctx, unsigned long s2tte,
746 long level, unsigned long ns)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000747{
748 unsigned long desc_type;
749
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000750 (void)s2_ctx;
751
Soby Mathewb4c6df42022-11-09 11:13:29 +0000752 if ((s2tte & S2TTE_NS) != ns) {
753 return false;
754 }
755
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100756 desc_type = s2tte & S2TT_DESC_TYPE_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000757
Shruti Gupta3105c3f2024-02-26 14:06:11 +0000758 /* Only pages at L3 and valid blocks at L2 and L1 allowed */
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +0100759 if (level == S2TT_PAGE_LEVEL) {
760 return (desc_type == S2TTE_L3_PAGE);
761 }
762
763 if ((level >= S2TT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000764 return true;
765 }
766
767 return false;
768}
769
770/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100771 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000772 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000773bool s2tte_is_assigned_ram(const struct s2tt_context *s2_ctx,
774 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000775{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000776 return s2tte_check(s2_ctx, s2tte, level, 0UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000777}
778
779/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100780 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000781 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000782bool s2tte_is_assigned_ns(const struct s2tt_context *s2_ctx,
783 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000784{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000785 return s2tte_check(s2_ctx, s2tte, level, S2TTE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000786}
787
788/*
789 * Returns true if @s2tte is a table at level @level.
790 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000791bool s2tte_is_table(const struct s2tt_context *s2_ctx, unsigned long s2tte,
792 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000793{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000794 (void)s2_ctx;
795
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100796 return ((level < S2TT_PAGE_LEVEL) &&
797 ((s2tte & S2TT_DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000798}
799
800/*
801 * Returns RIPAS of @s2tte.
802 *
803 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100804 * The s2tte, if valid, should correspond to RIPAS_RAM.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000805 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000806enum ripas s2tte_get_ripas(const struct s2tt_context *s2_ctx, unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000807{
808 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
Javier Almansa Sobrinob802a0e2024-07-05 12:52:23 +0100809 unsigned long desc_type = s2tte & S2TT_DESC_TYPE_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000810
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000811 (void)s2_ctx;
812
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 */
Javier Almansa Sobrinob802a0e2024-07-05 12:52:23 +0100817 if (desc_type != S2TTE_INVALID) {
818 assert((desc_type == S2TTE_L012_BLOCK) ||
819 (desc_type == S2TTE_L3_PAGE));
820 return RIPAS_RAM;
821 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000822
Javier Almansa Sobrinob802a0e2024-07-05 12:52:23 +0100823 assert(EXTRACT(S2TTE_INVALID_HIPAS, s2tte) <= RMI_ASSIGNED);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100824
825 desc_ripas = desc_ripas >> S2TTE_INVALID_RIPAS_SHIFT;
826
827 assert(desc_ripas <= (unsigned int)RIPAS_DESTROYED);
828
829 return (enum ripas)desc_ripas;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000830}
831
832/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100833 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000834 *
835 * The granule is populated before it is made a table,
836 * hence, don't use s2tte_write for access.
837 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000838void s2tt_init_unassigned_empty(const struct s2tt_context *s2_ctx,
839 unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000840{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100841 assert(s2tt != NULL);
842
843 unsigned long s2tte =
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000844 s2tte_create_unassigned_empty(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100845
Soby Mathewb4c6df42022-11-09 11:13:29 +0000846 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100847 s2tt[i] = s2tte;
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100848 }
849
850 dsb(ish);
851}
852
853/*
854 * Populates @s2tt with unassigned_ram s2ttes.
855 *
856 * The granule is populated before it is made a table,
857 * hence, don't use s2tte_write for access.
858 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000859void s2tt_init_unassigned_ram(const struct s2tt_context *s2_ctx,
860 unsigned long *s2tt)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100861{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100862 assert(s2tt != NULL);
863
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000864 unsigned long s2tte = s2tte_create_unassigned_ram(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100865
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100866 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100867 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000868 }
869
870 dsb(ish);
871}
872
873/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100874 * Populates @s2tt with unassigned_ns s2ttes.
875 *
876 * The granule is populated before it is made a table,
877 * hence, don't use s2tte_write for access.
878 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000879void s2tt_init_unassigned_ns(const struct s2tt_context *s2_ctx,
880 unsigned long *s2tt)
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100881{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100882 assert(s2tt != NULL);
883
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000884 unsigned long s2tte = s2tte_create_unassigned_ns(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100885
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100886 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100887 s2tt[i] = s2tte;
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100888 }
889
890 dsb(ish);
891}
892
893/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000894 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
895 *
896 * The granule is populated before it is made a table,
897 * hence, don't use s2tte_write for access.
898 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000899void s2tt_init_unassigned_destroyed(const struct s2tt_context *s2_ctx,
900 unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000901{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100902 assert(s2tt != NULL);
903
904 unsigned long s2tte =
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000905 s2tte_create_unassigned_destroyed(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100906
Soby Mathewb4c6df42022-11-09 11:13:29 +0000907 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100908 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000909 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100910 dsb(ish);
911}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000912
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100913/*
914 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
915 * contiguous memory block starting at @pa, and mapped at level @level.
916 *
917 * The granule is populated before it is made a table,
918 * hence, don't use s2tte_write for access.
919 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000920void s2tt_init_assigned_destroyed(const struct s2tt_context *s2_ctx,
921 unsigned long *s2tt, unsigned long pa,
922 long level)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100923{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000924 assert(s2tt != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100925 assert(level >= S2TT_MIN_BLOCK_LEVEL);
926 assert(level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000927 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100928
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100929 const unsigned long map_size = s2tte_map_size(level);
930
931 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000932 s2tt[i] = s2tte_create_assigned_destroyed(s2_ctx, pa, level);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100933 pa += map_size;
934 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000935 dsb(ish);
936}
937
Soby Mathewb4c6df42022-11-09 11:13:29 +0000938/*
939 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
940 * contiguous memory block starting at @pa, and mapped at level @level.
941 *
942 * The granule is populated before it is made a table,
943 * hence, don't use s2tte_write for access.
944 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000945void s2tt_init_assigned_empty(const struct s2tt_context *s2_ctx,
946 unsigned long *s2tt, unsigned long pa,
947 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000948{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100949 assert(level >= S2TT_MIN_BLOCK_LEVEL);
950 assert(level <= S2TT_PAGE_LEVEL);
951 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000952 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100953
Soby Mathewb4c6df42022-11-09 11:13:29 +0000954 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000955
AlexeiFedorov3a739332023-04-13 13:54:04 +0100956 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000957 s2tt[i] = s2tte_create_assigned_empty(s2_ctx, pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000958 pa += map_size;
959 }
960 dsb(ish);
961}
962
963/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100964 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000965 * contiguous memory block starting at @pa, and mapped at level @level.
966 *
967 * The granule is populated before it is made a table,
968 * hence, don't use s2tte_write for access.
969 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000970void s2tt_init_assigned_ram(const struct s2tt_context *s2_ctx,
971 unsigned long *s2tt, unsigned long pa,
972 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000973{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100974 assert(level >= S2TT_MIN_BLOCK_LEVEL);
975 assert(level <= S2TT_PAGE_LEVEL);
976 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000977 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100978
Soby Mathewb4c6df42022-11-09 11:13:29 +0000979 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000980
AlexeiFedorov3a739332023-04-13 13:54:04 +0100981 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000982 s2tt[i] = s2tte_create_assigned_ram(s2_ctx, pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000983 pa += map_size;
984 }
985 dsb(ish);
986}
987
988/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100989 * Populates @s2tt with NS attributes @attrs that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000990 * contiguous memory block starting at @pa, and mapped at level @level.
991 *
992 * The granule is populated before it is made a table,
993 * hence, don't use s2tte_write for access.
994 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000995void s2tt_init_assigned_ns(const struct s2tt_context *s2_ctx,
996 unsigned long *s2tt, unsigned long attrs,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100997 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000998{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100999 assert(level >= S2TT_MIN_BLOCK_LEVEL);
1000 assert(level <= S2TT_PAGE_LEVEL);
1001 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001002 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001003
Soby Mathewb4c6df42022-11-09 11:13:29 +00001004 const unsigned long map_size = s2tte_map_size(level);
Soby Mathew217748d2024-10-02 11:02:19 +01001005
1006 attrs &= S2TTE_NS_ATTR_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001007
AlexeiFedorov3a739332023-04-13 13:54:04 +01001008 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001009 s2tt[i] = s2tte_create_assigned_ns(s2_ctx,
Soby Mathew217748d2024-10-02 11:02:19 +01001010 attrs | pa_to_s2tte(pa, s2_ctx->enable_lpa2),
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001011 level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001012 pa += map_size;
1013 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001014
Soby Mathewb4c6df42022-11-09 11:13:29 +00001015 dsb(ish);
1016}
1017
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001018/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001019 * Returns true if s2tte is a live RTTE entry. i.e.,
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001020 * HIPAS is ASSIGNED.
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001021 *
1022 * NOTE: For now, only the RTTE with PA are live.
1023 * This could change with EXPORT/IMPORT support.
1024 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001025static bool s2tte_is_live(const struct s2tt_context *s2_ctx,
1026 unsigned long s2tte, long level)
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001027{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001028 return s2tte_has_pa(s2_ctx, s2tte, level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001029}
1030
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001031/* Returns physical address of a S2TTE */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001032unsigned long s2tte_pa(const struct s2tt_context *s2_ctx, unsigned long s2tte,
1033 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001034{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001035 bool lpa2;
1036 unsigned long pa;
1037 __unused long min_starting_level;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001038
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001039 assert(s2_ctx != NULL);
1040
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +01001041 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001042 min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1043 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1044 assert(level >= min_starting_level);
1045 assert(level <= S2TT_PAGE_LEVEL);
1046 assert(s2tte_has_pa(s2_ctx, s2tte, level));
1047
1048 lpa2 = s2_ctx->enable_lpa2;
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001049
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001050 if (s2tte_is_table(s2_ctx, s2tte, level)) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001051 pa = table_entry_to_phys(s2tte, lpa2);
1052 } else {
1053 pa = s2tte_to_pa(s2tte, level, lpa2);
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001054 }
1055
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001056 return pa;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001057}
1058
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001059bool s2tte_is_addr_lvl_aligned(const struct s2tt_context *s2_ctx,
1060 unsigned long addr, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001061{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001062 assert(s2_ctx != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001063
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +01001064 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001065 __unused long min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1066 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1067 unsigned long levels = (unsigned long)(S2TT_PAGE_LEVEL - level);
1068 unsigned long lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
1069 unsigned long s2tte_oa_bits = (s2_ctx->enable_lpa2 == true) ?
1070 S2TTE_OA_BITS_LPA2 : S2TTE_OA_BITS;
1071
1072 assert(level <= S2TT_PAGE_LEVEL);
1073 assert(level >= min_starting_level);
1074
1075 return (addr == (addr & BIT_MASK_ULL((s2tte_oa_bits - 1U), lsb)));
Soby Mathewb4c6df42022-11-09 11:13:29 +00001076}
1077
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001078typedef bool (*s2tte_type_checker)(const struct s2tt_context *s2_ctx,
1079 unsigned long s2tte);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001080
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001081static bool table_is_uniform_block(const struct s2tt_context *s2_ctx,
1082 unsigned long *table,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001083 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001084{
AlexeiFedorov377d81f2023-04-14 16:29:12 +01001085 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
1086 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001087
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001088 if (!s2tte_is_x(s2_ctx, s2tte)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001089 return false;
1090 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001091 }
1092
1093 return true;
1094}
1095
1096/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001097 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001098 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001099bool s2tt_is_unassigned_empty_block(const struct s2tt_context *s2_ctx,
1100 unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001101{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001102 assert(table != NULL);
1103
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001104 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001105}
1106
1107/*
1108 * Returns true if all s2ttes in @table are unassigned_ram.
1109 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001110bool s2tt_is_unassigned_ram_block(const struct s2tt_context *s2_ctx,
1111 unsigned long *table)
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001112{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001113 assert(table != NULL);
1114
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001115 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001116}
1117
1118/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001119 * Returns true if all s2ttes in @table are unassigned_ns
1120 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001121bool s2tt_is_unassigned_ns_block(const struct s2tt_context *s2_ctx,
1122 unsigned long *table)
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001123{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001124 assert(table != NULL);
1125
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001126 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001127}
1128
1129/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001130 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +00001131 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001132bool s2tt_is_unassigned_destroyed_block(const struct s2tt_context *s2_ctx,
1133 unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001134{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001135 assert(table != NULL);
1136
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001137 return table_is_uniform_block(s2_ctx, table,
1138 s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001139}
1140
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001141typedef bool (*s2tte_type_level_checker)(const struct s2tt_context *s2_ctx,
1142 unsigned long s2tte, long level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001143
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001144static bool table_maps_block(const struct s2tt_context *s2_ctx,
1145 unsigned long *table,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001146 long level,
1147 s2tte_type_level_checker s2tte_is_x,
1148 bool check_ns_attrs)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001149{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001150 assert(table != NULL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001151 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001152
Soby Mathew217748d2024-10-02 11:02:19 +01001153 unsigned long base_pa;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001154 unsigned long map_size = s2tte_map_size(level);
1155 unsigned long s2tte = s2tte_read(&table[0]);
Javier Almansa Sobrino8865ec32024-04-18 10:50:03 +01001156 unsigned long s2tt_ns_attrs;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001157 unsigned int i;
1158
Javier Almansa Sobrino6e3b5522024-04-10 12:12:13 +01001159 if (s2_ctx->enable_lpa2 == true) {
1160 assert(level >= S2TT_MIN_STARTING_LEVEL_LPA2);
1161 } else {
1162 assert(level >= S2TT_MIN_STARTING_LEVEL);
1163 }
1164
1165 assert(level <= S2TT_PAGE_LEVEL);
1166
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001167 if (!s2tte_is_x(s2_ctx, s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001168 return false;
1169 }
1170
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001171 base_pa = s2tte_pa(s2_ctx, s2tte, level);
1172 if (!s2tte_is_addr_lvl_aligned(s2_ctx, base_pa, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001173 return false;
1174 }
1175
Soby Mathew217748d2024-10-02 11:02:19 +01001176 s2tt_ns_attrs = s2tte & S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001177
Soby Mathewb4c6df42022-11-09 11:13:29 +00001178 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
1179 unsigned long expected_pa = base_pa + (i * map_size);
1180
1181 s2tte = s2tte_read(&table[i]);
1182
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001183 if (!s2tte_is_x(s2_ctx, s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001184 return false;
1185 }
1186
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001187 if (s2tte_pa(s2_ctx, s2tte, level) != expected_pa) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001188 return false;
1189 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001190
1191 if (check_ns_attrs) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001192 unsigned long ns_attrs =
Soby Mathew217748d2024-10-02 11:02:19 +01001193 s2tte & S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001194
1195 /*
1196 * We match all the attributes in the S2TTE
1197 * except for the AF bit.
1198 */
Javier Almansa Sobrino8865ec32024-04-18 10:50:03 +01001199 if (s2tt_ns_attrs != ns_attrs) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001200 return false;
1201 }
1202 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001203 }
1204
1205 return true;
1206}
1207
1208/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001209 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +00001210 * and refer to a contiguous block of granules aligned to @level - 1.
1211 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001212bool s2tt_maps_assigned_empty_block(const struct s2tt_context *s2_ctx,
1213 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001214{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001215 return table_maps_block(s2_ctx, table, level,
1216 s2tte_is_assigned_empty, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001217}
1218
1219/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001220 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001221 * refer to a contiguous block of granules aligned to @level - 1.
1222 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001223bool s2tt_maps_assigned_ram_block(const struct s2tt_context *s2_ctx,
1224 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001225{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001226 return table_maps_block(s2_ctx, table, level,
1227 s2tte_is_assigned_ram, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001228}
1229
1230/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001231 * Returns true if
1232 * - all s2ttes in @table are assigned_ns s2ttes and
1233 * - they refer to a contiguous block of granules aligned to @level - 1 and
1234 * - all the s2tte attributes in @table controlled by the host are identical
AlexeiFedorov3a739332023-04-13 13:54:04 +01001235 *
1236 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001237 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001238bool s2tt_maps_assigned_ns_block(const struct s2tt_context *s2_ctx,
1239 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001240{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001241 return table_maps_block(s2_ctx, table, level,
1242 s2tte_is_assigned_ns, true);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001243}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001244
1245/*
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001246 * Returns true if all s2ttes are assigned_destroyed and
1247 * refer to a contiguous block of granules aligned to @level - 1.
1248 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001249bool s2tt_maps_assigned_destroyed_block(const struct s2tt_context *s2_ctx,
1250 unsigned long *table, long level)
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001251{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001252 return table_maps_block(s2_ctx, table, level,
1253 s2tte_is_assigned_destroyed, false);
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001254}
1255
1256/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001257 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001258 * skip the non-live entries (i.e., HIPAS=UNASSIGNED).
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001259 * In other words, the scanning stops when a live RTTE is encountered or we
1260 * reach the end of this RTT.
1261 *
1262 * For now an RTTE can be considered non-live if it doesn't have a PA.
1263 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1264 * in the RTTE.
1265 *
1266 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1267 * with RMI_ERROR_RTT).
1268 *
1269 * Returns:
1270 * - If the entry @wi.index is live, returns @addr.
1271 * - If none of the entries in the @s2tt are "live", returns the address of the
1272 * first entry in the next table.
1273 * - Otherwise, the address of the first live entry in @s2tt
1274 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001275unsigned long s2tt_skip_non_live_entries(const struct s2tt_context *s2_ctx,
1276 unsigned long addr,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001277 unsigned long *table,
1278 const struct s2tt_walk *wi)
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001279{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001280 assert(table != NULL);
1281 assert(wi != NULL);
1282 assert(wi->index <= S2TTES_PER_S2TT);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001283 assert(wi->last_level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001284 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001285
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001286 unsigned long i, index = wi->index;
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001287 long level = wi->last_level;
1288 unsigned long map_size;
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +01001289
1290 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001291 __unused long min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1292 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1293
1294 assert(wi->last_level >= min_starting_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001295
1296 /*
1297 * If the entry for the map_addr is live,
1298 * return @addr.
1299 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001300 if (s2tte_is_live(s2_ctx, s2tte_read(&table[index]), level)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001301 return addr;
1302 }
1303
1304 /*
1305 * Align the address DOWN to the map_size, as expected for the @level,
1306 * so that we can compute the correct address by using the index.
1307 */
1308 map_size = s2tte_map_size(level);
1309 addr &= ~(map_size - 1UL);
1310
1311 /* Skip the "index" */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001312 for (i = index + 1UL; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001313 unsigned long s2tte = s2tte_read(&table[i]);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001314
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001315 if (s2tte_is_live(s2_ctx, s2tte, level)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001316 break;
1317 }
1318 }
1319
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001320 return (addr + ((i - index) * map_size));
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001321}