blob: 298acf8c228c0d4769e993bda86709c5128016a8 [file] [log] [blame]
Soby Mathewb4c6df42022-11-09 11:13:29 +00001/*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
5 */
6
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01007#include <assert.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +00008#include <buffer.h>
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01009#include <errno.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000010#include <granule.h>
11#include <measurement.h>
12#include <realm.h>
13#include <ripas.h>
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010014#include <s2tt.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000015#include <smc-handler.h>
16#include <smc-rmi.h>
17#include <smc.h>
18#include <stddef.h>
19#include <string.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000020
21/*
22 * Validate the map_addr value passed to RMI_RTT_* and RMI_DATA_* commands.
23 */
24static bool validate_map_addr(unsigned long map_addr,
AlexeiFedorov4faab852023-08-30 15:06:49 +010025 long level,
Soby Mathewb4c6df42022-11-09 11:13:29 +000026 struct rd *rd)
27{
AlexeiFedorov14d47ae2023-07-19 15:26:50 +010028 return ((map_addr < realm_ipa_size(rd)) &&
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010029 s2tte_is_addr_lvl_aligned(map_addr, level));
Soby Mathewb4c6df42022-11-09 11:13:29 +000030}
31
32/*
33 * Structure commands can operate on all RTTs except for the root RTT so
34 * the minimal valid level is the stage 2 starting level + 1.
35 */
36static bool validate_rtt_structure_cmds(unsigned long map_addr,
37 long level,
38 struct rd *rd)
39{
40 int min_level = realm_rtt_starting_level(rd) + 1;
41
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010042 if ((level < min_level) || (level > S2TT_PAGE_LEVEL)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +000043 return false;
44 }
AlexeiFedorovf85f8102023-09-11 16:14:18 +010045 return validate_map_addr(map_addr, level - 1L, rd);
Soby Mathewb4c6df42022-11-09 11:13:29 +000046}
47
48/*
49 * Map/Unmap commands can operate up to a level 2 block entry so min_level is
50 * the smallest block size.
51 */
52static bool validate_rtt_map_cmds(unsigned long map_addr,
53 long level,
54 struct rd *rd)
55{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010056 if ((level < S2TT_MIN_BLOCK_LEVEL) || (level > S2TT_PAGE_LEVEL)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +000057 return false;
58 }
59 return validate_map_addr(map_addr, level, rd);
60}
61
62/*
63 * Entry commands can operate on any entry so the minimal valid level is the
64 * stage 2 starting level.
65 */
66static bool validate_rtt_entry_cmds(unsigned long map_addr,
67 long level,
68 struct rd *rd)
69{
70 if ((level < realm_rtt_starting_level(rd)) ||
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010071 (level > S2TT_PAGE_LEVEL)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +000072 return false;
73 }
74 return validate_map_addr(map_addr, level, rd);
75}
76
AlexeiFedorovac923c82023-04-06 15:12:04 +010077unsigned long smc_rtt_create(unsigned long rd_addr,
78 unsigned long rtt_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +000079 unsigned long map_addr,
80 unsigned long ulevel)
81{
82 struct granule *g_rd;
83 struct granule *g_tbl;
84 struct rd *rd;
85 struct granule *g_table_root;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010086 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +000087 unsigned long *s2tt, *parent_s2tt, parent_s2tte;
88 long level = (long)ulevel;
89 unsigned long ipa_bits;
90 unsigned long ret;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +000091 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +000092 int sl;
93
94 if (!find_lock_two_granules(rtt_addr,
95 GRANULE_STATE_DELEGATED,
96 &g_tbl,
97 rd_addr,
98 GRANULE_STATE_RD,
99 &g_rd)) {
100 return RMI_ERROR_INPUT;
101 }
102
103 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100104 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000105
106 if (!validate_rtt_structure_cmds(map_addr, level, rd)) {
107 buffer_unmap(rd);
108 granule_unlock(g_rd);
109 granule_unlock(g_tbl);
110 return RMI_ERROR_INPUT;
111 }
112
113 g_table_root = rd->s2_ctx.g_rtt;
114 sl = realm_rtt_starting_level(rd);
115 ipa_bits = realm_ipa_bits(rd);
116 s2_ctx = rd->s2_ctx;
117 buffer_unmap(rd);
118
119 /*
120 * Lock the RTT root. Enforcing locking order RD->RTT is enough to
121 * ensure deadlock free locking guarentee.
122 */
123 granule_lock(g_table_root, GRANULE_STATE_RTT);
124
125 /* Unlock RD after locking RTT Root */
126 granule_unlock(g_rd);
127
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100128 s2tt_walk_lock_unlock(g_table_root, sl, ipa_bits,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000129 map_addr, level - 1L, &wi);
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100130 if (wi.last_level != (level - 1L)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100131 ret = pack_return_code(RMI_ERROR_RTT,
132 (unsigned int)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000133 goto out_unlock_llt;
134 }
135
136 parent_s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100137 assert(parent_s2tt != NULL);
138
Soby Mathewb4c6df42022-11-09 11:13:29 +0000139 parent_s2tte = s2tte_read(&parent_s2tt[wi.index]);
140 s2tt = granule_map(g_tbl, SLOT_DELEGATED);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100141 assert(s2tt != NULL);
142
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100143 if (s2tte_is_unassigned_empty(parent_s2tte)) {
144 s2tt_init_unassigned_empty(s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000145
146 /*
147 * Increase the refcount of the parent, the granule was
148 * locked while table walking and hand-over-hand locking.
149 * Atomicity and acquire/release semantics not required because
150 * the table is accessed always locked.
151 */
152 __granule_get(wi.g_llt);
153
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100154 } else if (s2tte_is_unassigned_ram(parent_s2tte)) {
155 s2tt_init_unassigned_ram(s2tt);
156 __granule_get(wi.g_llt);
157
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100158 } else if (s2tte_is_unassigned_ns(parent_s2tte)) {
159 s2tt_init_unassigned_ns(s2tt);
160 __granule_get(wi.g_llt);
161
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100162 } else if (s2tte_is_unassigned_destroyed(parent_s2tte)) {
163 s2tt_init_unassigned_destroyed(s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000164 __granule_get(wi.g_llt);
165
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100166 } else if (s2tte_is_assigned_destroyed(parent_s2tte, level - 1L)) {
167 unsigned long block_pa;
168
169 /*
170 * We should observe parent assigned s2tte only when
171 * we create tables above this level.
172 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100173 assert(level > S2TT_MIN_BLOCK_LEVEL);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100174
175 block_pa = s2tte_pa(parent_s2tte, level - 1L);
176
177 s2tt_init_assigned_destroyed(s2tt, block_pa, level);
178
179 /*
180 * Increase the refcount to mark the granule as in-use. refcount
181 * is incremented by S2TTES_PER_S2TT (ref RTT unfolding).
182 */
183 __granule_refcount_inc(g_tbl, S2TTES_PER_S2TT);
184
AlexeiFedorov3a739332023-04-13 13:54:04 +0100185 } else if (s2tte_is_assigned_empty(parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000186 unsigned long block_pa;
187
188 /*
189 * We should observe parent assigned s2tte only when
190 * we create tables above this level.
191 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100192 assert(level > S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000193
194 block_pa = s2tte_pa(parent_s2tte, level - 1L);
195
196 s2tt_init_assigned_empty(s2tt, block_pa, level);
197
198 /*
199 * Increase the refcount to mark the granule as in-use. refcount
200 * is incremented by S2TTES_PER_S2TT (ref RTT unfolding).
201 */
202 __granule_refcount_inc(g_tbl, S2TTES_PER_S2TT);
203
AlexeiFedorov3a739332023-04-13 13:54:04 +0100204 } else if (s2tte_is_assigned_ram(parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000205 unsigned long block_pa;
206
207 /*
208 * We should observe parent valid s2tte only when
209 * we create tables above this level.
210 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100211 assert(level > S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000212
213 /*
214 * Break before make. This may cause spurious S2 aborts.
215 */
216 s2tte_write(&parent_s2tt[wi.index], 0UL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100217 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000218
219 block_pa = s2tte_pa(parent_s2tte, level - 1L);
220
AlexeiFedorov3a739332023-04-13 13:54:04 +0100221 s2tt_init_assigned_ram(s2tt, block_pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000222
223 /*
224 * Increase the refcount to mark the granule as in-use. refcount
225 * is incremented by S2TTES_PER_S2TT (ref RTT unfolding).
226 */
227 __granule_refcount_inc(g_tbl, S2TTES_PER_S2TT);
228
AlexeiFedorov3a739332023-04-13 13:54:04 +0100229 } else if (s2tte_is_assigned_ns(parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000230 unsigned long block_pa;
231
232 /*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100233 * We should observe parent assigned_ns s2tte only when
Soby Mathewb4c6df42022-11-09 11:13:29 +0000234 * we create tables above this level.
235 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100236 assert(level > S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000237
238 /*
239 * Break before make. This may cause spurious S2 aborts.
240 */
241 s2tte_write(&parent_s2tt[wi.index], 0UL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100242 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000243
244 block_pa = s2tte_pa(parent_s2tte, level - 1L);
245
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100246 s2tt_init_assigned_ns(s2tt, parent_s2tte, block_pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000247
248 /*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100249 * Increment the refcount on the parent for the new RTT we are
250 * about to add. The NS block entry doesn't have a refcount
251 * on the parent RTT.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000252 */
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100253 __granule_get(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000254
255 } else if (s2tte_is_table(parent_s2tte, level - 1L)) {
256 ret = pack_return_code(RMI_ERROR_RTT,
257 (unsigned int)(level - 1L));
258 goto out_unmap_table;
259
260 } else {
261 assert(false);
262 }
263
264 ret = RMI_SUCCESS;
265
266 granule_set_state(g_tbl, GRANULE_STATE_RTT);
267
268 parent_s2tte = s2tte_create_table(rtt_addr, level - 1L);
269 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
270
271out_unmap_table:
272 buffer_unmap(s2tt);
273 buffer_unmap(parent_s2tt);
274out_unlock_llt:
275 granule_unlock(wi.g_llt);
276 granule_unlock(g_tbl);
277 return ret;
278}
279
AlexeiFedorove2002be2023-04-19 17:20:12 +0100280void smc_rtt_fold(unsigned long rd_addr,
281 unsigned long map_addr,
282 unsigned long ulevel,
283 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000284{
285 struct granule *g_rd;
286 struct granule *g_tbl;
287 struct rd *rd;
288 struct granule *g_table_root;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100289 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000290 unsigned long *table, *parent_s2tt, parent_s2tte;
291 long level = (long)ulevel;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100292 unsigned long ipa_bits, rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000293 unsigned long ret;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000294 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000295 int sl;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000296
297 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
298 if (g_rd == NULL) {
AlexeiFedorove2002be2023-04-19 17:20:12 +0100299 res->x[0] = RMI_ERROR_INPUT;
300 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000301 }
302
303 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100304 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000305
306 if (!validate_rtt_structure_cmds(map_addr, level, rd)) {
307 buffer_unmap(rd);
308 granule_unlock(g_rd);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100309 res->x[0] = RMI_ERROR_INPUT;
310 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000311 }
312
313 g_table_root = rd->s2_ctx.g_rtt;
314 sl = realm_rtt_starting_level(rd);
315 ipa_bits = realm_ipa_bits(rd);
316 s2_ctx = rd->s2_ctx;
317 buffer_unmap(rd);
318 granule_lock(g_table_root, GRANULE_STATE_RTT);
319 granule_unlock(g_rd);
320
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100321 s2tt_walk_lock_unlock(g_table_root, sl, ipa_bits,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000322 map_addr, level - 1L, &wi);
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100323 if (wi.last_level != (level - 1L)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100324 ret = pack_return_code(RMI_ERROR_RTT,
325 (unsigned int)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000326 goto out_unlock_parent_table;
327 }
328
329 parent_s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100330 assert(parent_s2tt != NULL);
331
Soby Mathewb4c6df42022-11-09 11:13:29 +0000332 parent_s2tte = s2tte_read(&parent_s2tt[wi.index]);
333 if (!s2tte_is_table(parent_s2tte, level - 1L)) {
334 ret = pack_return_code(RMI_ERROR_RTT,
335 (unsigned int)(level - 1L));
336 goto out_unmap_parent_table;
337 }
338
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100339 rtt_addr = s2tte_pa(parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000340 g_tbl = find_lock_granule(rtt_addr, GRANULE_STATE_RTT);
341
342 /*
343 * A table descriptor S2TTE always points to a TABLE granule.
344 */
AlexeiFedorov63b71692023-04-19 11:18:42 +0100345 assert(g_tbl != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000346
347 table = granule_map(g_tbl, SLOT_RTT2);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100348 assert(table != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000349
350 /*
351 * The command can succeed only if all 512 S2TTEs are of the same type.
352 * We first check the table's ref. counter to speed up the case when
353 * the host makes a guess whether a memory region can be folded.
354 */
355 if (g_tbl->refcount == 0UL) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100356 if (s2tt_is_unassigned_destroyed_block(table)) {
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100357 parent_s2tte = s2tte_create_unassigned_destroyed();
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100358 } else if (s2tt_is_unassigned_empty_block(table)) {
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100359 parent_s2tte = s2tte_create_unassigned_empty();
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100360 } else if (s2tt_is_unassigned_ram_block(table)) {
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100361 parent_s2tte = s2tte_create_unassigned_ram();
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100362 } else if (s2tt_is_unassigned_ns_block(table)) {
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100363 parent_s2tte = s2tte_create_unassigned_ns();
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100364 } else if (s2tt_maps_assigned_ns_block(table, level)) {
AlexeiFedorov49752c62023-04-24 14:31:14 +0100365 unsigned long s2tte = s2tte_read(&table[0]);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100366
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100367 /*
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100368 * Since s2tt_maps_assigned_ns_block() has succedded,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100369 * the PA in first entry of the table is aligned at
370 * parent level. Use the TTE from the first entry
371 * directly as it also has the NS attributes to be used
372 * for the parent block entry.
373 */
374 parent_s2tte = s2tte_create_assigned_ns(s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000375 } else {
376 /*
377 * The table holds a mixture of destroyed and
378 * unassigned entries.
379 */
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100380 ret = pack_return_code(RMI_ERROR_RTT,
381 (unsigned int)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000382 goto out_unmap_table;
383 }
AlexeiFedorov49752c62023-04-24 14:31:14 +0100384 __granule_put(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000385 } else if (g_tbl->refcount == S2TTES_PER_S2TT) {
386
387 unsigned long s2tte, block_pa;
388
389 /* The RMM specification does not allow creating block
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100390 * entries less than S2TT_MIN_BLOCK_LEVEL even though
Soby Mathewb4c6df42022-11-09 11:13:29 +0000391 * permitted by the Arm Architecture.
392 * Hence ensure that the table being folded is at a level
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100393 * higher than the S2TT_MIN_BLOCK_LEVEL.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000394 *
395 * A fully populated table cannot be destroyed if that
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100396 * would create a block mapping below S2TT_MIN_BLOCK_LEVEL.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000397 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100398 if (level <= S2TT_MIN_BLOCK_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100399 ret = pack_return_code(RMI_ERROR_RTT,
400 (unsigned int)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000401 goto out_unmap_table;
402 }
403
404 s2tte = s2tte_read(&table[0]);
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000405 block_pa = s2tte_pa(s2tte, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000406
407 /*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100408 * The table must also refer to a contiguous block through the
AlexeiFedorov3f840a02023-07-19 10:55:05 +0100409 * same type of s2tte, either Assigned or Valid.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000410 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100411 if (s2tt_maps_assigned_empty_block(table, level)) {
412 parent_s2tte = s2tte_create_assigned_empty(
413 block_pa, level - 1L);
414 } else if (s2tt_maps_assigned_ram_block(table, level)) {
AlexeiFedorov3a739332023-04-13 13:54:04 +0100415 parent_s2tte = s2tte_create_assigned_ram(block_pa,
416 level - 1L);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100417 } else if (s2tt_maps_assigned_destroyed_block(table, level)) {
418 parent_s2tte = s2tte_create_assigned_destroyed(
419 block_pa, level - 1L);
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000420 /* The table contains mixed entries that cannot be folded */
Soby Mathewb4c6df42022-11-09 11:13:29 +0000421 } else {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100422 ret = pack_return_code(RMI_ERROR_RTT,
423 (unsigned int)level);
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000424 goto out_unmap_table;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000425 }
426
427 __granule_refcount_dec(g_tbl, S2TTES_PER_S2TT);
428 } else {
429 /*
430 * The table holds a mixture of different types of s2ttes.
431 */
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100432 ret = pack_return_code(RMI_ERROR_RTT,
433 (unsigned int)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000434 goto out_unmap_table;
435 }
436
437 ret = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100438 res->x[1] = rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000439
440 /*
441 * Break before make.
442 */
443 s2tte_write(&parent_s2tt[wi.index], 0UL);
444
AlexeiFedorov3a739332023-04-13 13:54:04 +0100445 if (s2tte_is_assigned_ram(parent_s2tte, level - 1L) ||
446 s2tte_is_assigned_ns(parent_s2tte, level - 1L)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100447 s2tt_invalidate_pages_in_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000448 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100449 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000450 }
451
452 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
453
454 granule_memzero_mapped(table);
455 granule_set_state(g_tbl, GRANULE_STATE_DELEGATED);
456
457out_unmap_table:
458 buffer_unmap(table);
459 granule_unlock(g_tbl);
460out_unmap_parent_table:
461 buffer_unmap(parent_s2tt);
462out_unlock_parent_table:
463 granule_unlock(wi.g_llt);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100464 res->x[0] = ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000465}
466
AlexeiFedorove2002be2023-04-19 17:20:12 +0100467void smc_rtt_destroy(unsigned long rd_addr,
468 unsigned long map_addr,
469 unsigned long ulevel,
470 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000471{
472 struct granule *g_rd;
473 struct granule *g_tbl;
474 struct rd *rd;
475 struct granule *g_table_root;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100476 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000477 unsigned long *table, *parent_s2tt, parent_s2tte;
478 long level = (long)ulevel;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100479 unsigned long ipa_bits, rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000480 unsigned long ret;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000481 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000482 int sl;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100483 bool in_par, skip_non_live = false;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000484
485 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
486 if (g_rd == NULL) {
AlexeiFedorove2002be2023-04-19 17:20:12 +0100487 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100488 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100489 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000490 }
491
492 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100493 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000494
495 if (!validate_rtt_structure_cmds(map_addr, level, rd)) {
496 buffer_unmap(rd);
497 granule_unlock(g_rd);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100498 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100499 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100500 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000501 }
502
503 g_table_root = rd->s2_ctx.g_rtt;
504 sl = realm_rtt_starting_level(rd);
505 ipa_bits = realm_ipa_bits(rd);
506 s2_ctx = rd->s2_ctx;
507 in_par = addr_in_par(rd, map_addr);
508 buffer_unmap(rd);
509 granule_lock(g_table_root, GRANULE_STATE_RTT);
510 granule_unlock(g_rd);
511
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100512 s2tt_walk_lock_unlock(g_table_root, sl, ipa_bits,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000513 map_addr, level - 1L, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000514
515 parent_s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100516 assert(parent_s2tt != NULL);
517
Soby Mathewb4c6df42022-11-09 11:13:29 +0000518 parent_s2tte = s2tte_read(&parent_s2tt[wi.index]);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100519
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100520 if ((wi.last_level != (level - 1L)) ||
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100521 !s2tte_is_table(parent_s2tte, level - 1L)) {
522 ret = pack_return_code(RMI_ERROR_RTT,
523 (unsigned int)wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100524 skip_non_live = true;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000525 goto out_unmap_parent_table;
526 }
527
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100528 rtt_addr = s2tte_pa(parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000529
530 /*
531 * Lock the RTT granule. The 'rtt_addr' is verified, thus can be treated
532 * as an internal granule.
533 */
534 g_tbl = find_lock_granule(rtt_addr, GRANULE_STATE_RTT);
535
536 /*
537 * A table descriptor S2TTE always points to a TABLE granule.
538 */
539 assert(g_tbl != NULL);
540
541 /*
542 * Read the refcount value. RTT granule is always accessed locked, thus
543 * the refcount can be accessed without atomic operations.
544 */
545 if (g_tbl->refcount != 0UL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100546 ret = pack_return_code(RMI_ERROR_RTT, (unsigned int)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000547 goto out_unlock_table;
548 }
549
550 ret = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100551 res->x[1] = rtt_addr;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100552 skip_non_live = true;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000553
554 table = granule_map(g_tbl, SLOT_RTT2);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100555 assert(table != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000556
557 if (in_par) {
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100558 parent_s2tte = s2tte_create_unassigned_destroyed();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000559 } else {
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100560 parent_s2tte = s2tte_create_unassigned_ns();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000561 }
562
563 __granule_put(wi.g_llt);
564
565 /*
566 * Break before make. Note that this may cause spurious S2 aborts.
567 */
568 s2tte_write(&parent_s2tt[wi.index], 0UL);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000569
570 if (in_par) {
571 /* For protected IPA, all S2TTEs in the RTT will be invalid */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100572 s2tt_invalidate_block(&s2_ctx, map_addr);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000573 } else {
574 /*
575 * For unprotected IPA, invalidate the TLB for the entire range
576 * mapped by the RTT as it may have valid NS mappings.
577 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100578 s2tt_invalidate_pages_in_block(&s2_ctx, map_addr);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000579 }
580
Soby Mathewb4c6df42022-11-09 11:13:29 +0000581 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
582
583 granule_memzero_mapped(table);
584 granule_set_state(g_tbl, GRANULE_STATE_DELEGATED);
585
586 buffer_unmap(table);
587out_unlock_table:
588 granule_unlock(g_tbl);
589out_unmap_parent_table:
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100590 if (skip_non_live) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100591 res->x[2] = s2tt_skip_non_live_entries(map_addr, parent_s2tt, &wi);
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100592 } else {
593 res->x[2] = map_addr;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100594 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000595 buffer_unmap(parent_s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000596 granule_unlock(wi.g_llt);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100597 res->x[0] = ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000598}
599
600enum map_unmap_ns_op {
601 MAP_NS,
602 UNMAP_NS
603};
604
605/*
606 * We don't hold a reference on the NS granule when it is
607 * mapped into a realm. Instead we rely on the guarantees
608 * provided by the architecture to ensure that a NS access
609 * to a protected granule is prohibited even within the realm.
610 */
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100611static void map_unmap_ns(unsigned long rd_addr,
612 unsigned long map_addr,
613 long level,
614 unsigned long host_s2tte,
615 enum map_unmap_ns_op op,
616 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000617{
618 struct granule *g_rd;
619 struct rd *rd;
620 struct granule *g_table_root;
621 unsigned long *s2tt, s2tte;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100622 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000623 unsigned long ipa_bits;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000624 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000625 int sl;
626
627 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
628 if (g_rd == NULL) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100629 res->x[0] = RMI_ERROR_INPUT;
630 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000631 }
632
633 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100634 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000635
636 if (!validate_rtt_map_cmds(map_addr, level, rd)) {
637 buffer_unmap(rd);
638 granule_unlock(g_rd);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100639 res->x[0] = RMI_ERROR_INPUT;
640 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000641 }
642
643 g_table_root = rd->s2_ctx.g_rtt;
644 sl = realm_rtt_starting_level(rd);
645 ipa_bits = realm_ipa_bits(rd);
646
AlexeiFedorovc34e3242023-04-12 11:30:33 +0100647 /* Check if map_addr is outside PAR */
648 if (addr_in_par(rd, map_addr)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000649 buffer_unmap(rd);
650 granule_unlock(g_rd);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100651 res->x[0] = RMI_ERROR_INPUT;
652 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000653 }
654
655 s2_ctx = rd->s2_ctx;
656 buffer_unmap(rd);
657
658 granule_lock(g_table_root, GRANULE_STATE_RTT);
659 granule_unlock(g_rd);
660
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100661 s2tt_walk_lock_unlock(g_table_root, sl, ipa_bits,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000662 map_addr, level, &wi);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100663
664 /*
665 * For UNMAP_NS, we need to map the table and look
666 * for the end of the non-live region.
667 */
AlexeiFedorov14d47ae2023-07-19 15:26:50 +0100668 if ((op == MAP_NS) && (wi.last_level != level)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100669 res->x[0] = pack_return_code(RMI_ERROR_RTT,
670 (unsigned int)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000671 goto out_unlock_llt;
672 }
673
674 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100675 assert(s2tt != NULL);
676
Soby Mathewb4c6df42022-11-09 11:13:29 +0000677 s2tte = s2tte_read(&s2tt[wi.index]);
678
679 if (op == MAP_NS) {
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100680 if (!s2tte_is_unassigned_ns(s2tte)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100681 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000682 (unsigned int)level);
683 goto out_unmap_table;
684 }
685
AlexeiFedorov3a739332023-04-13 13:54:04 +0100686 s2tte = s2tte_create_assigned_ns(host_s2tte, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000687 s2tte_write(&s2tt[wi.index], s2tte);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000688
689 } else if (op == UNMAP_NS) {
690 /*
691 * The following check also verifies that map_addr is outside
692 * PAR, as valid_NS s2tte may only cover outside PAR IPA range.
693 */
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100694 bool assigned_ns = s2tte_is_assigned_ns(s2tte, wi.last_level);
695
696 if ((wi.last_level != level) || !assigned_ns) {
697 res->x[0] = pack_return_code(RMI_ERROR_RTT,
698 (unsigned int)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000699 goto out_unmap_table;
700 }
701
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100702 s2tte = s2tte_create_unassigned_ns();
Soby Mathewb4c6df42022-11-09 11:13:29 +0000703 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100704 if (level == S2TT_PAGE_LEVEL) {
705 s2tt_invalidate_page(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000706 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100707 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000708 }
709 }
710
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100711 res->x[0] = RMI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000712
713out_unmap_table:
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100714 if (op == UNMAP_NS) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100715 res->x[1] = s2tt_skip_non_live_entries(map_addr, s2tt, &wi);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100716 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000717 buffer_unmap(s2tt);
718out_unlock_llt:
719 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000720}
721
722unsigned long smc_rtt_map_unprotected(unsigned long rd_addr,
723 unsigned long map_addr,
724 unsigned long ulevel,
725 unsigned long s2tte)
726{
727 long level = (long)ulevel;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100728 struct smc_result res;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000729
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100730 if ((level < S2TT_MIN_BLOCK_LEVEL) || (level > S2TT_PAGE_LEVEL)) {
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100731 return RMI_ERROR_INPUT;
732 }
733
Soby Mathewb4c6df42022-11-09 11:13:29 +0000734 if (!host_ns_s2tte_is_valid(s2tte, level)) {
735 return RMI_ERROR_INPUT;
736 }
737
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100738 map_unmap_ns(rd_addr, map_addr, level, s2tte, MAP_NS, &res);
739 return res.x[0];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000740}
741
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100742void smc_rtt_unmap_unprotected(unsigned long rd_addr,
743 unsigned long map_addr,
744 unsigned long ulevel,
745 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000746{
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100747 long level = (long)ulevel;
748
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100749 if ((level < S2TT_MIN_BLOCK_LEVEL) || (level > S2TT_PAGE_LEVEL)) {
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100750 res->x[0] = RMI_ERROR_INPUT;
751 return;
752 }
753
754 map_unmap_ns(rd_addr, map_addr, level, 0UL, UNMAP_NS, res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000755}
756
757void smc_rtt_read_entry(unsigned long rd_addr,
758 unsigned long map_addr,
759 unsigned long ulevel,
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100760 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000761{
762 struct granule *g_rd, *g_rtt_root;
763 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100764 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000765 unsigned long *s2tt, s2tte;
766 unsigned long ipa_bits;
767 long level = (long)ulevel;
768 int sl;
769
770 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
771 if (g_rd == NULL) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100772 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000773 return;
774 }
775
776 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100777 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000778
779 if (!validate_rtt_entry_cmds(map_addr, level, rd)) {
780 buffer_unmap(rd);
781 granule_unlock(g_rd);
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100782 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000783 return;
784 }
785
786 g_rtt_root = rd->s2_ctx.g_rtt;
787 sl = realm_rtt_starting_level(rd);
788 ipa_bits = realm_ipa_bits(rd);
789 buffer_unmap(rd);
790
791 granule_lock(g_rtt_root, GRANULE_STATE_RTT);
792 granule_unlock(g_rd);
793
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100794 s2tt_walk_lock_unlock(g_rtt_root, sl, ipa_bits,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000795 map_addr, level, &wi);
796 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100797 assert(s2tt != NULL);
798
Soby Mathewb4c6df42022-11-09 11:13:29 +0000799 s2tte = s2tte_read(&s2tt[wi.index]);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100800 res->x[1] = (unsigned long)wi.last_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000801
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100802 if (s2tte_is_unassigned_empty(s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100803 res->x[2] = RMI_UNASSIGNED;
804 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100805 res->x[4] = (unsigned long)RIPAS_EMPTY;
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100806 } else if (s2tte_is_unassigned_ram(s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100807 res->x[2] = RMI_UNASSIGNED;
808 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100809 res->x[4] = (unsigned long)RIPAS_RAM;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100810 } else if (s2tte_is_unassigned_destroyed(s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100811 res->x[2] = RMI_UNASSIGNED;
812 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100813 res->x[4] = (unsigned long)RIPAS_DESTROYED;
AlexeiFedorov3a739332023-04-13 13:54:04 +0100814 } else if (s2tte_is_assigned_empty(s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100815 res->x[2] = RMI_ASSIGNED;
816 res->x[3] = s2tte_pa(s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100817 res->x[4] = (unsigned long)RIPAS_EMPTY;
AlexeiFedorov3a739332023-04-13 13:54:04 +0100818 } else if (s2tte_is_assigned_ram(s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100819 res->x[2] = RMI_ASSIGNED;
820 res->x[3] = s2tte_pa(s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100821 res->x[4] = (unsigned long)RIPAS_RAM;
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100822 } else if (s2tte_is_assigned_destroyed(s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100823 res->x[2] = RMI_ASSIGNED;
824 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100825 res->x[4] = (unsigned long)RIPAS_DESTROYED;
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100826 } else if (s2tte_is_unassigned_ns(s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100827 res->x[2] = RMI_UNASSIGNED;
828 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100829 res->x[4] = (unsigned long)RIPAS_EMPTY;
AlexeiFedorov3a739332023-04-13 13:54:04 +0100830 } else if (s2tte_is_assigned_ns(s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100831 res->x[2] = RMI_ASSIGNED;
832 res->x[3] = host_ns_s2tte(s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100833 res->x[4] = (unsigned long)RIPAS_EMPTY;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000834 } else if (s2tte_is_table(s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100835 res->x[2] = RMI_TABLE;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100836 res->x[3] = s2tte_pa(s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100837 res->x[4] = (unsigned long)RIPAS_EMPTY;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000838 } else {
839 assert(false);
840 }
841
842 buffer_unmap(s2tt);
843 granule_unlock(wi.g_llt);
844
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100845 res->x[0] = RMI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000846}
847
Soby Mathewb4c6df42022-11-09 11:13:29 +0000848static unsigned long validate_data_create_unknown(unsigned long map_addr,
849 struct rd *rd)
850{
851 if (!addr_in_par(rd, map_addr)) {
852 return RMI_ERROR_INPUT;
853 }
854
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100855 if (!validate_map_addr(map_addr, S2TT_PAGE_LEVEL, rd)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000856 return RMI_ERROR_INPUT;
857 }
858
859 return RMI_SUCCESS;
860}
861
862static unsigned long validate_data_create(unsigned long map_addr,
863 struct rd *rd)
864{
Mate Toth-Pal988dfcb2024-01-19 10:52:06 +0100865 if (get_rd_state_locked(rd) != REALM_NEW) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000866 return RMI_ERROR_REALM;
867 }
868
869 return validate_data_create_unknown(map_addr, rd);
870}
871
872/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100873 * Implements both RMI_DATA_CREATE and RMI_DATA_CREATE_UNKNOWN
Soby Mathewb4c6df42022-11-09 11:13:29 +0000874 *
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100875 * if @g_src == NULL, implements RMI_DATA_CREATE_UNKNOWN
876 * and RMI_DATA_CREATE otherwise.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000877 */
AlexeiFedorovac923c82023-04-06 15:12:04 +0100878static unsigned long data_create(unsigned long rd_addr,
879 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000880 unsigned long map_addr,
881 struct granule *g_src,
882 unsigned long flags)
883{
884 struct granule *g_data;
885 struct granule *g_rd;
886 struct granule *g_table_root;
887 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100888 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000889 unsigned long s2tte, *s2tt;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000890 enum granule_state new_data_state = GRANULE_STATE_DELEGATED;
891 unsigned long ipa_bits;
892 unsigned long ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000893 int sl;
894
895 if (!find_lock_two_granules(data_addr,
896 GRANULE_STATE_DELEGATED,
897 &g_data,
898 rd_addr,
899 GRANULE_STATE_RD,
900 &g_rd)) {
901 return RMI_ERROR_INPUT;
902 }
903
904 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100905 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000906
907 ret = (g_src != NULL) ?
908 validate_data_create(map_addr, rd) :
909 validate_data_create_unknown(map_addr, rd);
910
911 if (ret != RMI_SUCCESS) {
912 goto out_unmap_rd;
913 }
914
915 g_table_root = rd->s2_ctx.g_rtt;
916 sl = realm_rtt_starting_level(rd);
917 ipa_bits = realm_ipa_bits(rd);
918 granule_lock(g_table_root, GRANULE_STATE_RTT);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100919 s2tt_walk_lock_unlock(g_table_root, sl, ipa_bits,
920 map_addr, S2TT_PAGE_LEVEL, &wi);
921 if (wi.last_level != S2TT_PAGE_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100922 ret = pack_return_code(RMI_ERROR_RTT,
923 (unsigned int)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000924 goto out_unlock_ll_table;
925 }
926
927 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100928 assert(s2tt != NULL);
929
Soby Mathewb4c6df42022-11-09 11:13:29 +0000930 s2tte = s2tte_read(&s2tt[wi.index]);
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100931 if (!s2tte_is_unassigned(s2tte)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100932 ret = pack_return_code(RMI_ERROR_RTT, S2TT_PAGE_LEVEL);
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100933 goto out_unmap_ll_table;
934 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000935
Soby Mathewb4c6df42022-11-09 11:13:29 +0000936 if (g_src != NULL) {
937 bool ns_access_ok;
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100938 void *data = granule_map(g_data, SLOT_DELEGATED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000939
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100940 assert(data != NULL);
941
Soby Mathewb4c6df42022-11-09 11:13:29 +0000942 ns_access_ok = ns_buffer_read(SLOT_NS, g_src, 0U,
943 GRANULE_SIZE, data);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000944 if (!ns_access_ok) {
945 /*
946 * Some data may be copied before the failure. Zero
947 * g_data granule as it will remain in delegated state.
948 */
949 (void)memset(data, 0, GRANULE_SIZE);
950 buffer_unmap(data);
951 ret = RMI_ERROR_INPUT;
952 goto out_unmap_ll_table;
953 }
954
Mate Toth-Palc7698312023-08-09 12:49:34 +0200955 measurement_data_granule_measure(
956 rd->measurement[RIM_MEASUREMENT_SLOT],
957 rd->algorithm,
958 data,
959 map_addr,
960 flags);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000961 buffer_unmap(data);
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100962
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100963 s2tte = s2tte_create_assigned_ram(data_addr, S2TT_PAGE_LEVEL);
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100964 } else {
965 s2tte = s2tte_create_assigned_unchanged(s2tte, data_addr,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100966 S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000967 }
968
969 new_data_state = GRANULE_STATE_DATA;
970
Soby Mathewb4c6df42022-11-09 11:13:29 +0000971 s2tte_write(&s2tt[wi.index], s2tte);
972 __granule_get(wi.g_llt);
973
974 ret = RMI_SUCCESS;
975
976out_unmap_ll_table:
977 buffer_unmap(s2tt);
978out_unlock_ll_table:
979 granule_unlock(wi.g_llt);
980out_unmap_rd:
981 buffer_unmap(rd);
982 granule_unlock(g_rd);
983 granule_unlock_transition(g_data, new_data_state);
984 return ret;
985}
986
AlexeiFedorovac923c82023-04-06 15:12:04 +0100987unsigned long smc_data_create(unsigned long rd_addr,
988 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000989 unsigned long map_addr,
990 unsigned long src_addr,
991 unsigned long flags)
992{
993 struct granule *g_src;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000994
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100995 if ((flags != RMI_NO_MEASURE_CONTENT) &&
996 (flags != RMI_MEASURE_CONTENT)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000997 return RMI_ERROR_INPUT;
998 }
999
1000 g_src = find_granule(src_addr);
1001 if ((g_src == NULL) || (g_src->state != GRANULE_STATE_NS)) {
1002 return RMI_ERROR_INPUT;
1003 }
1004
AlexeiFedorovac923c82023-04-06 15:12:04 +01001005 return data_create(rd_addr, data_addr, map_addr, g_src, flags);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001006}
1007
AlexeiFedorovac923c82023-04-06 15:12:04 +01001008unsigned long smc_data_create_unknown(unsigned long rd_addr,
1009 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +00001010 unsigned long map_addr)
1011{
AlexeiFedorovac923c82023-04-06 15:12:04 +01001012 return data_create(rd_addr, data_addr, map_addr, NULL, 0);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001013}
1014
AlexeiFedorove2002be2023-04-19 17:20:12 +01001015void smc_data_destroy(unsigned long rd_addr,
1016 unsigned long map_addr,
1017 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001018{
1019 struct granule *g_data;
1020 struct granule *g_rd;
1021 struct granule *g_table_root;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001022 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001023 unsigned long data_addr, s2tte, *s2tt;
1024 struct rd *rd;
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001025 unsigned long ipa_bits;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +00001026 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001027 int sl;
1028
1029 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
1030 if (g_rd == NULL) {
AlexeiFedorove2002be2023-04-19 17:20:12 +01001031 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorova1b2a1d2023-07-18 15:08:47 +01001032 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001033 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001034 }
1035
1036 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001037 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001038
AlexeiFedorov868a6512023-09-14 13:21:11 +01001039 if (!addr_in_par(rd, map_addr) ||
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001040 !validate_map_addr(map_addr, S2TT_PAGE_LEVEL, rd)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001041 buffer_unmap(rd);
1042 granule_unlock(g_rd);
AlexeiFedorove2002be2023-04-19 17:20:12 +01001043 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorova1b2a1d2023-07-18 15:08:47 +01001044 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001045 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001046 }
1047
1048 g_table_root = rd->s2_ctx.g_rtt;
1049 sl = realm_rtt_starting_level(rd);
1050 ipa_bits = realm_ipa_bits(rd);
1051 s2_ctx = rd->s2_ctx;
1052 buffer_unmap(rd);
1053
1054 granule_lock(g_table_root, GRANULE_STATE_RTT);
1055 granule_unlock(g_rd);
1056
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001057 s2tt_walk_lock_unlock(g_table_root, sl, ipa_bits,
1058 map_addr, S2TT_PAGE_LEVEL, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001059
1060 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001061 assert(s2tt != NULL);
1062
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001063 if (wi.last_level != S2TT_PAGE_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001064 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1065 (unsigned int)wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001066 goto out_unmap_ll_table;
1067 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001068
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001069 s2tte = s2tte_read(&s2tt[wi.index]);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001070
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001071 if (s2tte_is_assigned_ram(s2tte, S2TT_PAGE_LEVEL)) {
1072 data_addr = s2tte_pa(s2tte, S2TT_PAGE_LEVEL);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001073 s2tte = s2tte_create_unassigned_destroyed();
AlexeiFedorova43cd312023-04-17 11:42:25 +01001074 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001075 s2tt_invalidate_page(&s2_ctx, map_addr);
1076 } else if (s2tte_is_assigned_empty(s2tte, S2TT_PAGE_LEVEL)) {
1077 data_addr = s2tte_pa(s2tte, S2TT_PAGE_LEVEL);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001078 s2tte = s2tte_create_unassigned_empty();
1079 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001080 } else if (s2tte_is_assigned_destroyed(s2tte, S2TT_PAGE_LEVEL)) {
1081 data_addr = s2tte_pa(s2tte, S2TT_PAGE_LEVEL);
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +01001082 s2tte = s2tte_create_unassigned_destroyed();
1083 s2tte_write(&s2tt[wi.index], s2tte);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001084 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001085 res->x[0] = pack_return_code(RMI_ERROR_RTT, S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001086 goto out_unmap_ll_table;
1087 }
1088
Soby Mathewb4c6df42022-11-09 11:13:29 +00001089 __granule_put(wi.g_llt);
1090
1091 /*
1092 * Lock the data granule and check expected state. Correct locking order
1093 * is guaranteed because granule address is obtained from a locked
1094 * granule by table walk. This lock needs to be acquired before a state
1095 * transition to or from GRANULE_STATE_DATA for granule address can happen.
1096 */
1097 g_data = find_lock_granule(data_addr, GRANULE_STATE_DATA);
AlexeiFedorov63b71692023-04-19 11:18:42 +01001098 assert(g_data != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001099 granule_memzero(g_data, SLOT_DELEGATED);
1100 granule_unlock_transition(g_data, GRANULE_STATE_DELEGATED);
1101
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001102 res->x[0] = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001103 res->x[1] = data_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001104out_unmap_ll_table:
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001105 res->x[2] = s2tt_skip_non_live_entries(map_addr, s2tt, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001106 buffer_unmap(s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001107 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001108}
1109
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001110/*
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001111 * Update the ripas value for the entry pointed by @s2ttep.
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001112 *
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001113 * Returns:
1114 * < 0 - On error and the operation was aborted,
1115 * e.g., entry cannot have a ripas.
1116 * 0 - Operation was success and no TLBI is required.
1117 * > 0 - Operation was success and TLBI is required.
1118 * Sets:
1119 * @(*do_tlbi) to 'true' if the TLBs have to be invalidated.
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001120 */
AlexeiFedorov4faab852023-08-30 15:06:49 +01001121static int update_ripas(unsigned long *s2ttep, long level,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001122 enum ripas ripas_val,
1123 enum ripas_change_destroyed change_destroyed)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001124{
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001125 unsigned long pa, s2tte = s2tte_read(s2ttep);
1126 int ret = 0;
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001127
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001128 if (!s2tte_has_ripas(s2tte, level)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001129 return -EPERM;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001130 }
1131
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001132 if (ripas_val == RIPAS_RAM) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001133 if (s2tte_is_unassigned_empty(s2tte)) {
1134 s2tte = s2tte_create_unassigned_ram();
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001135 } else if (s2tte_is_unassigned_destroyed(s2tte)) {
1136 if (change_destroyed == CHANGE_DESTROYED) {
1137 s2tte = s2tte_create_unassigned_ram();
1138 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001139 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001140 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001141 } else if (s2tte_is_assigned_empty(s2tte, level)) {
1142 pa = s2tte_pa(s2tte, level);
1143 s2tte = s2tte_create_assigned_ram(pa, level);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001144 } else if (s2tte_is_assigned_destroyed(s2tte, level)) {
1145 if (change_destroyed == CHANGE_DESTROYED) {
1146 pa = s2tte_pa(s2tte, level);
1147 s2tte = s2tte_create_assigned_ram(pa, level);
1148 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001149 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001150 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001151 } else {
1152 /* No action is required */
1153 return 0;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001154 }
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001155 } else if (ripas_val == RIPAS_EMPTY) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001156 if (s2tte_is_unassigned_ram(s2tte)) {
1157 s2tte = s2tte_create_unassigned_empty();
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001158 } else if (s2tte_is_unassigned_destroyed(s2tte)) {
1159 if (change_destroyed == CHANGE_DESTROYED) {
1160 s2tte = s2tte_create_unassigned_empty();
1161 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001162 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001163 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001164 } else if (s2tte_is_assigned_ram(s2tte, level)) {
1165 pa = s2tte_pa(s2tte, level);
1166 s2tte = s2tte_create_assigned_empty(pa, level);
1167 /* TLBI is required */
1168 ret = 1;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001169 } else if (s2tte_is_assigned_destroyed(s2tte, level)) {
1170 if (change_destroyed == CHANGE_DESTROYED) {
1171 pa = s2tte_pa(s2tte, level);
1172 s2tte = s2tte_create_assigned_empty(pa, level);
1173 /* TLBI is required */
1174 ret = 1;
1175 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001176 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001177 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001178 } else {
1179 /* No action is required */
1180 return 0;
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001181 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001182 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001183 s2tte_write(s2ttep, s2tte);
1184 return ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001185}
1186
AlexeiFedorov960d1612023-04-25 13:23:39 +01001187void smc_rtt_init_ripas(unsigned long rd_addr,
1188 unsigned long base,
1189 unsigned long top,
1190 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001191{
1192 struct granule *g_rd, *g_rtt_root;
1193 struct rd *rd;
AlexeiFedorov960d1612023-04-25 13:23:39 +01001194 unsigned long ipa_bits, addr, map_size;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001195 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001196 unsigned long s2tte, *s2tt;
AlexeiFedorov960d1612023-04-25 13:23:39 +01001197 long level;
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001198 unsigned long index;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001199 int sl;
1200
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001201 if (top <= base) {
1202 res->x[0] = RMI_ERROR_INPUT;
1203 return;
1204 }
1205
Soby Mathewb4c6df42022-11-09 11:13:29 +00001206 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
1207 if (g_rd == NULL) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001208 res->x[0] = RMI_ERROR_INPUT;
1209 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001210 }
1211
1212 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001213 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001214
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001215 if (!validate_map_addr(base, S2TT_PAGE_LEVEL, rd) ||
1216 !validate_map_addr(top, S2TT_PAGE_LEVEL, rd) ||
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001217 !addr_in_par(rd, base) || !addr_in_par(rd, top - GRANULE_SIZE)) {
1218 buffer_unmap(rd);
1219 granule_unlock(g_rd);
1220 res->x[0] = RMI_ERROR_INPUT;
1221 return;
1222 }
1223
Mate Toth-Pal988dfcb2024-01-19 10:52:06 +01001224 if (get_rd_state_locked(rd) != REALM_NEW) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001225 buffer_unmap(rd);
1226 granule_unlock(g_rd);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001227 res->x[0] = RMI_ERROR_REALM;
1228 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001229 }
1230
Soby Mathewb4c6df42022-11-09 11:13:29 +00001231 g_rtt_root = rd->s2_ctx.g_rtt;
1232 sl = realm_rtt_starting_level(rd);
1233 ipa_bits = realm_ipa_bits(rd);
1234
1235 granule_lock(g_rtt_root, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001236
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001237 s2tt_walk_lock_unlock(g_rtt_root, sl, ipa_bits,
1238 base, S2TT_PAGE_LEVEL, &wi);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001239 level = wi.last_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001240 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001241 assert(s2tt != NULL);
1242
AlexeiFedorov960d1612023-04-25 13:23:39 +01001243 map_size = s2tte_map_size(level);
1244 addr = base & ~(map_size - 1UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001245
AlexeiFedorov960d1612023-04-25 13:23:39 +01001246 /*
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001247 * If the RTTE covers a range below "base", we need to go deeper.
AlexeiFedorov960d1612023-04-25 13:23:39 +01001248 */
1249 if (addr != base) {
1250 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1251 (unsigned int)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001252 goto out_unmap_llt;
1253 }
1254
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001255 for (index = wi.index; index < S2TTES_PER_S2TT; index++) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001256 unsigned long next = addr + map_size;
1257
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001258 /*
1259 * Break on "top_align" failure condition,
1260 * or if this entry crosses the range.
1261 */
AlexeiFedorov960d1612023-04-25 13:23:39 +01001262 if (next > top) {
1263 break;
1264 }
1265
1266 s2tte = s2tte_read(&s2tt[index]);
1267 if (s2tte_is_unassigned_empty(s2tte)) {
1268 s2tte = s2tte_create_unassigned_ram();
1269 s2tte_write(&s2tt[index], s2tte);
1270 } else if (!s2tte_is_unassigned_ram(s2tte)) {
1271 break;
1272 }
Mate Toth-Palc7698312023-08-09 12:49:34 +02001273 measurement_init_ripas_measure(rd->measurement[RIM_MEASUREMENT_SLOT],
1274 rd->algorithm,
1275 addr,
1276 next);
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001277 addr = next;
AlexeiFedorov960d1612023-04-25 13:23:39 +01001278 }
1279
1280 if (addr > base) {
1281 res->x[0] = RMI_SUCCESS;
1282 res->x[1] = addr;
1283 } else {
1284 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1285 (unsigned int)level);
1286 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001287
1288out_unmap_llt:
1289 buffer_unmap(s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001290 buffer_unmap(rd);
1291 granule_unlock(wi.g_llt);
AlexeiFedorov80295e42023-07-10 13:11:14 +01001292 granule_unlock(g_rd);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001293}
1294
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +00001295static void rtt_set_ripas_range(struct s2tt_context *s2_ctx,
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001296 unsigned long *s2tt,
1297 unsigned long base,
1298 unsigned long top,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001299 struct s2tt_walk *wi,
AlexeiFedorov4faab852023-08-30 15:06:49 +01001300 enum ripas ripas_val,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001301 enum ripas_change_destroyed change_destroyed,
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001302 struct smc_result *res)
1303{
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001304 unsigned long index;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001305 long level = wi->last_level;
AlexeiFedorov4faab852023-08-30 15:06:49 +01001306 unsigned long map_size = s2tte_map_size((int)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001307
1308 /* Align to the RTT level */
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001309 unsigned long addr = base & ~(map_size - 1UL);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001310
1311 /* Make sure we don't touch a range below the requested range */
1312 if (addr != base) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001313 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1314 (unsigned int)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001315 return;
1316 }
1317
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001318 for (index = wi->index; index < S2TTES_PER_S2TT; index++) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001319 int ret;
1320
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001321 /*
1322 * Break on "top_align" failure condition,
1323 * or if this entry crosses the range.
1324 */
1325 if ((addr + map_size) > top) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001326 break;
1327 }
1328
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001329 ret = update_ripas(&s2tt[index], level,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001330 ripas_val, change_destroyed);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001331 if (ret < 0) {
1332 break;
1333 }
1334
1335 /* Handle TLBI */
1336 if (ret != 0) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001337 if (level == S2TT_PAGE_LEVEL) {
1338 s2tt_invalidate_page(s2_ctx, addr);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001339 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001340 s2tt_invalidate_block(s2_ctx, addr);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001341 }
1342 }
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001343
1344 addr += map_size;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001345 }
1346
1347 if (addr > base) {
1348 res->x[0] = RMI_SUCCESS;
1349 res->x[1] = addr;
1350 } else {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001351 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1352 (unsigned int)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001353 }
1354}
1355
1356void smc_rtt_set_ripas(unsigned long rd_addr,
1357 unsigned long rec_addr,
1358 unsigned long base,
1359 unsigned long top,
1360 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001361{
1362 struct granule *g_rd, *g_rec, *g_rtt_root;
1363 struct rec *rec;
1364 struct rd *rd;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001365 unsigned long ipa_bits;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001366 struct s2tt_walk wi;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001367 unsigned long *s2tt;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +00001368 struct s2tt_context s2_ctx;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001369 enum ripas ripas_val;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001370 enum ripas_change_destroyed change_destroyed;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001371 int sl;
1372
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001373 if (top <= base) {
1374 res->x[0] = RMI_ERROR_INPUT;
1375 return;
1376 }
1377
Soby Mathewb4c6df42022-11-09 11:13:29 +00001378 if (!find_lock_two_granules(rd_addr,
1379 GRANULE_STATE_RD,
1380 &g_rd,
1381 rec_addr,
1382 GRANULE_STATE_REC,
1383 &g_rec)) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001384 res->x[0] = RMI_ERROR_INPUT;
1385 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001386 }
1387
1388 if (granule_refcount_read_acquire(g_rec) != 0UL) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001389 res->x[0] = RMI_ERROR_REC;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001390 goto out_unlock_rec_rd;
1391 }
1392
1393 rec = granule_map(g_rec, SLOT_REC);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001394 assert(rec != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001395
1396 if (g_rd != rec->realm_info.g_rd) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001397 res->x[0] = RMI_ERROR_REC;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001398 goto out_unmap_rec;
1399 }
1400
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001401 ripas_val = rec->set_ripas.ripas_val;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001402 change_destroyed = rec->set_ripas.change_destroyed;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001403
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001404 /*
1405 * Return error in case of target region:
1406 * - is not the next chunk of requested region
1407 * - extends beyond the end of requested region
1408 */
1409 if ((base != rec->set_ripas.addr) || (top > rec->set_ripas.top)) {
1410 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001411 goto out_unmap_rec;
1412 }
1413
1414 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001415 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001416
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001417 /*
1418 * At this point, we know base == rec->set_ripas.addr
1419 * and thus must be aligned to GRANULE size.
1420 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001421 assert(validate_map_addr(base, S2TT_PAGE_LEVEL, rd));
Soby Mathewb4c6df42022-11-09 11:13:29 +00001422
Soby Mathewb4c6df42022-11-09 11:13:29 +00001423 g_rtt_root = rd->s2_ctx.g_rtt;
1424 sl = realm_rtt_starting_level(rd);
1425 ipa_bits = realm_ipa_bits(rd);
1426 s2_ctx = rd->s2_ctx;
1427
1428 granule_lock(g_rtt_root, GRANULE_STATE_RTT);
1429
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001430 /* Walk to the deepest level possible */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001431 s2tt_walk_lock_unlock(g_rtt_root, sl, ipa_bits,
1432 base, S2TT_PAGE_LEVEL, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001433
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001434 /*
1435 * Base has to be aligned to the level at which
1436 * it is mapped in RTT.
1437 */
1438 if (!validate_map_addr(base, wi.last_level, rd)) {
1439 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1440 (unsigned int)wi.last_level);
1441 goto out_unlock_llt;
1442 }
1443
Soby Mathewb4c6df42022-11-09 11:13:29 +00001444 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001445 assert(s2tt != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001446
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001447 rtt_set_ripas_range(&s2_ctx, s2tt, base, top, &wi,
1448 ripas_val, change_destroyed, res);
1449
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001450 if (res->x[0] == RMI_SUCCESS) {
1451 rec->set_ripas.addr = res->x[1];
Soby Mathewb4c6df42022-11-09 11:13:29 +00001452 }
1453
Soby Mathewb4c6df42022-11-09 11:13:29 +00001454 buffer_unmap(s2tt);
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001455out_unlock_llt:
Soby Mathewb4c6df42022-11-09 11:13:29 +00001456 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001457 buffer_unmap(rd);
1458out_unmap_rec:
1459 buffer_unmap(rec);
1460out_unlock_rec_rd:
1461 granule_unlock(g_rec);
1462 granule_unlock(g_rd);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001463}