blob: 61e6d6afe5f9071560e5a0c5a1e1ec614c23a2b6 [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{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000313 struct granule *g_tbls[NR_RTT_LEVELS_LPA2] = { (struct granule *)NULL };
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000314 struct granule *g_root;
315 unsigned long sl_idx, ipa_bits;
316 int i, start_level, last_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000317
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000318 assert(s2_ctx != NULL);
319
320 start_level = s2_ctx->s2_starting_level;
321 ipa_bits = s2_ctx->ipa_bits;
322
Soby Mathewb4c6df42022-11-09 11:13:29 +0000323 assert(level >= start_level);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100324 assert(level <= S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000325 assert(map_addr < (1UL << ipa_bits));
326 assert(wi != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000327
328 g_root = s2_ctx->g_rtt;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000329
330 /* Handle concatenated starting level (SL) tables */
331 sl_idx = s2_sl_addr_to_idx(map_addr, start_level, ipa_bits);
332 if (sl_idx >= S2TTES_PER_S2TT) {
AlexeiFedorov4faab852023-08-30 15:06:49 +0100333 unsigned int tt_num = (unsigned int)(sl_idx >> S2TTE_STRIDE);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100334 struct granule *g_concat_root;
335
336 assert(tt_num < S2TTE_MAX_CONCAT_TABLES);
337
338 g_concat_root = (struct granule *)((uintptr_t)g_root +
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000339 (tt_num * sizeof(struct granule)));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000340
341 granule_lock(g_concat_root, GRANULE_STATE_RTT);
342 granule_unlock(g_root);
343 g_root = g_concat_root;
344 }
345
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000346 /* 'start_level' can be '-1', so add 1 when used as an index */
347 g_tbls[start_level + 1] = g_root;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000348 for (i = start_level; i < level; i++) {
349 /*
350 * Lock next RTT level. Correct locking order is guaranteed
351 * because reference is obtained from a locked granule
352 * (previous level). Also, hand-over-hand locking/unlocking is
353 * used to avoid race conditions.
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000354 *
355 * Note that as 'start_level' can be -1, we add '1' to the
356 * index 'i' to compensate for the negative value when we
357 * use it to index then 'g_tbls' list.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000358 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000359 g_tbls[i + 1 + 1] = find_lock_next_level(s2_ctx, g_tbls[i + 1],
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000360 map_addr, i);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000361 if (g_tbls[i + 1 + 1] == NULL) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000362 last_level = i;
363 goto out;
364 }
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000365 granule_unlock(g_tbls[i + 1]);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000366 }
367
AlexeiFedorov4faab852023-08-30 15:06:49 +0100368 last_level = (int)level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000369out:
370 wi->last_level = last_level;
AlexeiFedorove956db32024-04-04 14:36:21 +0100371 /* coverity[deref_overflow:SUPPRESS] */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000372 wi->g_llt = g_tbls[last_level + 1];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000373 wi->index = s2_addr_to_idx(map_addr, last_level);
374}
375
376/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100377 * Creates an unassigned_empty s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000378 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000379unsigned long s2tte_create_unassigned_empty(const struct s2tt_context *s2_ctx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000380{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000381 (void)s2_ctx;
382
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100383 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_EMPTY);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100384}
385
386/*
387 * Creates an unassigned_ram s2tte.
388 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000389unsigned long s2tte_create_unassigned_ram(const struct s2tt_context *s2_ctx)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100390{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000391 (void)s2_ctx;
392
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100393 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000394}
395
396/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100397 * Creates an unassigned_destroyed s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000398 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000399unsigned long s2tte_create_unassigned_destroyed(const struct s2tt_context *s2_ctx)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000400{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000401 (void)s2_ctx;
402
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100403 return (S2TTE_INVALID_HIPAS_UNASSIGNED | S2TTE_INVALID_RIPAS_DESTROYED);
404}
405
406/*
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100407 * Creates an unassigned_ns s2tte.
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100408 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000409unsigned long s2tte_create_unassigned_ns(const struct s2tt_context *s2_ctx)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100410{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000411 (void)s2_ctx;
412
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100413 return (S2TTE_NS | S2TTE_INVALID_HIPAS_UNASSIGNED |
414 S2TTE_INVALID_UNPROTECTED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000415}
416
417/*
418 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100419 * RIPAS=@s2tte_ripas, at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000420 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000421static unsigned long s2tte_create_assigned(const struct s2tt_context *s2_ctx,
422 unsigned long pa, long level,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100423 unsigned long s2tte_ripas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000424{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100425 assert(level >= S2TT_MIN_BLOCK_LEVEL);
426 assert(level <= S2TT_PAGE_LEVEL);
427 assert(s2tte_ripas <= S2TTE_INVALID_RIPAS_DESTROYED);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000428 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000429 assert(s2_ctx != NULL);
430
431 unsigned long tte = pa_to_s2tte(pa, s2_ctx->enable_lpa2);
432 unsigned long s2tte_page, s2tte_block;
433
434 if (s2_ctx->enable_lpa2 == true) {
435 s2tte_page = S2TTE_PAGE_LPA2;
436 s2tte_block = S2TTE_BLOCK_LPA2;
437 } else {
438 s2tte_page = S2TTE_PAGE;
439 s2tte_block = S2TTE_BLOCK;
440 }
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100441
442 if (s2tte_ripas == S2TTE_INVALID_RIPAS_RAM) {
443 if (level == S2TT_PAGE_LEVEL) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000444 return (tte | s2tte_page);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100445 }
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000446 return (tte | s2tte_block);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100447 }
448
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000449 return (tte | S2TTE_INVALID_HIPAS_ASSIGNED | s2tte_ripas);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100450}
451
452/*
453 * Creates and invalid s2tte with output address @pa, HIPAS=ASSIGNED and
454 * RIPAS=DESTROYED at level @level.
455 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000456unsigned long s2tte_create_assigned_destroyed(const struct s2tt_context *s2_ctx,
457 unsigned long pa, long level)
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100458{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000459 return s2tte_create_assigned(s2_ctx, pa, level,
460 S2TTE_INVALID_RIPAS_DESTROYED);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100461}
462
463/*
464 * Creates an invalid s2tte with output address @pa, HIPAS=ASSIGNED and
465 * RIPAS=EMPTY at level @level.
466 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000467unsigned long s2tte_create_assigned_empty(const struct s2tt_context *s2_ctx,
468 unsigned long pa, long level)
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100469{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000470 return s2tte_create_assigned(s2_ctx, pa, level,
471 S2TTE_INVALID_RIPAS_EMPTY);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000472}
473
474/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100475 * Creates an assigned_ram s2tte with output address @pa.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000476 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000477unsigned long s2tte_create_assigned_ram(const struct s2tt_context *s2_ctx,
478 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000479{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000480 return s2tte_create_assigned(s2_ctx, pa, level,
481 S2TTE_INVALID_RIPAS_RAM);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000482}
483
484/*
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100485 * Creates an assigned s2tte with output address @pa and the same
486 * RIPAS as passed on @s2tte.
487 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000488unsigned long s2tte_create_assigned_unchanged(const struct s2tt_context *s2_ctx,
489 unsigned long s2tte,
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +0100490 unsigned long pa,
491 long level)
492{
493 unsigned long current_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
494
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000495 return s2tte_create_assigned(s2_ctx, pa, level, current_ripas);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000496}
497
498/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100499 * Creates an assigned_ns s2tte at level @level.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000500 *
501 * The following S2 TTE fields are provided through @s2tte argument:
502 * - The physical address
503 * - MemAttr
504 * - S2AP
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000505 * - Shareability (when FEAT_LPA2 is disabled)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000506 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000507unsigned long s2tte_create_assigned_ns(const struct s2tt_context *s2_ctx,
508 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000509{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000510 /*
511 * We just mask out the DESC_TYPE below. The Shareability bits
512 * without FEAT_LPA2 are at the same position as OA bits [51:50]
513 * with FEAT_LPA2 enabled, so we don't need to cater for that
514 * separately.
515 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100516 unsigned long new_s2tte = s2tte & ~S2TT_DESC_TYPE_MASK;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100517
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000518 (void)s2_ctx;
519
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100520 assert(level >= S2TT_MIN_BLOCK_LEVEL);
521 assert(level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100522
523 if (level == S2TT_PAGE_LEVEL) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100524 return (new_s2tte | S2TTE_PAGE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000525 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100526 return (new_s2tte | S2TTE_BLOCK_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000527}
528
529/*
530 * Validate the portion of NS S2TTE that is provided by the host.
531 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000532bool host_ns_s2tte_is_valid(const struct s2tt_context *s2_ctx,
533 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000534{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100535
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000536 bool lpa2;
537 unsigned long mask;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100538
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000539 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100540 assert(level >= S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000541
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000542 lpa2 = s2_ctx->enable_lpa2;
543
544 mask = s2tte_lvl_mask(level, lpa2);
545 if (lpa2 == true) {
546 mask |= S2TTE_NS_ATTR_LPA2_MASK;
547 } else {
548 mask |= S2TTE_NS_ATTR_MASK;
549
550 /* Only SH_IS is allowed */
551 if ((s2tte & S2TTE_SH_MASK) != S2TTE_SH_IS) {
552 return false;
553 }
554 }
555
Soby Mathewb4c6df42022-11-09 11:13:29 +0000556 /*
557 * Test that all fields that are not controlled by the host are zero
558 * and that the output address is correctly aligned. Note that
559 * the host is permitted to map any physical address outside PAR.
560 */
561 if ((s2tte & ~mask) != 0UL) {
562 return false;
563 }
564
565 /*
566 * Only one value masked by S2TTE_MEMATTR_MASK is invalid/reserved.
567 */
568 if ((s2tte & S2TTE_MEMATTR_MASK) == S2TTE_MEMATTR_FWB_RESERVED) {
569 return false;
570 }
571
572 /*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000573 * Note that all the values that are masked by S2TTE_AP_MASK are valid.
574 */
575 return true;
576}
577
578/*
579 * Returns the portion of NS S2TTE that is set by the host.
580 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000581unsigned long host_ns_s2tte(const struct s2tt_context *s2_ctx,
582 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000583{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000584 assert(s2_ctx != NULL);
585
586 unsigned long mask = s2tte_lvl_mask(level, s2_ctx->enable_lpa2);
587
588 mask |= (s2_ctx->enable_lpa2 == true) ? S2TTE_NS_ATTR_LPA2_MASK :
589 S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000590
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100591 assert(level >= S2TT_MIN_BLOCK_LEVEL);
592
Soby Mathewb4c6df42022-11-09 11:13:29 +0000593 return (s2tte & mask);
594}
595
596/*
597 * Creates a table s2tte at level @level with output address @pa.
598 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000599unsigned long s2tte_create_table(const struct s2tt_context *s2_ctx,
600 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000601{
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +0100602 __unused long min_starting_level;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000603
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100604 (void)level;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000605
606 assert(s2_ctx != NULL);
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +0100607
608 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000609 min_starting_level = (s2_ctx->enable_lpa2 == true) ?
610 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
Chuyue Luo5ef71d92023-10-24 14:29:20 +0100611
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100612 assert(level < S2TT_PAGE_LEVEL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000613 assert(level >= min_starting_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000614 assert(GRANULE_ALIGNED(pa));
615
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000616 return (pa_to_s2tte(pa, s2_ctx->enable_lpa2) | S2TTE_TABLE);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000617}
618
619/*
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100620 * Returns true if s2tte has defined ripas value, namely if it is one of:
621 * - unassigned_empty
622 * - unassigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100623 * - unassigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100624 * - assigned_empty
625 * - assigned_ram
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100626 * - assigned_destroyed
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100627 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000628bool s2tte_has_ripas(const struct s2tt_context *s2_ctx,
629 unsigned long s2tte, long level)
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100630{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000631 return (((s2tte & S2TTE_NS) == 0UL) && !s2tte_is_table(s2_ctx,
632 s2tte, level));
AlexeiFedorov0fb44552023-04-14 15:37:58 +0100633}
634
635/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000636 * Returns true if @s2tte has HIPAS=@hipas.
637 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100638static inline bool s2tte_has_hipas(unsigned long s2tte, unsigned long hipas)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000639{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100640 unsigned long desc_type = s2tte & S2TT_DESC_TYPE_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000641 unsigned long invalid_desc_hipas = s2tte & S2TTE_INVALID_HIPAS_MASK;
642
AlexeiFedorov63614ea2023-07-14 17:07:20 +0100643 return ((desc_type == S2TTE_INVALID) && (invalid_desc_hipas == hipas));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000644}
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 Sobrino1e1781e2023-10-18 18:25:56 +0100760 if (((level == S2TT_PAGE_LEVEL) && (desc_type == S2TTE_L3_PAGE)) ||
Shruti Gupta3105c3f2024-02-26 14:06:11 +0000761 ((level >= S2TT_MIN_BLOCK_LEVEL) && (desc_type == S2TTE_L012_BLOCK))) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000762 return true;
763 }
764
765 return false;
766}
767
768/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100769 * Returns true if @s2tte is an assigned_ram.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000770 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000771bool s2tte_is_assigned_ram(const struct s2tt_context *s2_ctx,
772 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000773{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000774 return s2tte_check(s2_ctx, s2tte, level, 0UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000775}
776
777/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100778 * Returns true if @s2tte is an assigned_ns s2tte.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000779 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000780bool s2tte_is_assigned_ns(const struct s2tt_context *s2_ctx,
781 unsigned long s2tte, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000782{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000783 return s2tte_check(s2_ctx, s2tte, level, S2TTE_NS);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000784}
785
786/*
787 * Returns true if @s2tte is a table at level @level.
788 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000789bool s2tte_is_table(const struct s2tt_context *s2_ctx, unsigned long s2tte,
790 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000791{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000792 (void)s2_ctx;
793
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100794 return ((level < S2TT_PAGE_LEVEL) &&
795 ((s2tte & S2TT_DESC_TYPE_MASK) == S2TTE_L012_TABLE));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000796}
797
798/*
799 * Returns RIPAS of @s2tte.
800 *
801 * Caller should ensure that HIPAS=UNASSIGNED or HIPAS=ASSIGNED.
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100802 * The s2tte, if valid, should correspond to RIPAS_RAM.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000803 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000804enum ripas s2tte_get_ripas(const struct s2tt_context *s2_ctx, unsigned long s2tte)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000805{
806 unsigned long desc_ripas = s2tte & S2TTE_INVALID_RIPAS_MASK;
807
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000808 (void)s2_ctx;
809
Soby Mathewb4c6df42022-11-09 11:13:29 +0000810 /*
811 * If valid s2tte descriptor is passed, then ensure S2AP[0]
812 * bit is 1 (S2AP is set to RW for lower EL), which corresponds
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100813 * to RIPAS_RAM (bits[6:5] = b01) on a valid descriptor.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000814 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100815 assert(((s2tte & S2TT_DESC_TYPE_MASK) == S2TTE_INVALID) ||
816 (desc_ripas == S2TTE_INVALID_RIPAS_RAM));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000817
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100818 assert(EXTRACT(S2TTE_INVALID_HIPAS, s2tte) <=
819 EXTRACT(S2TTE_INVALID_HIPAS, S2TTE_INVALID_HIPAS_ASSIGNED));
820
821 desc_ripas = desc_ripas >> S2TTE_INVALID_RIPAS_SHIFT;
822
823 assert(desc_ripas <= (unsigned int)RIPAS_DESTROYED);
824
825 return (enum ripas)desc_ripas;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000826}
827
828/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100829 * Populates @s2tt with unassigned_empty s2ttes.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000830 *
831 * The granule is populated before it is made a table,
832 * hence, don't use s2tte_write for access.
833 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000834void s2tt_init_unassigned_empty(const struct s2tt_context *s2_ctx,
835 unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000836{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100837 assert(s2tt != NULL);
838
839 unsigned long s2tte =
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000840 s2tte_create_unassigned_empty(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100841
Soby Mathewb4c6df42022-11-09 11:13:29 +0000842 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100843 s2tt[i] = s2tte;
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100844 }
845
846 dsb(ish);
847}
848
849/*
850 * Populates @s2tt with unassigned_ram s2ttes.
851 *
852 * The granule is populated before it is made a table,
853 * hence, don't use s2tte_write for access.
854 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000855void s2tt_init_unassigned_ram(const struct s2tt_context *s2_ctx,
856 unsigned long *s2tt)
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100857{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100858 assert(s2tt != NULL);
859
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000860 unsigned long s2tte = s2tte_create_unassigned_ram(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100861
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100862 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100863 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000864 }
865
866 dsb(ish);
867}
868
869/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100870 * Populates @s2tt with unassigned_ns s2ttes.
871 *
872 * The granule is populated before it is made a table,
873 * hence, don't use s2tte_write for access.
874 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000875void s2tt_init_unassigned_ns(const struct s2tt_context *s2_ctx,
876 unsigned long *s2tt)
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100877{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100878 assert(s2tt != NULL);
879
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000880 unsigned long s2tte = s2tte_create_unassigned_ns(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100881
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100882 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100883 s2tt[i] = s2tte;
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100884 }
885
886 dsb(ish);
887}
888
889/*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000890 * Populates @s2tt with s2ttes which have HIPAS=DESTROYED.
891 *
892 * The granule is populated before it is made a table,
893 * hence, don't use s2tte_write for access.
894 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000895void s2tt_init_unassigned_destroyed(const struct s2tt_context *s2_ctx,
896 unsigned long *s2tt)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000897{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100898 assert(s2tt != NULL);
899
900 unsigned long s2tte =
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000901 s2tte_create_unassigned_destroyed(s2_ctx);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100902
Soby Mathewb4c6df42022-11-09 11:13:29 +0000903 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100904 s2tt[i] = s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000905 }
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100906 dsb(ish);
907}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000908
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100909/*
910 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=DESTROYED s2ttes that refer to a
911 * contiguous memory block starting at @pa, and mapped at level @level.
912 *
913 * The granule is populated before it is made a table,
914 * hence, don't use s2tte_write for access.
915 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000916void s2tt_init_assigned_destroyed(const struct s2tt_context *s2_ctx,
917 unsigned long *s2tt, unsigned long pa,
918 long level)
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100919{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000920 assert(s2tt != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100921 assert(level >= S2TT_MIN_BLOCK_LEVEL);
922 assert(level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000923 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100924
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100925 const unsigned long map_size = s2tte_map_size(level);
926
927 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000928 s2tt[i] = s2tte_create_assigned_destroyed(s2_ctx, pa, level);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100929 pa += map_size;
930 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000931 dsb(ish);
932}
933
Soby Mathewb4c6df42022-11-09 11:13:29 +0000934/*
935 * Populates @s2tt with HIPAS=ASSIGNED, RIPAS=EMPTY s2ttes that refer to a
936 * contiguous memory block starting at @pa, and mapped at level @level.
937 *
938 * The granule is populated before it is made a table,
939 * hence, don't use s2tte_write for access.
940 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000941void s2tt_init_assigned_empty(const struct s2tt_context *s2_ctx,
942 unsigned long *s2tt, unsigned long pa,
943 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000944{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100945 assert(level >= S2TT_MIN_BLOCK_LEVEL);
946 assert(level <= S2TT_PAGE_LEVEL);
947 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000948 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100949
Soby Mathewb4c6df42022-11-09 11:13:29 +0000950 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000951
AlexeiFedorov3a739332023-04-13 13:54:04 +0100952 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000953 s2tt[i] = s2tte_create_assigned_empty(s2_ctx, pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000954 pa += map_size;
955 }
956 dsb(ish);
957}
958
959/*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100960 * Populates @s2tt with assigned_ram s2ttes that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000961 * contiguous memory block starting at @pa, and mapped at level @level.
962 *
963 * The granule is populated before it is made a table,
964 * hence, don't use s2tte_write for access.
965 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000966void s2tt_init_assigned_ram(const struct s2tt_context *s2_ctx,
967 unsigned long *s2tt, unsigned long pa,
968 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000969{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100970 assert(level >= S2TT_MIN_BLOCK_LEVEL);
971 assert(level <= S2TT_PAGE_LEVEL);
972 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000973 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100974
Soby Mathewb4c6df42022-11-09 11:13:29 +0000975 const unsigned long map_size = s2tte_map_size(level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000976
AlexeiFedorov3a739332023-04-13 13:54:04 +0100977 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000978 s2tt[i] = s2tte_create_assigned_ram(s2_ctx, pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000979 pa += map_size;
980 }
981 dsb(ish);
982}
983
984/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100985 * Populates @s2tt with NS attributes @attrs that refer to a
Soby Mathewb4c6df42022-11-09 11:13:29 +0000986 * contiguous memory block starting at @pa, and mapped at level @level.
987 *
988 * The granule is populated before it is made a table,
989 * hence, don't use s2tte_write for access.
990 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000991void s2tt_init_assigned_ns(const struct s2tt_context *s2_ctx,
992 unsigned long *s2tt, unsigned long attrs,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100993 unsigned long pa, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000994{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100995 assert(level >= S2TT_MIN_BLOCK_LEVEL);
996 assert(level <= S2TT_PAGE_LEVEL);
997 assert(s2tt != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000998 assert(s2tte_is_addr_lvl_aligned(s2_ctx, pa, level));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100999
Soby Mathewb4c6df42022-11-09 11:13:29 +00001000 const unsigned long map_size = s2tte_map_size(level);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001001 unsigned long ns_attr_host_mask = (s2_ctx->enable_lpa2 == true) ?
1002 S2TTE_NS_ATTR_LPA2_MASK : S2TTE_NS_ATTR_MASK;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001003
AlexeiFedorov3a739332023-04-13 13:54:04 +01001004 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001005 unsigned long s2tte = attrs & ns_attr_host_mask;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001006
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001007 s2tt[i] = s2tte_create_assigned_ns(s2_ctx,
1008 s2tte | pa_to_s2tte(pa, s2_ctx->enable_lpa2),
1009 level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001010 pa += map_size;
1011 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001012
Soby Mathewb4c6df42022-11-09 11:13:29 +00001013 dsb(ish);
1014}
1015
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001016/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001017 * Returns true if s2tte is a live RTTE entry. i.e.,
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001018 * HIPAS is ASSIGNED.
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001019 *
1020 * NOTE: For now, only the RTTE with PA are live.
1021 * This could change with EXPORT/IMPORT support.
1022 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001023static bool s2tte_is_live(const struct s2tt_context *s2_ctx,
1024 unsigned long s2tte, long level)
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001025{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001026 return s2tte_has_pa(s2_ctx, s2tte, level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001027}
1028
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001029/* Returns physical address of a S2TTE */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001030unsigned long s2tte_pa(const struct s2tt_context *s2_ctx, unsigned long s2tte,
1031 long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001032{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001033 bool lpa2;
1034 unsigned long pa;
1035 __unused long min_starting_level;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001036
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001037 assert(s2_ctx != NULL);
1038
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +01001039 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001040 min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1041 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1042 assert(level >= min_starting_level);
1043 assert(level <= S2TT_PAGE_LEVEL);
1044 assert(s2tte_has_pa(s2_ctx, s2tte, level));
1045
1046 lpa2 = s2_ctx->enable_lpa2;
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001047
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001048 if (s2tte_is_table(s2_ctx, s2tte, level)) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001049 pa = table_entry_to_phys(s2tte, lpa2);
1050 } else {
1051 pa = s2tte_to_pa(s2tte, level, lpa2);
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001052 }
1053
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001054 return pa;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001055}
1056
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001057bool s2tte_is_addr_lvl_aligned(const struct s2tt_context *s2_ctx,
1058 unsigned long addr, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001059{
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001060 assert(s2_ctx != NULL);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001061
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +01001062 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001063 __unused long min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1064 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1065 unsigned long levels = (unsigned long)(S2TT_PAGE_LEVEL - level);
1066 unsigned long lsb = (levels * S2TTE_STRIDE) + GRANULE_SHIFT;
1067 unsigned long s2tte_oa_bits = (s2_ctx->enable_lpa2 == true) ?
1068 S2TTE_OA_BITS_LPA2 : S2TTE_OA_BITS;
1069
1070 assert(level <= S2TT_PAGE_LEVEL);
1071 assert(level >= min_starting_level);
1072
1073 return (addr == (addr & BIT_MASK_ULL((s2tte_oa_bits - 1U), lsb)));
Soby Mathewb4c6df42022-11-09 11:13:29 +00001074}
1075
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001076typedef bool (*s2tte_type_checker)(const struct s2tt_context *s2_ctx,
1077 unsigned long s2tte);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001078
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001079static bool table_is_uniform_block(const struct s2tt_context *s2_ctx,
1080 unsigned long *table,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001081 s2tte_type_checker s2tte_is_x)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001082{
AlexeiFedorov377d81f2023-04-14 16:29:12 +01001083 for (unsigned int i = 0U; i < S2TTES_PER_S2TT; i++) {
1084 unsigned long s2tte = s2tte_read(&table[i]);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001085
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001086 if (!s2tte_is_x(s2_ctx, s2tte)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001087 return false;
1088 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001089 }
1090
1091 return true;
1092}
1093
1094/*
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001095 * Returns true if all s2ttes in @table are unassigned_empty.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001096 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001097bool s2tt_is_unassigned_empty_block(const struct s2tt_context *s2_ctx,
1098 unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001099{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001100 assert(table != NULL);
1101
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001102 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_empty);
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001103}
1104
1105/*
1106 * Returns true if all s2ttes in @table are unassigned_ram.
1107 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001108bool s2tt_is_unassigned_ram_block(const struct s2tt_context *s2_ctx,
1109 unsigned long *table)
AlexeiFedorovc07a6382023-04-14 11:59:18 +01001110{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001111 assert(table != NULL);
1112
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001113 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_ram);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001114}
1115
1116/*
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001117 * Returns true if all s2ttes in @table are unassigned_ns
1118 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001119bool s2tt_is_unassigned_ns_block(const struct s2tt_context *s2_ctx,
1120 unsigned long *table)
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001121{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001122 assert(table != NULL);
1123
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001124 return table_is_uniform_block(s2_ctx, table, s2tte_is_unassigned_ns);
AlexeiFedorov5ceff352023-04-12 16:17:00 +01001125}
1126
1127/*
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001128 * Returns true if all s2ttes in @table are unassigned_destroyed
Soby Mathewb4c6df42022-11-09 11:13:29 +00001129 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001130bool s2tt_is_unassigned_destroyed_block(const struct s2tt_context *s2_ctx,
1131 unsigned long *table)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001132{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001133 assert(table != NULL);
1134
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001135 return table_is_uniform_block(s2_ctx, table,
1136 s2tte_is_unassigned_destroyed);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001137}
1138
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001139typedef bool (*s2tte_type_level_checker)(const struct s2tt_context *s2_ctx,
1140 unsigned long s2tte, long level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001141
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001142static bool table_maps_block(const struct s2tt_context *s2_ctx,
1143 unsigned long *table,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001144 long level,
1145 s2tte_type_level_checker s2tte_is_x,
1146 bool check_ns_attrs)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001147{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001148 assert(table != NULL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001149 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001150
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001151 unsigned long base_pa, ns_attr_host_mask;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001152 unsigned long map_size = s2tte_map_size(level);
1153 unsigned long s2tte = s2tte_read(&table[0]);
Javier Almansa Sobrino8865ec32024-04-18 10:50:03 +01001154 unsigned long s2tt_ns_attrs;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001155 unsigned int i;
1156
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001157 if (!s2tte_is_x(s2_ctx, s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001158 return false;
1159 }
1160
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001161 base_pa = s2tte_pa(s2_ctx, s2tte, level);
1162 if (!s2tte_is_addr_lvl_aligned(s2_ctx, base_pa, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001163 return false;
1164 }
1165
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001166 ns_attr_host_mask = (s2_ctx->enable_lpa2 == true) ?
1167 S2TTE_NS_ATTR_LPA2_MASK : S2TTE_NS_ATTR_MASK;
Javier Almansa Sobrino8865ec32024-04-18 10:50:03 +01001168 s2tt_ns_attrs = s2tte & ns_attr_host_mask;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001169
Soby Mathewb4c6df42022-11-09 11:13:29 +00001170 for (i = 1U; i < S2TTES_PER_S2TT; i++) {
1171 unsigned long expected_pa = base_pa + (i * map_size);
1172
1173 s2tte = s2tte_read(&table[i]);
1174
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001175 if (!s2tte_is_x(s2_ctx, s2tte, level)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001176 return false;
1177 }
1178
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001179 if (s2tte_pa(s2_ctx, s2tte, level) != expected_pa) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001180 return false;
1181 }
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001182
1183 if (check_ns_attrs) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001184 unsigned long ns_attrs =
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001185 s2tte & ns_attr_host_mask;
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001186
1187 /*
1188 * We match all the attributes in the S2TTE
1189 * except for the AF bit.
1190 */
Javier Almansa Sobrino8865ec32024-04-18 10:50:03 +01001191 if (s2tt_ns_attrs != ns_attrs) {
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001192 return false;
1193 }
1194 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001195 }
1196
1197 return true;
1198}
1199
1200/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001201 * Returns true if all s2ttes are assigned_empty
Soby Mathewb4c6df42022-11-09 11:13:29 +00001202 * and refer to a contiguous block of granules aligned to @level - 1.
1203 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001204bool s2tt_maps_assigned_empty_block(const struct s2tt_context *s2_ctx,
1205 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001206{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001207 return table_maps_block(s2_ctx, table, level,
1208 s2tte_is_assigned_empty, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001209}
1210
1211/*
AlexeiFedorov3a739332023-04-13 13:54:04 +01001212 * Returns true if all s2ttes are assigned_ram and
Soby Mathewb4c6df42022-11-09 11:13:29 +00001213 * refer to a contiguous block of granules aligned to @level - 1.
1214 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001215bool s2tt_maps_assigned_ram_block(const struct s2tt_context *s2_ctx,
1216 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001217{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001218 return table_maps_block(s2_ctx, table, level,
1219 s2tte_is_assigned_ram, false);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001220}
1221
1222/*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +01001223 * Returns true if
1224 * - all s2ttes in @table are assigned_ns s2ttes and
1225 * - they refer to a contiguous block of granules aligned to @level - 1 and
1226 * - all the s2tte attributes in @table controlled by the host are identical
AlexeiFedorov3a739332023-04-13 13:54:04 +01001227 *
1228 * @pre: @table maps IPA outside PAR.
Soby Mathewb4c6df42022-11-09 11:13:29 +00001229 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001230bool s2tt_maps_assigned_ns_block(const struct s2tt_context *s2_ctx,
1231 unsigned long *table, long level)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001232{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001233 return table_maps_block(s2_ctx, table, level,
1234 s2tte_is_assigned_ns, true);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001235}
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001236
1237/*
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001238 * Returns true if all s2ttes are assigned_destroyed and
1239 * refer to a contiguous block of granules aligned to @level - 1.
1240 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001241bool s2tt_maps_assigned_destroyed_block(const struct s2tt_context *s2_ctx,
1242 unsigned long *table, long level)
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001243{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001244 return table_maps_block(s2_ctx, table, level,
1245 s2tte_is_assigned_destroyed, false);
AlexeiFedorov3f840a02023-07-19 10:55:05 +01001246}
1247
1248/*
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001249 * Scan the RTT @s2tt (which is @wi.level), from the entry (@wi.index) and
AlexeiFedorov3ebd4622023-07-18 16:27:39 +01001250 * skip the non-live entries (i.e., HIPAS=UNASSIGNED).
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001251 * In other words, the scanning stops when a live RTTE is encountered or we
1252 * reach the end of this RTT.
1253 *
1254 * For now an RTTE can be considered non-live if it doesn't have a PA.
1255 * NOTE: This would change with EXPORT/IMPORT where we may have metadata stored
1256 * in the RTTE.
1257 *
1258 * @addr is not necessarily aligned to the wi.last_level (e.g., if we were called
1259 * with RMI_ERROR_RTT).
1260 *
1261 * Returns:
1262 * - If the entry @wi.index is live, returns @addr.
1263 * - If none of the entries in the @s2tt are "live", returns the address of the
1264 * first entry in the next table.
1265 * - Otherwise, the address of the first live entry in @s2tt
1266 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001267unsigned long s2tt_skip_non_live_entries(const struct s2tt_context *s2_ctx,
1268 unsigned long addr,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001269 unsigned long *table,
1270 const struct s2tt_walk *wi)
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001271{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001272 assert(table != NULL);
1273 assert(wi != NULL);
1274 assert(wi->index <= S2TTES_PER_S2TT);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001275 assert(wi->last_level <= S2TT_PAGE_LEVEL);
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001276 assert(s2_ctx != NULL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001277
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001278 unsigned long i, index = wi->index;
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001279 long level = wi->last_level;
1280 unsigned long map_size;
Shruti Gupta0a0d4ee2024-04-22 21:37:25 +01001281
1282 /* cppcheck-suppress misra-c2012-10.6 */
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001283 __unused long min_starting_level = (s2_ctx->enable_lpa2 == true) ?
1284 S2TT_MIN_STARTING_LEVEL_LPA2 : S2TT_MIN_STARTING_LEVEL;
1285
1286 assert(wi->last_level >= min_starting_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001287
1288 /*
1289 * If the entry for the map_addr is live,
1290 * return @addr.
1291 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001292 if (s2tte_is_live(s2_ctx, s2tte_read(&table[index]), level)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001293 return addr;
1294 }
1295
1296 /*
1297 * Align the address DOWN to the map_size, as expected for the @level,
1298 * so that we can compute the correct address by using the index.
1299 */
1300 map_size = s2tte_map_size(level);
1301 addr &= ~(map_size - 1UL);
1302
1303 /* Skip the "index" */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001304 for (i = index + 1UL; i < S2TTES_PER_S2TT; i++) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001305 unsigned long s2tte = s2tte_read(&table[i]);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001306
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001307 if (s2tte_is_live(s2_ctx, s2tte, level)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001308 break;
1309 }
1310 }
1311
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +01001312 return (addr + ((i - index) * map_size));
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001313}