blob: 84e64bc79e5d498e3842b6902292d3c240de8675 [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 Sobrino2595cd82024-01-25 18:25:12 +000029 s2tte_is_addr_lvl_aligned(&(rd->s2_ctx), 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;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010085 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +000086 unsigned long *s2tt, *parent_s2tt, parent_s2tte;
87 long level = (long)ulevel;
Soby Mathewb4c6df42022-11-09 11:13:29 +000088 unsigned long ret;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +000089 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +000090
91 if (!find_lock_two_granules(rtt_addr,
92 GRANULE_STATE_DELEGATED,
93 &g_tbl,
94 rd_addr,
95 GRANULE_STATE_RD,
96 &g_rd)) {
97 return RMI_ERROR_INPUT;
98 }
99
100 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100101 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000102
103 if (!validate_rtt_structure_cmds(map_addr, level, rd)) {
104 buffer_unmap(rd);
105 granule_unlock(g_rd);
106 granule_unlock(g_tbl);
107 return RMI_ERROR_INPUT;
108 }
109
Soby Mathewb4c6df42022-11-09 11:13:29 +0000110 s2_ctx = rd->s2_ctx;
111 buffer_unmap(rd);
112
113 /*
114 * Lock the RTT root. Enforcing locking order RD->RTT is enough to
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000115 * ensure deadlock free locking guarantee.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000116 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000117 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000118
119 /* Unlock RD after locking RTT Root */
120 granule_unlock(g_rd);
121
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000122 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level - 1L, &wi);
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100123 if (wi.last_level != (level - 1L)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100124 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000125 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000126 goto out_unlock_llt;
127 }
128
129 parent_s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100130 assert(parent_s2tt != NULL);
131
Soby Mathewb4c6df42022-11-09 11:13:29 +0000132 parent_s2tte = s2tte_read(&parent_s2tt[wi.index]);
133 s2tt = granule_map(g_tbl, SLOT_DELEGATED);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100134 assert(s2tt != NULL);
135
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000136 if (s2tte_is_unassigned_empty(&s2_ctx, parent_s2tte)) {
137 s2tt_init_unassigned_empty(&s2_ctx, s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000138
139 /*
140 * Increase the refcount of the parent, the granule was
141 * locked while table walking and hand-over-hand locking.
142 * Atomicity and acquire/release semantics not required because
143 * the table is accessed always locked.
144 */
145 __granule_get(wi.g_llt);
146
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000147 } else if (s2tte_is_unassigned_ram(&s2_ctx, parent_s2tte)) {
148 s2tt_init_unassigned_ram(&s2_ctx, s2tt);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100149 __granule_get(wi.g_llt);
150
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000151 } else if (s2tte_is_unassigned_ns(&s2_ctx, parent_s2tte)) {
152 s2tt_init_unassigned_ns(&s2_ctx, s2tt);
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100153 __granule_get(wi.g_llt);
154
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000155 } else if (s2tte_is_unassigned_destroyed(&s2_ctx, parent_s2tte)) {
156 s2tt_init_unassigned_destroyed(&s2_ctx, s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000157 __granule_get(wi.g_llt);
158
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000159 } else if (s2tte_is_assigned_destroyed(&s2_ctx, parent_s2tte,
160 level - 1L)) {
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100161 unsigned long block_pa;
162
163 /*
164 * We should observe parent assigned s2tte only when
165 * we create tables above this level.
166 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100167 assert(level > S2TT_MIN_BLOCK_LEVEL);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100168
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000169 block_pa = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100170
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000171 s2tt_init_assigned_destroyed(&s2_ctx, s2tt, block_pa, level);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100172
173 /*
174 * Increase the refcount to mark the granule as in-use. refcount
175 * is incremented by S2TTES_PER_S2TT (ref RTT unfolding).
176 */
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000177 __granule_refcount_inc(g_tbl, (unsigned short)S2TTES_PER_S2TT);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100178
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000179 } else if (s2tte_is_assigned_empty(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000180 unsigned long block_pa;
181
182 /*
183 * We should observe parent assigned s2tte only when
184 * we create tables above this level.
185 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100186 assert(level > S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000187
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000188 block_pa = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000189
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000190 s2tt_init_assigned_empty(&s2_ctx, s2tt, block_pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000191
192 /*
193 * Increase the refcount to mark the granule as in-use. refcount
194 * is incremented by S2TTES_PER_S2TT (ref RTT unfolding).
195 */
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000196 __granule_refcount_inc(g_tbl, (unsigned short)S2TTES_PER_S2TT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000197
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000198 } else if (s2tte_is_assigned_ram(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000199 unsigned long block_pa;
200
201 /*
202 * We should observe parent valid s2tte only when
203 * we create tables above this level.
204 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100205 assert(level > S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000206
207 /*
208 * Break before make. This may cause spurious S2 aborts.
209 */
210 s2tte_write(&parent_s2tt[wi.index], 0UL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100211 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000212
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000213 block_pa = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000214
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000215 s2tt_init_assigned_ram(&s2_ctx, s2tt, block_pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000216
217 /*
218 * Increase the refcount to mark the granule as in-use. refcount
219 * is incremented by S2TTES_PER_S2TT (ref RTT unfolding).
220 */
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000221 __granule_refcount_inc(g_tbl, (unsigned short)S2TTES_PER_S2TT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000222
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000223 } else if (s2tte_is_assigned_ns(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000224 unsigned long block_pa;
225
226 /*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100227 * We should observe parent assigned_ns s2tte only when
Soby Mathewb4c6df42022-11-09 11:13:29 +0000228 * we create tables above this level.
229 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100230 assert(level > S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000231
232 /*
233 * Break before make. This may cause spurious S2 aborts.
234 */
235 s2tte_write(&parent_s2tt[wi.index], 0UL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100236 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000237
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000238 block_pa = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000239
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000240 s2tt_init_assigned_ns(&s2_ctx, s2tt, parent_s2tte,
241 block_pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000242
243 /*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100244 * Increment the refcount on the parent for the new RTT we are
245 * about to add. The NS block entry doesn't have a refcount
246 * on the parent RTT.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000247 */
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100248 __granule_get(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000249
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000250 } else if (s2tte_is_table(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000251 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000252 (unsigned char)(level - 1L));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000253 goto out_unmap_table;
254
255 } else {
256 assert(false);
257 }
258
259 ret = RMI_SUCCESS;
260
261 granule_set_state(g_tbl, GRANULE_STATE_RTT);
262
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000263 parent_s2tte = s2tte_create_table(&s2_ctx, rtt_addr, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000264 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
265
266out_unmap_table:
267 buffer_unmap(s2tt);
268 buffer_unmap(parent_s2tt);
269out_unlock_llt:
270 granule_unlock(wi.g_llt);
271 granule_unlock(g_tbl);
272 return ret;
273}
274
AlexeiFedorove2002be2023-04-19 17:20:12 +0100275void smc_rtt_fold(unsigned long rd_addr,
276 unsigned long map_addr,
277 unsigned long ulevel,
278 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000279{
280 struct granule *g_rd;
281 struct granule *g_tbl;
282 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100283 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000284 unsigned long *table, *parent_s2tt, parent_s2tte;
285 long level = (long)ulevel;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000286 unsigned long rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000287 unsigned long ret;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000288 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000289
290 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
291 if (g_rd == NULL) {
AlexeiFedorove2002be2023-04-19 17:20:12 +0100292 res->x[0] = RMI_ERROR_INPUT;
293 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000294 }
295
296 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100297 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000298
299 if (!validate_rtt_structure_cmds(map_addr, level, rd)) {
300 buffer_unmap(rd);
301 granule_unlock(g_rd);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100302 res->x[0] = RMI_ERROR_INPUT;
303 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000304 }
305
Soby Mathewb4c6df42022-11-09 11:13:29 +0000306 s2_ctx = rd->s2_ctx;
307 buffer_unmap(rd);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000308 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000309 granule_unlock(g_rd);
310
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000311 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level - 1L, &wi);
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100312 if (wi.last_level != (level - 1L)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100313 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000314 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000315 goto out_unlock_parent_table;
316 }
317
318 parent_s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100319 assert(parent_s2tt != NULL);
320
Soby Mathewb4c6df42022-11-09 11:13:29 +0000321 parent_s2tte = s2tte_read(&parent_s2tt[wi.index]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000322 if (!s2tte_is_table(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000323 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000324 (unsigned char)(level - 1L));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000325 goto out_unmap_parent_table;
326 }
327
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000328 rtt_addr = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000329 g_tbl = find_lock_granule(rtt_addr, GRANULE_STATE_RTT);
330
331 /*
332 * A table descriptor S2TTE always points to a TABLE granule.
333 */
AlexeiFedorov63b71692023-04-19 11:18:42 +0100334 assert(g_tbl != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000335
336 table = granule_map(g_tbl, SLOT_RTT2);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100337 assert(table != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000338
339 /*
340 * The command can succeed only if all 512 S2TTEs are of the same type.
341 * We first check the table's ref. counter to speed up the case when
342 * the host makes a guess whether a memory region can be folded.
343 */
344 if (g_tbl->refcount == 0UL) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000345 if (s2tt_is_unassigned_destroyed_block(&s2_ctx, table)) {
346 parent_s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
347 } else if (s2tt_is_unassigned_empty_block(&s2_ctx, table)) {
348 parent_s2tte = s2tte_create_unassigned_empty(&s2_ctx);
349 } else if (s2tt_is_unassigned_ram_block(&s2_ctx, table)) {
350 parent_s2tte = s2tte_create_unassigned_ram(&s2_ctx);
351 } else if (s2tt_is_unassigned_ns_block(&s2_ctx, table)) {
352 parent_s2tte = s2tte_create_unassigned_ns(&s2_ctx);
353 } else if (s2tt_maps_assigned_ns_block(&s2_ctx, table, level)) {
Shruti Gupta3105c3f2024-02-26 14:06:11 +0000354
355 /*
356 * The RMM specification does not allow creating block entries less than
357 * S2TT_MIN_BLOCK_LEVEL for ASSIGNED_NS state.
358 */
359 if (level <= S2TT_MIN_BLOCK_LEVEL) {
360 ret = pack_return_code(RMI_ERROR_RTT,
361 (unsigned char)wi.last_level);
362 goto out_unmap_table;
363 }
AlexeiFedorov49752c62023-04-24 14:31:14 +0100364 unsigned long s2tte = s2tte_read(&table[0]);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100365
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100366 /*
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100367 * Since s2tt_maps_assigned_ns_block() has succedded,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100368 * the PA in first entry of the table is aligned at
369 * parent level. Use the TTE from the first entry
370 * directly as it also has the NS attributes to be used
371 * for the parent block entry.
372 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000373 parent_s2tte = s2tte_create_assigned_ns(&s2_ctx, s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000374 } else {
375 /*
376 * The table holds a mixture of destroyed and
377 * unassigned entries.
378 */
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100379 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000380 (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000381 goto out_unmap_table;
382 }
AlexeiFedorov49752c62023-04-24 14:31:14 +0100383 __granule_put(wi.g_llt);
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000384 } else if (g_tbl->refcount == (unsigned short)S2TTES_PER_S2TT) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000385
386 unsigned long s2tte, block_pa;
387
388 /* The RMM specification does not allow creating block
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100389 * entries less than S2TT_MIN_BLOCK_LEVEL even though
Soby Mathewb4c6df42022-11-09 11:13:29 +0000390 * permitted by the Arm Architecture.
391 * Hence ensure that the table being folded is at a level
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100392 * higher than the S2TT_MIN_BLOCK_LEVEL.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000393 *
394 * A fully populated table cannot be destroyed if that
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100395 * would create a block mapping below S2TT_MIN_BLOCK_LEVEL.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000396 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100397 if (level <= S2TT_MIN_BLOCK_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100398 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000399 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000400 goto out_unmap_table;
401 }
402
403 s2tte = s2tte_read(&table[0]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000404 block_pa = s2tte_pa(&s2_ctx, s2tte, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000405
406 /*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100407 * The table must also refer to a contiguous block through the
AlexeiFedorov3f840a02023-07-19 10:55:05 +0100408 * same type of s2tte, either Assigned or Valid.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000409 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000410 if (s2tt_maps_assigned_empty_block(&s2_ctx, table, level)) {
411 parent_s2tte = s2tte_create_assigned_empty(&s2_ctx,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100412 block_pa, level - 1L);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000413 } else if (s2tt_maps_assigned_ram_block(&s2_ctx,
414 table, level)) {
415 parent_s2tte = s2tte_create_assigned_ram(&s2_ctx,
416 block_pa,
AlexeiFedorov3a739332023-04-13 13:54:04 +0100417 level - 1L);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000418 } else if (s2tt_maps_assigned_destroyed_block(&s2_ctx,
419 table, level)) {
420 parent_s2tte = s2tte_create_assigned_destroyed(&s2_ctx,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100421 block_pa, level - 1L);
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000422 /* The table contains mixed entries that cannot be folded */
Soby Mathewb4c6df42022-11-09 11:13:29 +0000423 } else {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100424 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000425 (unsigned char)level);
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000426 goto out_unmap_table;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000427 }
428
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000429 __granule_refcount_dec(g_tbl, (unsigned short)S2TTES_PER_S2TT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000430 } else {
431 /*
432 * The table holds a mixture of different types of s2ttes.
433 */
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100434 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000435 (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000436 goto out_unmap_table;
437 }
438
439 ret = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100440 res->x[1] = rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000441
442 /*
443 * Break before make.
444 */
445 s2tte_write(&parent_s2tt[wi.index], 0UL);
446
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000447 if (s2tte_is_assigned_ram(&s2_ctx, parent_s2tte, level - 1L) ||
448 s2tte_is_assigned_ns(&s2_ctx, parent_s2tte, level - 1L)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100449 s2tt_invalidate_pages_in_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000450 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100451 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000452 }
453
454 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
455
456 granule_memzero_mapped(table);
457 granule_set_state(g_tbl, GRANULE_STATE_DELEGATED);
458
459out_unmap_table:
460 buffer_unmap(table);
461 granule_unlock(g_tbl);
462out_unmap_parent_table:
463 buffer_unmap(parent_s2tt);
464out_unlock_parent_table:
465 granule_unlock(wi.g_llt);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100466 res->x[0] = ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000467}
468
AlexeiFedorove2002be2023-04-19 17:20:12 +0100469void smc_rtt_destroy(unsigned long rd_addr,
470 unsigned long map_addr,
471 unsigned long ulevel,
472 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000473{
474 struct granule *g_rd;
475 struct granule *g_tbl;
476 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100477 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000478 unsigned long *table, *parent_s2tt, parent_s2tte;
479 long level = (long)ulevel;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000480 unsigned long rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000481 unsigned long ret;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000482 struct s2tt_context s2_ctx;
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
Soby Mathewb4c6df42022-11-09 11:13:29 +0000503 s2_ctx = rd->s2_ctx;
504 in_par = addr_in_par(rd, map_addr);
505 buffer_unmap(rd);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000506 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000507 granule_unlock(g_rd);
508
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000509 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level - 1L, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000510
511 parent_s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100512 assert(parent_s2tt != NULL);
513
Soby Mathewb4c6df42022-11-09 11:13:29 +0000514 parent_s2tte = s2tte_read(&parent_s2tt[wi.index]);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100515
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100516 if ((wi.last_level != (level - 1L)) ||
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000517 !s2tte_is_table(&s2_ctx, parent_s2tte, level - 1L)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100518 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000519 (unsigned char)wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100520 skip_non_live = true;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000521 goto out_unmap_parent_table;
522 }
523
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000524 rtt_addr = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000525
526 /*
527 * Lock the RTT granule. The 'rtt_addr' is verified, thus can be treated
528 * as an internal granule.
529 */
530 g_tbl = find_lock_granule(rtt_addr, GRANULE_STATE_RTT);
531
532 /*
533 * A table descriptor S2TTE always points to a TABLE granule.
534 */
535 assert(g_tbl != NULL);
536
537 /*
538 * Read the refcount value. RTT granule is always accessed locked, thus
539 * the refcount can be accessed without atomic operations.
540 */
541 if (g_tbl->refcount != 0UL) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000542 ret = pack_return_code(RMI_ERROR_RTT, (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000543 goto out_unlock_table;
544 }
545
546 ret = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100547 res->x[1] = rtt_addr;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100548 skip_non_live = true;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000549
550 table = granule_map(g_tbl, SLOT_RTT2);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100551 assert(table != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000552
553 if (in_par) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000554 parent_s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000555 } else {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000556 parent_s2tte = s2tte_create_unassigned_ns(&s2_ctx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000557 }
558
559 __granule_put(wi.g_llt);
560
561 /*
562 * Break before make. Note that this may cause spurious S2 aborts.
563 */
564 s2tte_write(&parent_s2tt[wi.index], 0UL);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000565
566 if (in_par) {
567 /* For protected IPA, all S2TTEs in the RTT will be invalid */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100568 s2tt_invalidate_block(&s2_ctx, map_addr);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000569 } else {
570 /*
571 * For unprotected IPA, invalidate the TLB for the entire range
572 * mapped by the RTT as it may have valid NS mappings.
573 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100574 s2tt_invalidate_pages_in_block(&s2_ctx, map_addr);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000575 }
576
Soby Mathewb4c6df42022-11-09 11:13:29 +0000577 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
578
579 granule_memzero_mapped(table);
580 granule_set_state(g_tbl, GRANULE_STATE_DELEGATED);
581
582 buffer_unmap(table);
583out_unlock_table:
584 granule_unlock(g_tbl);
585out_unmap_parent_table:
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100586 if (skip_non_live) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000587 res->x[2] = s2tt_skip_non_live_entries(&s2_ctx, map_addr,
588 parent_s2tt, &wi);
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100589 } else {
590 res->x[2] = map_addr;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100591 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000592 buffer_unmap(parent_s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000593 granule_unlock(wi.g_llt);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100594 res->x[0] = ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000595}
596
597enum map_unmap_ns_op {
598 MAP_NS,
599 UNMAP_NS
600};
601
602/*
603 * We don't hold a reference on the NS granule when it is
604 * mapped into a realm. Instead we rely on the guarantees
605 * provided by the architecture to ensure that a NS access
606 * to a protected granule is prohibited even within the realm.
607 */
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100608static void map_unmap_ns(unsigned long rd_addr,
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000609 unsigned long map_addr,
610 long level,
611 unsigned long host_s2tte,
612 enum map_unmap_ns_op op,
613 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000614{
615 struct granule *g_rd;
616 struct rd *rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000617 unsigned long *s2tt, s2tte;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100618 struct s2tt_walk wi;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000619 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000620
621 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
622 if (g_rd == NULL) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100623 res->x[0] = RMI_ERROR_INPUT;
624 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000625 }
626
627 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100628 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000629
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000630 s2_ctx = rd->s2_ctx;
631
632 if (op == MAP_NS) {
633 if (!host_ns_s2tte_is_valid(&s2_ctx, host_s2tte, level)) {
634 buffer_unmap(rd);
635 granule_unlock(g_rd);
636 res->x[0] = RMI_ERROR_INPUT;
637 return;
638 }
639 }
640
641
Soby Mathewb4c6df42022-11-09 11:13:29 +0000642 if (!validate_rtt_map_cmds(map_addr, level, rd)) {
643 buffer_unmap(rd);
644 granule_unlock(g_rd);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100645 res->x[0] = RMI_ERROR_INPUT;
646 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000647 }
648
AlexeiFedorovc34e3242023-04-12 11:30:33 +0100649 /* Check if map_addr is outside PAR */
650 if (addr_in_par(rd, map_addr)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000651 buffer_unmap(rd);
652 granule_unlock(g_rd);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100653 res->x[0] = RMI_ERROR_INPUT;
654 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000655 }
656
Soby Mathewb4c6df42022-11-09 11:13:29 +0000657 buffer_unmap(rd);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000658 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000659 granule_unlock(g_rd);
660
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000661 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level, &wi);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100662
663 /*
664 * For UNMAP_NS, we need to map the table and look
665 * for the end of the non-live region.
666 */
AlexeiFedorov14d47ae2023-07-19 15:26:50 +0100667 if ((op == MAP_NS) && (wi.last_level != level)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100668 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000669 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000670 goto out_unlock_llt;
671 }
672
673 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100674 assert(s2tt != NULL);
675
Soby Mathewb4c6df42022-11-09 11:13:29 +0000676 s2tte = s2tte_read(&s2tt[wi.index]);
677
678 if (op == MAP_NS) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000679 if (!s2tte_is_unassigned_ns(&s2_ctx, s2tte)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100680 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000681 (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000682 goto out_unmap_table;
683 }
684
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000685 s2tte = s2tte_create_assigned_ns(&s2_ctx, host_s2tte, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000686 s2tte_write(&s2tt[wi.index], s2tte);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000687
688 } else if (op == UNMAP_NS) {
689 /*
690 * The following check also verifies that map_addr is outside
691 * PAR, as valid_NS s2tte may only cover outside PAR IPA range.
692 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000693 bool assigned_ns = s2tte_is_assigned_ns(&s2_ctx, s2tte,
694 wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100695
696 if ((wi.last_level != level) || !assigned_ns) {
697 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000698 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000699 goto out_unmap_table;
700 }
701
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000702 s2tte = s2tte_create_unassigned_ns(&s2_ctx);
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 Sobrino2595cd82024-01-25 18:25:12 +0000715 res->x[1] = s2tt_skip_non_live_entries(&s2_ctx, map_addr,
716 s2tt, &wi);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100717 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000718 buffer_unmap(s2tt);
719out_unlock_llt:
720 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000721}
722
723unsigned long smc_rtt_map_unprotected(unsigned long rd_addr,
724 unsigned long map_addr,
725 unsigned long ulevel,
726 unsigned long s2tte)
727{
728 long level = (long)ulevel;
Shruti Gupta9e966b82024-03-21 13:45:24 +0000729 struct smc_result res;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000730
Shruti Gupta9e966b82024-03-21 13:45:24 +0000731 (void)memset(&res, 0, sizeof(struct smc_result));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100732 if ((level < S2TT_MIN_BLOCK_LEVEL) || (level > S2TT_PAGE_LEVEL)) {
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100733 return RMI_ERROR_INPUT;
734 }
735
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100736 map_unmap_ns(rd_addr, map_addr, level, s2tte, MAP_NS, &res);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000737
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100738 return res.x[0];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000739}
740
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100741void smc_rtt_unmap_unprotected(unsigned long rd_addr,
742 unsigned long map_addr,
743 unsigned long ulevel,
744 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000745{
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100746 long level = (long)ulevel;
747
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100748 if ((level < S2TT_MIN_BLOCK_LEVEL) || (level > S2TT_PAGE_LEVEL)) {
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100749 res->x[0] = RMI_ERROR_INPUT;
750 return;
751 }
752
753 map_unmap_ns(rd_addr, map_addr, level, 0UL, UNMAP_NS, res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000754}
755
756void smc_rtt_read_entry(unsigned long rd_addr,
757 unsigned long map_addr,
758 unsigned long ulevel,
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100759 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000760{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000761 struct granule *g_rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000762 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100763 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000764 unsigned long *s2tt, s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000765 long level = (long)ulevel;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000766 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000767
768 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
769 if (g_rd == NULL) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100770 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000771 return;
772 }
773
774 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100775 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000776
777 if (!validate_rtt_entry_cmds(map_addr, level, rd)) {
778 buffer_unmap(rd);
779 granule_unlock(g_rd);
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100780 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000781 return;
782 }
783
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000784 s2_ctx = rd->s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000785 buffer_unmap(rd);
786
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000787 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000788 granule_unlock(g_rd);
789
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000790 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000791 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100792 assert(s2tt != NULL);
793
Soby Mathewb4c6df42022-11-09 11:13:29 +0000794 s2tte = s2tte_read(&s2tt[wi.index]);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100795 res->x[1] = (unsigned long)wi.last_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000796
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000797 if (s2tte_is_unassigned_empty(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100798 res->x[2] = RMI_UNASSIGNED;
799 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100800 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000801 } else if (s2tte_is_unassigned_ram(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100802 res->x[2] = RMI_UNASSIGNED;
803 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100804 res->x[4] = (unsigned long)RIPAS_RAM;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000805 } else if (s2tte_is_unassigned_destroyed(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100806 res->x[2] = RMI_UNASSIGNED;
807 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100808 res->x[4] = (unsigned long)RIPAS_DESTROYED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000809 } else if (s2tte_is_assigned_empty(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100810 res->x[2] = RMI_ASSIGNED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000811 res->x[3] = s2tte_pa(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100812 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000813 } else if (s2tte_is_assigned_ram(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100814 res->x[2] = RMI_ASSIGNED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000815 res->x[3] = s2tte_pa(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100816 res->x[4] = (unsigned long)RIPAS_RAM;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000817 } else if (s2tte_is_assigned_destroyed(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100818 res->x[2] = RMI_ASSIGNED;
819 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100820 res->x[4] = (unsigned long)RIPAS_DESTROYED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000821 } else if (s2tte_is_unassigned_ns(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100822 res->x[2] = RMI_UNASSIGNED;
823 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100824 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000825 } else if (s2tte_is_assigned_ns(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100826 res->x[2] = RMI_ASSIGNED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000827 res->x[3] = host_ns_s2tte(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100828 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000829 } else if (s2tte_is_table(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100830 res->x[2] = RMI_TABLE;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000831 res->x[3] = s2tte_pa(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100832 res->x[4] = (unsigned long)RIPAS_EMPTY;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000833 } else {
834 assert(false);
835 }
836
837 buffer_unmap(s2tt);
838 granule_unlock(wi.g_llt);
839
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100840 res->x[0] = RMI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000841}
842
Soby Mathewb4c6df42022-11-09 11:13:29 +0000843static unsigned long validate_data_create_unknown(unsigned long map_addr,
844 struct rd *rd)
845{
846 if (!addr_in_par(rd, map_addr)) {
847 return RMI_ERROR_INPUT;
848 }
849
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100850 if (!validate_map_addr(map_addr, S2TT_PAGE_LEVEL, rd)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000851 return RMI_ERROR_INPUT;
852 }
853
854 return RMI_SUCCESS;
855}
856
857static unsigned long validate_data_create(unsigned long map_addr,
858 struct rd *rd)
859{
Mate Toth-Pal988dfcb2024-01-19 10:52:06 +0100860 if (get_rd_state_locked(rd) != REALM_NEW) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000861 return RMI_ERROR_REALM;
862 }
863
864 return validate_data_create_unknown(map_addr, rd);
865}
866
867/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100868 * Implements both RMI_DATA_CREATE and RMI_DATA_CREATE_UNKNOWN
Soby Mathewb4c6df42022-11-09 11:13:29 +0000869 *
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100870 * if @g_src == NULL, implements RMI_DATA_CREATE_UNKNOWN
871 * and RMI_DATA_CREATE otherwise.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000872 */
AlexeiFedorovac923c82023-04-06 15:12:04 +0100873static unsigned long data_create(unsigned long rd_addr,
874 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000875 unsigned long map_addr,
876 struct granule *g_src,
877 unsigned long flags)
878{
879 struct granule *g_data;
880 struct granule *g_rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000881 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100882 struct s2tt_walk wi;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000883 struct s2tt_context *s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000884 unsigned long s2tte, *s2tt;
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000885 unsigned char new_data_state = GRANULE_STATE_DELEGATED;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000886 unsigned long ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000887
888 if (!find_lock_two_granules(data_addr,
889 GRANULE_STATE_DELEGATED,
890 &g_data,
891 rd_addr,
892 GRANULE_STATE_RD,
893 &g_rd)) {
894 return RMI_ERROR_INPUT;
895 }
896
897 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100898 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000899
900 ret = (g_src != NULL) ?
901 validate_data_create(map_addr, rd) :
902 validate_data_create_unknown(map_addr, rd);
903
904 if (ret != RMI_SUCCESS) {
905 goto out_unmap_rd;
906 }
907
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000908 s2_ctx = &(rd->s2_ctx);
909 granule_lock(s2_ctx->g_rtt, GRANULE_STATE_RTT);
910
911 s2tt_walk_lock_unlock(s2_ctx, map_addr, S2TT_PAGE_LEVEL, &wi);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100912 if (wi.last_level != S2TT_PAGE_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100913 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000914 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000915 goto out_unlock_ll_table;
916 }
917
918 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100919 assert(s2tt != NULL);
920
Soby Mathewb4c6df42022-11-09 11:13:29 +0000921 s2tte = s2tte_read(&s2tt[wi.index]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000922 if (!s2tte_is_unassigned(s2_ctx, s2tte)) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000923 ret = pack_return_code(RMI_ERROR_RTT,
924 (unsigned char)S2TT_PAGE_LEVEL);
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100925 goto out_unmap_ll_table;
926 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000927
Soby Mathewb4c6df42022-11-09 11:13:29 +0000928 if (g_src != NULL) {
929 bool ns_access_ok;
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100930 void *data = granule_map(g_data, SLOT_DELEGATED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000931
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100932 assert(data != NULL);
933
Soby Mathewb4c6df42022-11-09 11:13:29 +0000934 ns_access_ok = ns_buffer_read(SLOT_NS, g_src, 0U,
935 GRANULE_SIZE, data);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000936 if (!ns_access_ok) {
937 /*
938 * Some data may be copied before the failure. Zero
939 * g_data granule as it will remain in delegated state.
940 */
AlexeiFedorov862f96c2024-03-01 16:26:48 +0000941 granule_memzero_mapped(data);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000942 buffer_unmap(data);
943 ret = RMI_ERROR_INPUT;
944 goto out_unmap_ll_table;
945 }
946
Mate Toth-Palc7698312023-08-09 12:49:34 +0200947 measurement_data_granule_measure(
948 rd->measurement[RIM_MEASUREMENT_SLOT],
949 rd->algorithm,
950 data,
951 map_addr,
952 flags);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000953 buffer_unmap(data);
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100954
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000955 s2tte = s2tte_create_assigned_ram(s2_ctx, data_addr,
956 S2TT_PAGE_LEVEL);
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100957 } else {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000958 s2tte = s2tte_create_assigned_unchanged(s2_ctx, s2tte,
959 data_addr,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100960 S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000961 }
962
963 new_data_state = GRANULE_STATE_DATA;
964
Soby Mathewb4c6df42022-11-09 11:13:29 +0000965 s2tte_write(&s2tt[wi.index], s2tte);
966 __granule_get(wi.g_llt);
967
968 ret = RMI_SUCCESS;
969
970out_unmap_ll_table:
971 buffer_unmap(s2tt);
972out_unlock_ll_table:
973 granule_unlock(wi.g_llt);
974out_unmap_rd:
975 buffer_unmap(rd);
976 granule_unlock(g_rd);
977 granule_unlock_transition(g_data, new_data_state);
978 return ret;
979}
980
AlexeiFedorovac923c82023-04-06 15:12:04 +0100981unsigned long smc_data_create(unsigned long rd_addr,
982 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000983 unsigned long map_addr,
984 unsigned long src_addr,
985 unsigned long flags)
986{
987 struct granule *g_src;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000988
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100989 if ((flags != RMI_NO_MEASURE_CONTENT) &&
990 (flags != RMI_MEASURE_CONTENT)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000991 return RMI_ERROR_INPUT;
992 }
993
994 g_src = find_granule(src_addr);
995 if ((g_src == NULL) || (g_src->state != GRANULE_STATE_NS)) {
996 return RMI_ERROR_INPUT;
997 }
998
AlexeiFedorovac923c82023-04-06 15:12:04 +0100999 return data_create(rd_addr, data_addr, map_addr, g_src, flags);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001000}
1001
AlexeiFedorovac923c82023-04-06 15:12:04 +01001002unsigned long smc_data_create_unknown(unsigned long rd_addr,
1003 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +00001004 unsigned long map_addr)
1005{
AlexeiFedorovac923c82023-04-06 15:12:04 +01001006 return data_create(rd_addr, data_addr, map_addr, NULL, 0);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001007}
1008
AlexeiFedorove2002be2023-04-19 17:20:12 +01001009void smc_data_destroy(unsigned long rd_addr,
1010 unsigned long map_addr,
1011 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001012{
1013 struct granule *g_data;
1014 struct granule *g_rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001015 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001016 unsigned long data_addr, s2tte, *s2tt;
1017 struct rd *rd;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +00001018 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001019
1020 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
1021 if (g_rd == NULL) {
AlexeiFedorove2002be2023-04-19 17:20:12 +01001022 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorova1b2a1d2023-07-18 15:08:47 +01001023 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001024 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001025 }
1026
1027 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001028 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001029
AlexeiFedorov868a6512023-09-14 13:21:11 +01001030 if (!addr_in_par(rd, map_addr) ||
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001031 !validate_map_addr(map_addr, S2TT_PAGE_LEVEL, rd)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001032 buffer_unmap(rd);
1033 granule_unlock(g_rd);
AlexeiFedorove2002be2023-04-19 17:20:12 +01001034 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorova1b2a1d2023-07-18 15:08:47 +01001035 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001036 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001037 }
1038
Soby Mathewb4c6df42022-11-09 11:13:29 +00001039 s2_ctx = rd->s2_ctx;
1040 buffer_unmap(rd);
1041
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001042 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001043 granule_unlock(g_rd);
1044
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001045 s2tt_walk_lock_unlock(&s2_ctx, map_addr, S2TT_PAGE_LEVEL, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001046 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001047 assert(s2tt != NULL);
1048
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001049 if (wi.last_level != S2TT_PAGE_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001050 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001051 (unsigned char)wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001052 goto out_unmap_ll_table;
1053 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001054
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001055 s2tte = s2tte_read(&s2tt[wi.index]);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001056
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001057 if (s2tte_is_assigned_ram(&s2_ctx, s2tte, S2TT_PAGE_LEVEL)) {
1058 data_addr = s2tte_pa(&s2_ctx, s2tte, S2TT_PAGE_LEVEL);
1059 s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001060 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001061 s2tt_invalidate_page(&s2_ctx, map_addr);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001062 } else if (s2tte_is_assigned_empty(&s2_ctx, s2tte, S2TT_PAGE_LEVEL)) {
1063 data_addr = s2tte_pa(&s2_ctx, s2tte, S2TT_PAGE_LEVEL);
1064 s2tte = s2tte_create_unassigned_empty(&s2_ctx);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001065 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001066 } else if (s2tte_is_assigned_destroyed(&s2_ctx, s2tte,
1067 S2TT_PAGE_LEVEL)) {
1068 data_addr = s2tte_pa(&s2_ctx, s2tte, S2TT_PAGE_LEVEL);
1069 s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +01001070 s2tte_write(&s2tt[wi.index], s2tte);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001071 } else {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001072 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1073 (unsigned char)S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001074 goto out_unmap_ll_table;
1075 }
1076
Soby Mathewb4c6df42022-11-09 11:13:29 +00001077 __granule_put(wi.g_llt);
1078
1079 /*
1080 * Lock the data granule and check expected state. Correct locking order
1081 * is guaranteed because granule address is obtained from a locked
1082 * granule by table walk. This lock needs to be acquired before a state
1083 * transition to or from GRANULE_STATE_DATA for granule address can happen.
1084 */
1085 g_data = find_lock_granule(data_addr, GRANULE_STATE_DATA);
AlexeiFedorov63b71692023-04-19 11:18:42 +01001086 assert(g_data != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001087 granule_memzero(g_data, SLOT_DELEGATED);
1088 granule_unlock_transition(g_data, GRANULE_STATE_DELEGATED);
1089
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001090 res->x[0] = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001091 res->x[1] = data_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001092out_unmap_ll_table:
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001093 res->x[2] = s2tt_skip_non_live_entries(&s2_ctx, map_addr, s2tt, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001094 buffer_unmap(s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001095 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001096}
1097
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001098/*
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001099 * Update the ripas value for the entry pointed by @s2ttep.
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001100 *
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001101 * Returns:
1102 * < 0 - On error and the operation was aborted,
1103 * e.g., entry cannot have a ripas.
1104 * 0 - Operation was success and no TLBI is required.
1105 * > 0 - Operation was success and TLBI is required.
1106 * Sets:
1107 * @(*do_tlbi) to 'true' if the TLBs have to be invalidated.
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001108 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001109static int update_ripas(const struct s2tt_context *s2_ctx,
1110 unsigned long *s2ttep, long level,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001111 enum ripas ripas_val,
1112 enum ripas_change_destroyed change_destroyed)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001113{
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001114 unsigned long pa, s2tte = s2tte_read(s2ttep);
1115 int ret = 0;
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001116
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001117 assert(s2_ctx != NULL);
1118
1119 if (!s2tte_has_ripas(s2_ctx, s2tte, level)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001120 return -EPERM;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001121 }
1122
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001123 if (ripas_val == RIPAS_RAM) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001124 if (s2tte_is_unassigned_empty(s2_ctx, s2tte)) {
1125 s2tte = s2tte_create_unassigned_ram(s2_ctx);
1126 } else if (s2tte_is_unassigned_destroyed(s2_ctx, s2tte)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001127 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001128 s2tte = s2tte_create_unassigned_ram(s2_ctx);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001129 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001130 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001131 }
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001132 } else if (s2tte_is_assigned_empty(s2_ctx, s2tte, level)) {
1133 pa = s2tte_pa(s2_ctx, s2tte, level);
1134 s2tte = s2tte_create_assigned_ram(s2_ctx, pa, level);
1135 } else if (s2tte_is_assigned_destroyed(s2_ctx, s2tte, level)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001136 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001137 pa = s2tte_pa(s2_ctx, s2tte, level);
1138 s2tte = s2tte_create_assigned_ram(s2_ctx, pa,
1139 level);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001140 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001141 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001142 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001143 } else {
1144 /* No action is required */
1145 return 0;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001146 }
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001147 } else if (ripas_val == RIPAS_EMPTY) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001148 if (s2tte_is_unassigned_ram(s2_ctx, s2tte)) {
1149 s2tte = s2tte_create_unassigned_empty(s2_ctx);
1150 } else if (s2tte_is_unassigned_destroyed(s2_ctx, s2tte)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001151 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001152 s2tte = s2tte_create_unassigned_empty(s2_ctx);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001153 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001154 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001155 }
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001156 } else if (s2tte_is_assigned_ram(s2_ctx, s2tte, level)) {
1157 pa = s2tte_pa(s2_ctx, s2tte, level);
1158 s2tte = s2tte_create_assigned_empty(s2_ctx, pa, level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001159 /* TLBI is required */
1160 ret = 1;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001161 } else if (s2tte_is_assigned_destroyed(s2_ctx, s2tte, level)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001162 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001163 pa = s2tte_pa(s2_ctx, s2tte, level);
1164 s2tte = s2tte_create_assigned_empty(s2_ctx,
1165 pa, level);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001166 /* TLBI is required */
1167 ret = 1;
1168 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001169 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001170 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001171 } else {
1172 /* No action is required */
1173 return 0;
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001174 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001175 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001176 s2tte_write(s2ttep, s2tte);
1177 return ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001178}
1179
AlexeiFedorov960d1612023-04-25 13:23:39 +01001180void smc_rtt_init_ripas(unsigned long rd_addr,
1181 unsigned long base,
1182 unsigned long top,
1183 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001184{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001185 struct granule *g_rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001186 struct rd *rd;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001187 unsigned long addr, map_size;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001188 struct s2tt_walk wi;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001189 struct s2tt_context *s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001190 unsigned long s2tte, *s2tt;
AlexeiFedorov960d1612023-04-25 13:23:39 +01001191 long level;
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001192 unsigned long index;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001193 unsigned int s2ttes_per_s2tt;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001194
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001195 if (top <= base) {
1196 res->x[0] = RMI_ERROR_INPUT;
1197 return;
1198 }
1199
Soby Mathewb4c6df42022-11-09 11:13:29 +00001200 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
1201 if (g_rd == NULL) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001202 res->x[0] = RMI_ERROR_INPUT;
1203 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001204 }
1205
1206 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001207 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001208
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001209 if (!validate_map_addr(base, S2TT_PAGE_LEVEL, rd) ||
1210 !validate_map_addr(top, S2TT_PAGE_LEVEL, rd) ||
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001211 !addr_in_par(rd, base) || !addr_in_par(rd, top - GRANULE_SIZE)) {
1212 buffer_unmap(rd);
1213 granule_unlock(g_rd);
1214 res->x[0] = RMI_ERROR_INPUT;
1215 return;
1216 }
1217
Mate Toth-Pal988dfcb2024-01-19 10:52:06 +01001218 if (get_rd_state_locked(rd) != REALM_NEW) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001219 buffer_unmap(rd);
1220 granule_unlock(g_rd);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001221 res->x[0] = RMI_ERROR_REALM;
1222 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001223 }
1224
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001225 s2_ctx = &(rd->s2_ctx);
1226 granule_lock(s2_ctx->g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001227
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001228 s2tt_walk_lock_unlock(s2_ctx, base, S2TT_PAGE_LEVEL, &wi);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001229 level = wi.last_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001230 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001231 assert(s2tt != NULL);
1232
AlexeiFedorov960d1612023-04-25 13:23:39 +01001233 map_size = s2tte_map_size(level);
1234 addr = base & ~(map_size - 1UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001235
AlexeiFedorov960d1612023-04-25 13:23:39 +01001236 /*
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001237 * If the RTTE covers a range below "base", we need to go deeper.
AlexeiFedorov960d1612023-04-25 13:23:39 +01001238 */
1239 if (addr != base) {
1240 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001241 (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001242 goto out_unmap_llt;
1243 }
1244
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001245 s2ttes_per_s2tt =
1246 (unsigned int)((level == S2TT_MIN_STARTING_LEVEL_LPA2) ?
1247 S2TTES_PER_S2TT_LM1 : S2TTES_PER_S2TT);
1248 for (index = wi.index; index < s2ttes_per_s2tt; index++) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001249 unsigned long next = addr + map_size;
1250
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001251 /*
1252 * Break on "top_align" failure condition,
1253 * or if this entry crosses the range.
1254 */
AlexeiFedorov960d1612023-04-25 13:23:39 +01001255 if (next > top) {
1256 break;
1257 }
1258
1259 s2tte = s2tte_read(&s2tt[index]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001260 if (s2tte_is_unassigned_empty(s2_ctx, s2tte)) {
1261 s2tte = s2tte_create_unassigned_ram(s2_ctx);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001262 s2tte_write(&s2tt[index], s2tte);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001263 } else if (!s2tte_is_unassigned_ram(s2_ctx, s2tte)) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001264 break;
1265 }
Mate Toth-Palc7698312023-08-09 12:49:34 +02001266 measurement_init_ripas_measure(rd->measurement[RIM_MEASUREMENT_SLOT],
1267 rd->algorithm,
1268 addr,
1269 next);
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001270 addr = next;
AlexeiFedorov960d1612023-04-25 13:23:39 +01001271 }
1272
1273 if (addr > base) {
1274 res->x[0] = RMI_SUCCESS;
1275 res->x[1] = addr;
1276 } else {
1277 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001278 (unsigned char)level);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001279 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001280
1281out_unmap_llt:
1282 buffer_unmap(s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001283 buffer_unmap(rd);
1284 granule_unlock(wi.g_llt);
AlexeiFedorov80295e42023-07-10 13:11:14 +01001285 granule_unlock(g_rd);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001286}
1287
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +00001288static void rtt_set_ripas_range(struct s2tt_context *s2_ctx,
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001289 unsigned long *s2tt,
1290 unsigned long base,
1291 unsigned long top,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001292 struct s2tt_walk *wi,
AlexeiFedorov4faab852023-08-30 15:06:49 +01001293 enum ripas ripas_val,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001294 enum ripas_change_destroyed change_destroyed,
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001295 struct smc_result *res)
1296{
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001297 unsigned long index;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001298 long level = wi->last_level;
AlexeiFedorov4faab852023-08-30 15:06:49 +01001299 unsigned long map_size = s2tte_map_size((int)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001300
1301 /* Align to the RTT level */
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001302 unsigned long addr = base & ~(map_size - 1UL);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001303
1304 /* Make sure we don't touch a range below the requested range */
1305 if (addr != base) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001306 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001307 (unsigned char)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001308 return;
1309 }
1310
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001311 for (index = wi->index; index < S2TTES_PER_S2TT; index++) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001312 int ret;
1313
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001314 /*
1315 * Break on "top_align" failure condition,
1316 * or if this entry crosses the range.
1317 */
1318 if ((addr + map_size) > top) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001319 break;
1320 }
1321
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001322 ret = update_ripas(s2_ctx, &s2tt[index], level,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001323 ripas_val, change_destroyed);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001324 if (ret < 0) {
1325 break;
1326 }
1327
1328 /* Handle TLBI */
1329 if (ret != 0) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001330 if (level == S2TT_PAGE_LEVEL) {
1331 s2tt_invalidate_page(s2_ctx, addr);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001332 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001333 s2tt_invalidate_block(s2_ctx, addr);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001334 }
1335 }
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001336
1337 addr += map_size;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001338 }
1339
1340 if (addr > base) {
1341 res->x[0] = RMI_SUCCESS;
1342 res->x[1] = addr;
1343 } else {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001344 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001345 (unsigned char)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001346 }
1347}
1348
1349void smc_rtt_set_ripas(unsigned long rd_addr,
1350 unsigned long rec_addr,
1351 unsigned long base,
1352 unsigned long top,
1353 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001354{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001355 struct granule *g_rd, *g_rec;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001356 struct rec *rec;
1357 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001358 struct s2tt_walk wi;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001359 unsigned long *s2tt;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001360 struct s2tt_context *s2_ctx;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001361 enum ripas ripas_val;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001362 enum ripas_change_destroyed change_destroyed;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001363
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001364 if (top <= base) {
1365 res->x[0] = RMI_ERROR_INPUT;
1366 return;
1367 }
1368
Soby Mathewb4c6df42022-11-09 11:13:29 +00001369 if (!find_lock_two_granules(rd_addr,
1370 GRANULE_STATE_RD,
1371 &g_rd,
1372 rec_addr,
1373 GRANULE_STATE_REC,
1374 &g_rec)) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001375 res->x[0] = RMI_ERROR_INPUT;
1376 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001377 }
1378
AlexeiFedorovd6d93d82024-02-13 16:52:11 +00001379 if (granule_refcount_read_acquire(g_rec) != 0U) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001380 res->x[0] = RMI_ERROR_REC;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001381 goto out_unlock_rec_rd;
1382 }
1383
1384 rec = granule_map(g_rec, SLOT_REC);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001385 assert(rec != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001386
1387 if (g_rd != rec->realm_info.g_rd) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001388 res->x[0] = RMI_ERROR_REC;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001389 goto out_unmap_rec;
1390 }
1391
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001392 ripas_val = rec->set_ripas.ripas_val;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001393 change_destroyed = rec->set_ripas.change_destroyed;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001394
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001395 /*
1396 * Return error in case of target region:
1397 * - is not the next chunk of requested region
1398 * - extends beyond the end of requested region
1399 */
1400 if ((base != rec->set_ripas.addr) || (top > rec->set_ripas.top)) {
1401 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001402 goto out_unmap_rec;
1403 }
1404
1405 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001406 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001407
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001408 /*
1409 * At this point, we know base == rec->set_ripas.addr
1410 * and thus must be aligned to GRANULE size.
1411 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001412 assert(validate_map_addr(base, S2TT_PAGE_LEVEL, rd));
Soby Mathewb4c6df42022-11-09 11:13:29 +00001413
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001414 s2_ctx = &(rd->s2_ctx);
1415 granule_lock(s2_ctx->g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001416
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001417 /* Walk to the deepest level possible */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001418 s2tt_walk_lock_unlock(s2_ctx, base, S2TT_PAGE_LEVEL, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001419
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001420 /*
1421 * Base has to be aligned to the level at which
1422 * it is mapped in RTT.
1423 */
1424 if (!validate_map_addr(base, wi.last_level, rd)) {
1425 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001426 (unsigned char)wi.last_level);
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001427 goto out_unlock_llt;
1428 }
1429
Soby Mathewb4c6df42022-11-09 11:13:29 +00001430 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001431 assert(s2tt != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001432
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001433 rtt_set_ripas_range(s2_ctx, s2tt, base, top, &wi,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001434 ripas_val, change_destroyed, res);
1435
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001436 if (res->x[0] == RMI_SUCCESS) {
1437 rec->set_ripas.addr = res->x[1];
Soby Mathewb4c6df42022-11-09 11:13:29 +00001438 }
1439
Soby Mathewb4c6df42022-11-09 11:13:29 +00001440 buffer_unmap(s2tt);
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001441out_unlock_llt:
Soby Mathewb4c6df42022-11-09 11:13:29 +00001442 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001443 buffer_unmap(rd);
1444out_unmap_rec:
1445 buffer_unmap(rec);
1446out_unlock_rec_rd:
1447 granule_unlock(g_rec);
1448 granule_unlock(g_rd);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001449}