blob: 1792efc278b61df73fbbdf5e1b88e7145760d8cd [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>
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +000018#include <status.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000019#include <stddef.h>
20#include <string.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000021
22/*
23 * Validate the map_addr value passed to RMI_RTT_* and RMI_DATA_* commands.
24 */
25static bool validate_map_addr(unsigned long map_addr,
AlexeiFedorov4faab852023-08-30 15:06:49 +010026 long level,
Soby Mathewb4c6df42022-11-09 11:13:29 +000027 struct rd *rd)
28{
AlexeiFedorov14d47ae2023-07-19 15:26:50 +010029 return ((map_addr < realm_ipa_size(rd)) &&
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +000030 s2tte_is_addr_lvl_aligned(&(rd->s2_ctx), map_addr, level));
Soby Mathewb4c6df42022-11-09 11:13:29 +000031}
32
33/*
34 * Structure commands can operate on all RTTs except for the root RTT so
35 * the minimal valid level is the stage 2 starting level + 1.
36 */
37static bool validate_rtt_structure_cmds(unsigned long map_addr,
38 long level,
39 struct rd *rd)
40{
41 int min_level = realm_rtt_starting_level(rd) + 1;
42
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010043 if ((level < min_level) || (level > S2TT_PAGE_LEVEL)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +000044 return false;
45 }
AlexeiFedorovf85f8102023-09-11 16:14:18 +010046 return validate_map_addr(map_addr, level - 1L, rd);
Soby Mathewb4c6df42022-11-09 11:13:29 +000047}
48
49/*
50 * Map/Unmap commands can operate up to a level 2 block entry so min_level is
51 * the smallest block size.
52 */
53static bool validate_rtt_map_cmds(unsigned long map_addr,
54 long level,
55 struct rd *rd)
56{
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010057 if ((level < S2TT_MIN_BLOCK_LEVEL) || (level > S2TT_PAGE_LEVEL)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +000058 return false;
59 }
60 return validate_map_addr(map_addr, level, rd);
61}
62
63/*
64 * Entry commands can operate on any entry so the minimal valid level is the
65 * stage 2 starting level.
66 */
67static bool validate_rtt_entry_cmds(unsigned long map_addr,
68 long level,
69 struct rd *rd)
70{
71 if ((level < realm_rtt_starting_level(rd)) ||
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +010072 (level > S2TT_PAGE_LEVEL)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +000073 return false;
74 }
75 return validate_map_addr(map_addr, level, rd);
76}
77
AlexeiFedorovac923c82023-04-06 15:12:04 +010078unsigned long smc_rtt_create(unsigned long rd_addr,
79 unsigned long rtt_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +000080 unsigned long map_addr,
81 unsigned long ulevel)
82{
83 struct granule *g_rd;
84 struct granule *g_tbl;
85 struct rd *rd;
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;
Soby Mathewb4c6df42022-11-09 11:13:29 +000089 unsigned long ret;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +000090 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +000091
92 if (!find_lock_two_granules(rtt_addr,
93 GRANULE_STATE_DELEGATED,
94 &g_tbl,
95 rd_addr,
96 GRANULE_STATE_RD,
97 &g_rd)) {
98 return RMI_ERROR_INPUT;
99 }
100
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000101 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100102 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000103
104 if (!validate_rtt_structure_cmds(map_addr, level, rd)) {
105 buffer_unmap(rd);
106 granule_unlock(g_rd);
107 granule_unlock(g_tbl);
108 return RMI_ERROR_INPUT;
109 }
110
Soby Mathewb4c6df42022-11-09 11:13:29 +0000111 s2_ctx = rd->s2_ctx;
112 buffer_unmap(rd);
113
114 /*
Shruti Gupta3530a712024-09-12 10:50:21 +0100115 * If LPA2 is disabled for the realm, then `rtt_addr` must not be
116 * more than 48 bits wide.
117 */
118 if (!s2_ctx.enable_lpa2) {
119 if ((rtt_addr >= (UL(1) << S2TT_MAX_PA_BITS))) {
120 granule_unlock(g_rd);
121 granule_unlock(g_tbl);
122 return RMI_ERROR_INPUT;
123 }
124 }
125
126 /*
Soby Mathewb4c6df42022-11-09 11:13:29 +0000127 * Lock the RTT root. Enforcing locking order RD->RTT is enough to
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000128 * ensure deadlock free locking guarantee.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000129 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000130 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000131
132 /* Unlock RD after locking RTT Root */
133 granule_unlock(g_rd);
134
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000135 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level - 1L, &wi);
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100136 if (wi.last_level != (level - 1L)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100137 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000138 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000139 goto out_unlock_llt;
140 }
141
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000142 parent_s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100143 assert(parent_s2tt != NULL);
144
Soby Mathewb4c6df42022-11-09 11:13:29 +0000145 parent_s2tte = s2tte_read(&parent_s2tt[wi.index]);
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000146 s2tt = buffer_granule_map(g_tbl, SLOT_DELEGATED);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100147 assert(s2tt != NULL);
148
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000149 if (s2tte_is_unassigned_empty(&s2_ctx, parent_s2tte)) {
150 s2tt_init_unassigned_empty(&s2_ctx, s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000151
152 /*
AlexeiFedorov745499d2024-04-25 16:52:44 +0100153 * Atomically increase the refcount of the parent, the granule
154 * was locked while table walking and hand-over-hand locking.
155 * Acquire/release semantics not required because the table is
156 * accessed always locked.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000157 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100158 atomic_granule_get(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000159
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000160 } else if (s2tte_is_unassigned_ram(&s2_ctx, parent_s2tte)) {
161 s2tt_init_unassigned_ram(&s2_ctx, s2tt);
AlexeiFedorov745499d2024-04-25 16:52:44 +0100162 atomic_granule_get(wi.g_llt);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100163
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000164 } else if (s2tte_is_unassigned_ns(&s2_ctx, parent_s2tte)) {
165 s2tt_init_unassigned_ns(&s2_ctx, s2tt);
AlexeiFedorov745499d2024-04-25 16:52:44 +0100166 atomic_granule_get(wi.g_llt);
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100167
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000168 } else if (s2tte_is_unassigned_destroyed(&s2_ctx, parent_s2tte)) {
169 s2tt_init_unassigned_destroyed(&s2_ctx, s2tt);
AlexeiFedorov745499d2024-04-25 16:52:44 +0100170 atomic_granule_get(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000171
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000172 } else if (s2tte_is_assigned_destroyed(&s2_ctx, parent_s2tte,
173 level - 1L)) {
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100174 unsigned long block_pa;
175
176 /*
177 * We should observe parent assigned s2tte only when
178 * we create tables above this level.
179 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100180 assert(level > S2TT_MIN_BLOCK_LEVEL);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100181
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000182 block_pa = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100183
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000184 s2tt_init_assigned_destroyed(&s2_ctx, s2tt, block_pa, level);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100185
186 /*
187 * Increase the refcount to mark the granule as in-use. refcount
188 * is incremented by S2TTES_PER_S2TT (ref RTT unfolding).
189 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100190 granule_refcount_inc(g_tbl, (unsigned short)S2TTES_PER_S2TT);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100191
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000192 } else if (s2tte_is_assigned_empty(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000193 unsigned long block_pa;
194
195 /*
196 * We should observe parent assigned s2tte only when
197 * we create tables above this level.
198 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100199 assert(level > S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000200
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000201 block_pa = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000202
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000203 s2tt_init_assigned_empty(&s2_ctx, s2tt, block_pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000204
205 /*
206 * Increase the refcount to mark the granule as in-use. refcount
207 * is incremented by S2TTES_PER_S2TT (ref RTT unfolding).
208 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100209 granule_refcount_inc(g_tbl, (unsigned short)S2TTES_PER_S2TT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000210
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000211 } else if (s2tte_is_assigned_ram(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000212 unsigned long block_pa;
213
214 /*
215 * We should observe parent valid s2tte only when
216 * we create tables above this level.
217 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100218 assert(level > S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000219
220 /*
221 * Break before make. This may cause spurious S2 aborts.
222 */
223 s2tte_write(&parent_s2tt[wi.index], 0UL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100224 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000225
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000226 block_pa = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000227
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000228 s2tt_init_assigned_ram(&s2_ctx, s2tt, block_pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000229
230 /*
231 * Increase the refcount to mark the granule as in-use. refcount
232 * is incremented by S2TTES_PER_S2TT (ref RTT unfolding).
233 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100234 granule_refcount_inc(g_tbl, (unsigned short)S2TTES_PER_S2TT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000235
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000236 } else if (s2tte_is_assigned_ns(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000237 unsigned long block_pa;
238
239 /*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100240 * We should observe parent assigned_ns s2tte only when
Soby Mathewb4c6df42022-11-09 11:13:29 +0000241 * we create tables above this level.
242 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100243 assert(level > S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000244
245 /*
246 * Break before make. This may cause spurious S2 aborts.
247 */
248 s2tte_write(&parent_s2tt[wi.index], 0UL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100249 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000250
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000251 block_pa = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000252
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000253 s2tt_init_assigned_ns(&s2_ctx, s2tt, parent_s2tte,
254 block_pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000255
256 /*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100257 * Increment the refcount on the parent for the new RTT we are
258 * about to add. The NS block entry doesn't have a refcount
259 * on the parent RTT.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000260 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100261 atomic_granule_get(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000262
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000263 } else if (s2tte_is_table(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000264 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000265 (unsigned char)(level - 1L));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000266 goto out_unmap_table;
267
268 } else {
269 assert(false);
270 }
271
272 ret = RMI_SUCCESS;
273
274 granule_set_state(g_tbl, GRANULE_STATE_RTT);
275
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000276 parent_s2tte = s2tte_create_table(&s2_ctx, rtt_addr, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000277 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
278
279out_unmap_table:
280 buffer_unmap(s2tt);
281 buffer_unmap(parent_s2tt);
282out_unlock_llt:
283 granule_unlock(wi.g_llt);
284 granule_unlock(g_tbl);
285 return ret;
286}
287
AlexeiFedorove2002be2023-04-19 17:20:12 +0100288void smc_rtt_fold(unsigned long rd_addr,
289 unsigned long map_addr,
290 unsigned long ulevel,
291 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000292{
293 struct granule *g_rd;
294 struct granule *g_tbl;
295 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100296 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000297 unsigned long *table, *parent_s2tt, parent_s2tte;
298 long level = (long)ulevel;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000299 unsigned long rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000300 unsigned long ret;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000301 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000302
303 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
304 if (g_rd == NULL) {
AlexeiFedorove2002be2023-04-19 17:20:12 +0100305 res->x[0] = RMI_ERROR_INPUT;
306 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000307 }
308
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000309 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100310 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000311
312 if (!validate_rtt_structure_cmds(map_addr, level, rd)) {
313 buffer_unmap(rd);
314 granule_unlock(g_rd);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100315 res->x[0] = RMI_ERROR_INPUT;
316 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000317 }
318
Soby Mathewb4c6df42022-11-09 11:13:29 +0000319 s2_ctx = rd->s2_ctx;
320 buffer_unmap(rd);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000321 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000322 granule_unlock(g_rd);
323
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000324 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level - 1L, &wi);
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100325 if (wi.last_level != (level - 1L)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100326 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000327 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000328 goto out_unlock_parent_table;
329 }
330
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000331 parent_s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100332 assert(parent_s2tt != NULL);
333
Soby Mathewb4c6df42022-11-09 11:13:29 +0000334 parent_s2tte = s2tte_read(&parent_s2tt[wi.index]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000335 if (!s2tte_is_table(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000336 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000337 (unsigned char)(level - 1L));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000338 goto out_unmap_parent_table;
339 }
340
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000341 rtt_addr = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000342 g_tbl = find_lock_granule(rtt_addr, GRANULE_STATE_RTT);
343
344 /*
345 * A table descriptor S2TTE always points to a TABLE granule.
346 */
AlexeiFedorov63b71692023-04-19 11:18:42 +0100347 assert(g_tbl != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000348
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000349 table = buffer_granule_map(g_tbl, SLOT_RTT2);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100350 assert(table != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000351
352 /*
353 * The command can succeed only if all 512 S2TTEs are of the same type.
354 * We first check the table's ref. counter to speed up the case when
355 * the host makes a guess whether a memory region can be folded.
356 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100357 if (granule_refcount_read(g_tbl) == 0U) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000358 if (s2tt_is_unassigned_destroyed_block(&s2_ctx, table)) {
359 parent_s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
360 } else if (s2tt_is_unassigned_empty_block(&s2_ctx, table)) {
361 parent_s2tte = s2tte_create_unassigned_empty(&s2_ctx);
362 } else if (s2tt_is_unassigned_ram_block(&s2_ctx, table)) {
363 parent_s2tte = s2tte_create_unassigned_ram(&s2_ctx);
364 } else if (s2tt_is_unassigned_ns_block(&s2_ctx, table)) {
365 parent_s2tte = s2tte_create_unassigned_ns(&s2_ctx);
366 } else if (s2tt_maps_assigned_ns_block(&s2_ctx, table, level)) {
Shruti Gupta3105c3f2024-02-26 14:06:11 +0000367
368 /*
369 * The RMM specification does not allow creating block entries less than
370 * S2TT_MIN_BLOCK_LEVEL for ASSIGNED_NS state.
371 */
372 if (level <= S2TT_MIN_BLOCK_LEVEL) {
373 ret = pack_return_code(RMI_ERROR_RTT,
374 (unsigned char)wi.last_level);
375 goto out_unmap_table;
376 }
AlexeiFedorov49752c62023-04-24 14:31:14 +0100377 unsigned long s2tte = s2tte_read(&table[0]);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100378
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100379 /*
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100380 * Since s2tt_maps_assigned_ns_block() has succedded,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100381 * the PA in first entry of the table is aligned at
382 * parent level. Use the TTE from the first entry
383 * directly as it also has the NS attributes to be used
384 * for the parent block entry.
385 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000386 parent_s2tte = s2tte_create_assigned_ns(&s2_ctx, s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000387 } else {
388 /*
389 * The table holds a mixture of destroyed and
390 * unassigned entries.
391 */
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100392 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000393 (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000394 goto out_unmap_table;
395 }
AlexeiFedorov745499d2024-04-25 16:52:44 +0100396 atomic_granule_put(wi.g_llt);
397 } else if (granule_refcount_read(g_tbl) ==
398 (unsigned short)S2TTES_PER_S2TT) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000399
400 unsigned long s2tte, block_pa;
401
402 /* The RMM specification does not allow creating block
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100403 * entries less than S2TT_MIN_BLOCK_LEVEL even though
Soby Mathewb4c6df42022-11-09 11:13:29 +0000404 * permitted by the Arm Architecture.
405 * Hence ensure that the table being folded is at a level
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100406 * higher than the S2TT_MIN_BLOCK_LEVEL.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000407 *
408 * A fully populated table cannot be destroyed if that
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100409 * would create a block mapping below S2TT_MIN_BLOCK_LEVEL.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000410 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100411 if (level <= S2TT_MIN_BLOCK_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100412 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000413 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000414 goto out_unmap_table;
415 }
416
417 s2tte = s2tte_read(&table[0]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000418 block_pa = s2tte_pa(&s2_ctx, s2tte, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000419
420 /*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100421 * The table must also refer to a contiguous block through the
AlexeiFedorov3f840a02023-07-19 10:55:05 +0100422 * same type of s2tte, either Assigned or Valid.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000423 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000424 if (s2tt_maps_assigned_empty_block(&s2_ctx, table, level)) {
425 parent_s2tte = s2tte_create_assigned_empty(&s2_ctx,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100426 block_pa, level - 1L);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000427 } else if (s2tt_maps_assigned_ram_block(&s2_ctx,
428 table, level)) {
429 parent_s2tte = s2tte_create_assigned_ram(&s2_ctx,
430 block_pa,
AlexeiFedorov3a739332023-04-13 13:54:04 +0100431 level - 1L);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000432 } else if (s2tt_maps_assigned_destroyed_block(&s2_ctx,
433 table, level)) {
434 parent_s2tte = s2tte_create_assigned_destroyed(&s2_ctx,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100435 block_pa, level - 1L);
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000436 /* The table contains mixed entries that cannot be folded */
Soby Mathewb4c6df42022-11-09 11:13:29 +0000437 } else {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100438 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000439 (unsigned char)level);
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000440 goto out_unmap_table;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000441 }
442
AlexeiFedorov745499d2024-04-25 16:52:44 +0100443 granule_refcount_dec(g_tbl, (unsigned short)S2TTES_PER_S2TT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000444 } else {
445 /*
446 * The table holds a mixture of different types of s2ttes.
447 */
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100448 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000449 (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000450 goto out_unmap_table;
451 }
452
453 ret = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100454 res->x[1] = rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000455
456 /*
457 * Break before make.
458 */
459 s2tte_write(&parent_s2tt[wi.index], 0UL);
460
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000461 if (s2tte_is_assigned_ram(&s2_ctx, parent_s2tte, level - 1L) ||
462 s2tte_is_assigned_ns(&s2_ctx, parent_s2tte, level - 1L)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100463 s2tt_invalidate_pages_in_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000464 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100465 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000466 }
467
468 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
469
470 granule_memzero_mapped(table);
471 granule_set_state(g_tbl, GRANULE_STATE_DELEGATED);
472
473out_unmap_table:
474 buffer_unmap(table);
475 granule_unlock(g_tbl);
476out_unmap_parent_table:
477 buffer_unmap(parent_s2tt);
478out_unlock_parent_table:
479 granule_unlock(wi.g_llt);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100480 res->x[0] = ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000481}
482
AlexeiFedorove2002be2023-04-19 17:20:12 +0100483void smc_rtt_destroy(unsigned long rd_addr,
484 unsigned long map_addr,
485 unsigned long ulevel,
486 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000487{
488 struct granule *g_rd;
489 struct granule *g_tbl;
490 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100491 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000492 unsigned long *table, *parent_s2tt, parent_s2tte;
493 long level = (long)ulevel;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000494 unsigned long rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000495 unsigned long ret;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000496 struct s2tt_context s2_ctx;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100497 bool in_par, skip_non_live = false;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000498
499 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
500 if (g_rd == NULL) {
AlexeiFedorove2002be2023-04-19 17:20:12 +0100501 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100502 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100503 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000504 }
505
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000506 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100507 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000508
509 if (!validate_rtt_structure_cmds(map_addr, level, rd)) {
510 buffer_unmap(rd);
511 granule_unlock(g_rd);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100512 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100513 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100514 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000515 }
516
Soby Mathewb4c6df42022-11-09 11:13:29 +0000517 s2_ctx = rd->s2_ctx;
518 in_par = addr_in_par(rd, map_addr);
519 buffer_unmap(rd);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000520 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000521 granule_unlock(g_rd);
522
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000523 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level - 1L, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000524
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000525 parent_s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100526 assert(parent_s2tt != NULL);
527
Soby Mathewb4c6df42022-11-09 11:13:29 +0000528 parent_s2tte = s2tte_read(&parent_s2tt[wi.index]);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100529
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100530 if ((wi.last_level != (level - 1L)) ||
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000531 !s2tte_is_table(&s2_ctx, parent_s2tte, level - 1L)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100532 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000533 (unsigned char)wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100534 skip_non_live = true;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000535 goto out_unmap_parent_table;
536 }
537
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000538 rtt_addr = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000539
540 /*
541 * Lock the RTT granule. The 'rtt_addr' is verified, thus can be treated
542 * as an internal granule.
543 */
544 g_tbl = find_lock_granule(rtt_addr, GRANULE_STATE_RTT);
545
546 /*
547 * A table descriptor S2TTE always points to a TABLE granule.
548 */
549 assert(g_tbl != NULL);
550
551 /*
552 * Read the refcount value. RTT granule is always accessed locked, thus
553 * the refcount can be accessed without atomic operations.
554 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100555 if (granule_refcount_read(g_tbl) != 0U) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000556 ret = pack_return_code(RMI_ERROR_RTT, (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000557 goto out_unlock_table;
558 }
559
560 ret = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100561 res->x[1] = rtt_addr;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100562 skip_non_live = true;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000563
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000564 table = buffer_granule_map(g_tbl, SLOT_RTT2);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100565 assert(table != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000566
567 if (in_par) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000568 parent_s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000569 } else {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000570 parent_s2tte = s2tte_create_unassigned_ns(&s2_ctx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000571 }
572
AlexeiFedorov745499d2024-04-25 16:52:44 +0100573 atomic_granule_put(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000574
575 /*
576 * Break before make. Note that this may cause spurious S2 aborts.
577 */
578 s2tte_write(&parent_s2tt[wi.index], 0UL);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000579
580 if (in_par) {
581 /* For protected IPA, all S2TTEs in the RTT will be invalid */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100582 s2tt_invalidate_block(&s2_ctx, map_addr);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000583 } else {
584 /*
585 * For unprotected IPA, invalidate the TLB for the entire range
586 * mapped by the RTT as it may have valid NS mappings.
587 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100588 s2tt_invalidate_pages_in_block(&s2_ctx, map_addr);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000589 }
590
Soby Mathewb4c6df42022-11-09 11:13:29 +0000591 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
592
593 granule_memzero_mapped(table);
594 granule_set_state(g_tbl, GRANULE_STATE_DELEGATED);
595
596 buffer_unmap(table);
597out_unlock_table:
598 granule_unlock(g_tbl);
599out_unmap_parent_table:
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100600 if (skip_non_live) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000601 res->x[2] = s2tt_skip_non_live_entries(&s2_ctx, map_addr,
602 parent_s2tt, &wi);
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100603 } else {
604 res->x[2] = map_addr;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100605 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000606 buffer_unmap(parent_s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000607 granule_unlock(wi.g_llt);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100608 res->x[0] = ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000609}
610
611enum map_unmap_ns_op {
612 MAP_NS,
613 UNMAP_NS
614};
615
616/*
617 * We don't hold a reference on the NS granule when it is
618 * mapped into a realm. Instead we rely on the guarantees
619 * provided by the architecture to ensure that a NS access
620 * to a protected granule is prohibited even within the realm.
621 */
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100622static void map_unmap_ns(unsigned long rd_addr,
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000623 unsigned long map_addr,
624 long level,
625 unsigned long host_s2tte,
626 enum map_unmap_ns_op op,
627 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000628{
629 struct granule *g_rd;
630 struct rd *rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000631 unsigned long *s2tt, s2tte;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100632 struct s2tt_walk wi;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000633 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000634
635 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
636 if (g_rd == NULL) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100637 res->x[0] = RMI_ERROR_INPUT;
638 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000639 }
640
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000641 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100642 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000643
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000644 s2_ctx = rd->s2_ctx;
645
646 if (op == MAP_NS) {
647 if (!host_ns_s2tte_is_valid(&s2_ctx, host_s2tte, level)) {
648 buffer_unmap(rd);
649 granule_unlock(g_rd);
650 res->x[0] = RMI_ERROR_INPUT;
651 return;
652 }
653 }
654
655
Soby Mathewb4c6df42022-11-09 11:13:29 +0000656 if (!validate_rtt_map_cmds(map_addr, level, rd)) {
657 buffer_unmap(rd);
658 granule_unlock(g_rd);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100659 res->x[0] = RMI_ERROR_INPUT;
660 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000661 }
662
AlexeiFedorovc34e3242023-04-12 11:30:33 +0100663 /* Check if map_addr is outside PAR */
664 if (addr_in_par(rd, map_addr)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000665 buffer_unmap(rd);
666 granule_unlock(g_rd);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100667 res->x[0] = RMI_ERROR_INPUT;
668 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000669 }
670
Soby Mathewb4c6df42022-11-09 11:13:29 +0000671 buffer_unmap(rd);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000672 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000673 granule_unlock(g_rd);
674
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000675 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level, &wi);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100676
677 /*
678 * For UNMAP_NS, we need to map the table and look
679 * for the end of the non-live region.
680 */
AlexeiFedorov14d47ae2023-07-19 15:26:50 +0100681 if ((op == MAP_NS) && (wi.last_level != level)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100682 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000683 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000684 goto out_unlock_llt;
685 }
686
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000687 s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100688 assert(s2tt != NULL);
689
Soby Mathewb4c6df42022-11-09 11:13:29 +0000690 s2tte = s2tte_read(&s2tt[wi.index]);
691
692 if (op == MAP_NS) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000693 if (!s2tte_is_unassigned_ns(&s2_ctx, s2tte)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100694 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000695 (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000696 goto out_unmap_table;
697 }
698
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000699 s2tte = s2tte_create_assigned_ns(&s2_ctx, host_s2tte, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000700 s2tte_write(&s2tt[wi.index], s2tte);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000701
702 } else if (op == UNMAP_NS) {
703 /*
704 * The following check also verifies that map_addr is outside
705 * PAR, as valid_NS s2tte may only cover outside PAR IPA range.
706 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000707 bool assigned_ns = s2tte_is_assigned_ns(&s2_ctx, s2tte,
708 wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100709
710 if ((wi.last_level != level) || !assigned_ns) {
711 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000712 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000713 goto out_unmap_table;
714 }
715
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000716 s2tte = s2tte_create_unassigned_ns(&s2_ctx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000717 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100718 if (level == S2TT_PAGE_LEVEL) {
719 s2tt_invalidate_page(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000720 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100721 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000722 }
723 }
724
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100725 res->x[0] = RMI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000726
727out_unmap_table:
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100728 if (op == UNMAP_NS) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000729 res->x[1] = s2tt_skip_non_live_entries(&s2_ctx, map_addr,
730 s2tt, &wi);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100731 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000732 buffer_unmap(s2tt);
733out_unlock_llt:
734 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000735}
736
737unsigned long smc_rtt_map_unprotected(unsigned long rd_addr,
738 unsigned long map_addr,
739 unsigned long ulevel,
740 unsigned long s2tte)
741{
742 long level = (long)ulevel;
Shruti Gupta9e966b82024-03-21 13:45:24 +0000743 struct smc_result res;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000744
Shruti Gupta9e966b82024-03-21 13:45:24 +0000745 (void)memset(&res, 0, sizeof(struct smc_result));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100746 if ((level < S2TT_MIN_BLOCK_LEVEL) || (level > S2TT_PAGE_LEVEL)) {
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100747 return RMI_ERROR_INPUT;
748 }
749
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100750 map_unmap_ns(rd_addr, map_addr, level, s2tte, MAP_NS, &res);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000751
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100752 return res.x[0];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000753}
754
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100755void smc_rtt_unmap_unprotected(unsigned long rd_addr,
756 unsigned long map_addr,
757 unsigned long ulevel,
758 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000759{
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100760 long level = (long)ulevel;
761
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100762 if ((level < S2TT_MIN_BLOCK_LEVEL) || (level > S2TT_PAGE_LEVEL)) {
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100763 res->x[0] = RMI_ERROR_INPUT;
764 return;
765 }
766
767 map_unmap_ns(rd_addr, map_addr, level, 0UL, UNMAP_NS, res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000768}
769
770void smc_rtt_read_entry(unsigned long rd_addr,
771 unsigned long map_addr,
772 unsigned long ulevel,
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100773 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000774{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000775 struct granule *g_rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000776 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100777 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000778 unsigned long *s2tt, s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000779 long level = (long)ulevel;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000780 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000781
782 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
783 if (g_rd == NULL) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100784 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000785 return;
786 }
787
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000788 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100789 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000790
791 if (!validate_rtt_entry_cmds(map_addr, level, rd)) {
792 buffer_unmap(rd);
793 granule_unlock(g_rd);
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100794 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000795 return;
796 }
797
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000798 s2_ctx = rd->s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000799 buffer_unmap(rd);
800
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000801 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000802 granule_unlock(g_rd);
803
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000804 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level, &wi);
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000805 s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100806 assert(s2tt != NULL);
807
Soby Mathewb4c6df42022-11-09 11:13:29 +0000808 s2tte = s2tte_read(&s2tt[wi.index]);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100809 res->x[1] = (unsigned long)wi.last_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000810
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000811 if (s2tte_is_unassigned_empty(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100812 res->x[2] = RMI_UNASSIGNED;
813 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100814 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000815 } else if (s2tte_is_unassigned_ram(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100816 res->x[2] = RMI_UNASSIGNED;
817 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100818 res->x[4] = (unsigned long)RIPAS_RAM;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000819 } else if (s2tte_is_unassigned_destroyed(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100820 res->x[2] = RMI_UNASSIGNED;
821 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100822 res->x[4] = (unsigned long)RIPAS_DESTROYED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000823 } else if (s2tte_is_assigned_empty(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100824 res->x[2] = RMI_ASSIGNED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000825 res->x[3] = s2tte_pa(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100826 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000827 } else if (s2tte_is_assigned_ram(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100828 res->x[2] = RMI_ASSIGNED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000829 res->x[3] = s2tte_pa(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100830 res->x[4] = (unsigned long)RIPAS_RAM;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000831 } else if (s2tte_is_assigned_destroyed(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100832 res->x[2] = RMI_ASSIGNED;
833 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100834 res->x[4] = (unsigned long)RIPAS_DESTROYED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000835 } else if (s2tte_is_unassigned_ns(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100836 res->x[2] = RMI_UNASSIGNED;
837 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100838 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000839 } else if (s2tte_is_assigned_ns(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100840 res->x[2] = RMI_ASSIGNED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000841 res->x[3] = host_ns_s2tte(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100842 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000843 } else if (s2tte_is_table(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100844 res->x[2] = RMI_TABLE;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000845 res->x[3] = s2tte_pa(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100846 res->x[4] = (unsigned long)RIPAS_EMPTY;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000847 } else {
848 assert(false);
849 }
850
851 buffer_unmap(s2tt);
852 granule_unlock(wi.g_llt);
853
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100854 res->x[0] = RMI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000855}
856
Soby Mathewb4c6df42022-11-09 11:13:29 +0000857static unsigned long validate_data_create_unknown(unsigned long map_addr,
858 struct rd *rd)
859{
860 if (!addr_in_par(rd, map_addr)) {
861 return RMI_ERROR_INPUT;
862 }
863
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100864 if (!validate_map_addr(map_addr, S2TT_PAGE_LEVEL, rd)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000865 return RMI_ERROR_INPUT;
866 }
867
868 return RMI_SUCCESS;
869}
870
871static unsigned long validate_data_create(unsigned long map_addr,
872 struct rd *rd)
873{
Mate Toth-Pal988dfcb2024-01-19 10:52:06 +0100874 if (get_rd_state_locked(rd) != REALM_NEW) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000875 return RMI_ERROR_REALM;
876 }
877
878 return validate_data_create_unknown(map_addr, rd);
879}
880
881/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100882 * Implements both RMI_DATA_CREATE and RMI_DATA_CREATE_UNKNOWN
Soby Mathewb4c6df42022-11-09 11:13:29 +0000883 *
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100884 * if @g_src == NULL, implements RMI_DATA_CREATE_UNKNOWN
885 * and RMI_DATA_CREATE otherwise.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000886 */
AlexeiFedorovac923c82023-04-06 15:12:04 +0100887static unsigned long data_create(unsigned long rd_addr,
888 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000889 unsigned long map_addr,
890 struct granule *g_src,
891 unsigned long flags)
892{
893 struct granule *g_data;
894 struct granule *g_rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000895 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100896 struct s2tt_walk wi;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000897 struct s2tt_context *s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000898 unsigned long s2tte, *s2tt;
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000899 unsigned char new_data_state = GRANULE_STATE_DELEGATED;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000900 unsigned long ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000901
902 if (!find_lock_two_granules(data_addr,
903 GRANULE_STATE_DELEGATED,
904 &g_data,
905 rd_addr,
906 GRANULE_STATE_RD,
907 &g_rd)) {
908 return RMI_ERROR_INPUT;
909 }
910
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000911 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100912 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000913
914 ret = (g_src != NULL) ?
915 validate_data_create(map_addr, rd) :
916 validate_data_create_unknown(map_addr, rd);
917
918 if (ret != RMI_SUCCESS) {
919 goto out_unmap_rd;
920 }
921
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000922 s2_ctx = &(rd->s2_ctx);
Shruti Gupta3530a712024-09-12 10:50:21 +0100923
924 /*
925 * If LPA2 is disabled for the realm, then `data_addr` must not be
926 * more than 48 bits wide.
927 */
928 if (!s2_ctx->enable_lpa2) {
929 if ((data_addr >= (UL(1) << S2TT_MAX_PA_BITS))) {
930 ret = RMI_ERROR_INPUT;
931 goto out_unmap_rd;
932 }
933 }
934
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000935 granule_lock(s2_ctx->g_rtt, GRANULE_STATE_RTT);
936
937 s2tt_walk_lock_unlock(s2_ctx, map_addr, S2TT_PAGE_LEVEL, &wi);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100938 if (wi.last_level != S2TT_PAGE_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100939 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000940 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000941 goto out_unlock_ll_table;
942 }
943
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000944 s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100945 assert(s2tt != NULL);
946
Soby Mathewb4c6df42022-11-09 11:13:29 +0000947 s2tte = s2tte_read(&s2tt[wi.index]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000948 if (!s2tte_is_unassigned(s2_ctx, s2tte)) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000949 ret = pack_return_code(RMI_ERROR_RTT,
950 (unsigned char)S2TT_PAGE_LEVEL);
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100951 goto out_unmap_ll_table;
952 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000953
Soby Mathewb4c6df42022-11-09 11:13:29 +0000954 if (g_src != NULL) {
955 bool ns_access_ok;
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000956 void *data = buffer_granule_map(g_data, SLOT_DELEGATED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000957
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100958 assert(data != NULL);
959
Soby Mathewb4c6df42022-11-09 11:13:29 +0000960 ns_access_ok = ns_buffer_read(SLOT_NS, g_src, 0U,
961 GRANULE_SIZE, data);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000962 if (!ns_access_ok) {
963 /*
964 * Some data may be copied before the failure. Zero
965 * g_data granule as it will remain in delegated state.
966 */
AlexeiFedorov862f96c2024-03-01 16:26:48 +0000967 granule_memzero_mapped(data);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000968 buffer_unmap(data);
969 ret = RMI_ERROR_INPUT;
970 goto out_unmap_ll_table;
971 }
972
Mate Toth-Palc7698312023-08-09 12:49:34 +0200973 measurement_data_granule_measure(
974 rd->measurement[RIM_MEASUREMENT_SLOT],
975 rd->algorithm,
976 data,
977 map_addr,
978 flags);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000979 buffer_unmap(data);
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100980
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000981 s2tte = s2tte_create_assigned_ram(s2_ctx, data_addr,
982 S2TT_PAGE_LEVEL);
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100983 } else {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000984 s2tte = s2tte_create_assigned_unchanged(s2_ctx, s2tte,
985 data_addr,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100986 S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000987 }
988
989 new_data_state = GRANULE_STATE_DATA;
990
Soby Mathewb4c6df42022-11-09 11:13:29 +0000991 s2tte_write(&s2tt[wi.index], s2tte);
AlexeiFedorov745499d2024-04-25 16:52:44 +0100992 atomic_granule_get(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000993
994 ret = RMI_SUCCESS;
995
996out_unmap_ll_table:
997 buffer_unmap(s2tt);
998out_unlock_ll_table:
999 granule_unlock(wi.g_llt);
1000out_unmap_rd:
1001 buffer_unmap(rd);
1002 granule_unlock(g_rd);
1003 granule_unlock_transition(g_data, new_data_state);
1004 return ret;
1005}
1006
AlexeiFedorovac923c82023-04-06 15:12:04 +01001007unsigned long smc_data_create(unsigned long rd_addr,
1008 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +00001009 unsigned long map_addr,
1010 unsigned long src_addr,
1011 unsigned long flags)
1012{
1013 struct granule *g_src;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001014
AlexeiFedorov93f5ec52023-08-31 14:26:53 +01001015 if ((flags != RMI_NO_MEASURE_CONTENT) &&
1016 (flags != RMI_MEASURE_CONTENT)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001017 return RMI_ERROR_INPUT;
1018 }
1019
1020 g_src = find_granule(src_addr);
AlexeiFedorov745499d2024-04-25 16:52:44 +01001021 if ((g_src == NULL) ||
1022 (granule_unlocked_state(g_src) != GRANULE_STATE_NS)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001023 return RMI_ERROR_INPUT;
1024 }
1025
AlexeiFedorovac923c82023-04-06 15:12:04 +01001026 return data_create(rd_addr, data_addr, map_addr, g_src, flags);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001027}
1028
AlexeiFedorovac923c82023-04-06 15:12:04 +01001029unsigned long smc_data_create_unknown(unsigned long rd_addr,
1030 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +00001031 unsigned long map_addr)
1032{
AlexeiFedorovac923c82023-04-06 15:12:04 +01001033 return data_create(rd_addr, data_addr, map_addr, NULL, 0);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001034}
1035
AlexeiFedorove2002be2023-04-19 17:20:12 +01001036void smc_data_destroy(unsigned long rd_addr,
1037 unsigned long map_addr,
1038 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001039{
1040 struct granule *g_data;
1041 struct granule *g_rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001042 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001043 unsigned long data_addr, s2tte, *s2tt;
1044 struct rd *rd;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +00001045 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001046
1047 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
1048 if (g_rd == NULL) {
AlexeiFedorove2002be2023-04-19 17:20:12 +01001049 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorova1b2a1d2023-07-18 15:08:47 +01001050 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001051 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001052 }
1053
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001054 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001055 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001056
AlexeiFedorov868a6512023-09-14 13:21:11 +01001057 if (!addr_in_par(rd, map_addr) ||
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001058 !validate_map_addr(map_addr, S2TT_PAGE_LEVEL, rd)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001059 buffer_unmap(rd);
1060 granule_unlock(g_rd);
AlexeiFedorove2002be2023-04-19 17:20:12 +01001061 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorova1b2a1d2023-07-18 15:08:47 +01001062 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001063 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001064 }
1065
Soby Mathewb4c6df42022-11-09 11:13:29 +00001066 s2_ctx = rd->s2_ctx;
1067 buffer_unmap(rd);
1068
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001069 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001070 granule_unlock(g_rd);
1071
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001072 s2tt_walk_lock_unlock(&s2_ctx, map_addr, S2TT_PAGE_LEVEL, &wi);
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001073 s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001074 assert(s2tt != NULL);
1075
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001076 if (wi.last_level != S2TT_PAGE_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001077 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001078 (unsigned char)wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001079 goto out_unmap_ll_table;
1080 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001081
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001082 s2tte = s2tte_read(&s2tt[wi.index]);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001083
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001084 if (s2tte_is_assigned_ram(&s2_ctx, s2tte, S2TT_PAGE_LEVEL)) {
1085 data_addr = s2tte_pa(&s2_ctx, s2tte, S2TT_PAGE_LEVEL);
1086 s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001087 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001088 s2tt_invalidate_page(&s2_ctx, map_addr);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001089 } else if (s2tte_is_assigned_empty(&s2_ctx, s2tte, S2TT_PAGE_LEVEL)) {
1090 data_addr = s2tte_pa(&s2_ctx, s2tte, S2TT_PAGE_LEVEL);
1091 s2tte = s2tte_create_unassigned_empty(&s2_ctx);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001092 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001093 } else if (s2tte_is_assigned_destroyed(&s2_ctx, s2tte,
1094 S2TT_PAGE_LEVEL)) {
1095 data_addr = s2tte_pa(&s2_ctx, s2tte, S2TT_PAGE_LEVEL);
1096 s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +01001097 s2tte_write(&s2tt[wi.index], s2tte);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001098 } else {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001099 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1100 (unsigned char)S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001101 goto out_unmap_ll_table;
1102 }
1103
AlexeiFedorov745499d2024-04-25 16:52:44 +01001104 atomic_granule_put(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001105
1106 /*
1107 * Lock the data granule and check expected state. Correct locking order
1108 * is guaranteed because granule address is obtained from a locked
1109 * granule by table walk. This lock needs to be acquired before a state
1110 * transition to or from GRANULE_STATE_DATA for granule address can happen.
1111 */
1112 g_data = find_lock_granule(data_addr, GRANULE_STATE_DATA);
AlexeiFedorov63b71692023-04-19 11:18:42 +01001113 assert(g_data != NULL);
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001114 buffer_granule_memzero(g_data, SLOT_DELEGATED);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001115 granule_unlock_transition(g_data, GRANULE_STATE_DELEGATED);
1116
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001117 res->x[0] = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001118 res->x[1] = data_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001119out_unmap_ll_table:
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001120 res->x[2] = s2tt_skip_non_live_entries(&s2_ctx, map_addr, s2tt, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001121 buffer_unmap(s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001122 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001123}
1124
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001125/*
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001126 * Update the ripas value for the entry pointed by @s2ttep.
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001127 *
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001128 * Returns:
1129 * < 0 - On error and the operation was aborted,
1130 * e.g., entry cannot have a ripas.
1131 * 0 - Operation was success and no TLBI is required.
1132 * > 0 - Operation was success and TLBI is required.
1133 * Sets:
1134 * @(*do_tlbi) to 'true' if the TLBs have to be invalidated.
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001135 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001136static int update_ripas(const struct s2tt_context *s2_ctx,
1137 unsigned long *s2ttep, long level,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001138 enum ripas ripas_val,
1139 enum ripas_change_destroyed change_destroyed)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001140{
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001141 unsigned long pa, s2tte = s2tte_read(s2ttep);
1142 int ret = 0;
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001143
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001144 assert(s2_ctx != NULL);
1145
1146 if (!s2tte_has_ripas(s2_ctx, s2tte, level)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001147 return -EPERM;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001148 }
1149
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001150 if (ripas_val == RIPAS_RAM) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001151 if (s2tte_is_unassigned_empty(s2_ctx, s2tte)) {
1152 s2tte = s2tte_create_unassigned_ram(s2_ctx);
1153 } else if (s2tte_is_unassigned_destroyed(s2_ctx, s2tte)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001154 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001155 s2tte = s2tte_create_unassigned_ram(s2_ctx);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001156 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001157 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001158 }
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001159 } else if (s2tte_is_assigned_empty(s2_ctx, s2tte, level)) {
1160 pa = s2tte_pa(s2_ctx, s2tte, level);
1161 s2tte = s2tte_create_assigned_ram(s2_ctx, pa, level);
1162 } else if (s2tte_is_assigned_destroyed(s2_ctx, s2tte, level)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001163 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001164 pa = s2tte_pa(s2_ctx, s2tte, level);
1165 s2tte = s2tte_create_assigned_ram(s2_ctx, pa,
1166 level);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001167 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001168 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001169 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001170 } else {
1171 /* No action is required */
1172 return 0;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001173 }
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001174 } else if (ripas_val == RIPAS_EMPTY) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001175 if (s2tte_is_unassigned_ram(s2_ctx, s2tte)) {
1176 s2tte = s2tte_create_unassigned_empty(s2_ctx);
1177 } else if (s2tte_is_unassigned_destroyed(s2_ctx, s2tte)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001178 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001179 s2tte = s2tte_create_unassigned_empty(s2_ctx);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001180 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001181 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001182 }
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001183 } else if (s2tte_is_assigned_ram(s2_ctx, s2tte, level)) {
1184 pa = s2tte_pa(s2_ctx, s2tte, level);
1185 s2tte = s2tte_create_assigned_empty(s2_ctx, pa, level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001186 /* TLBI is required */
1187 ret = 1;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001188 } else if (s2tte_is_assigned_destroyed(s2_ctx, s2tte, level)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001189 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001190 pa = s2tte_pa(s2_ctx, s2tte, level);
1191 s2tte = s2tte_create_assigned_empty(s2_ctx,
1192 pa, level);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001193 /* TLBI is required */
1194 ret = 1;
1195 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001196 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001197 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001198 } else {
1199 /* No action is required */
1200 return 0;
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001201 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001202 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001203 s2tte_write(s2ttep, s2tte);
1204 return ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001205}
1206
AlexeiFedorov960d1612023-04-25 13:23:39 +01001207void smc_rtt_init_ripas(unsigned long rd_addr,
1208 unsigned long base,
1209 unsigned long top,
1210 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001211{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001212 struct granule *g_rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001213 struct rd *rd;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001214 unsigned long addr, map_size;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001215 struct s2tt_walk wi;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001216 struct s2tt_context *s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001217 unsigned long s2tte, *s2tt;
AlexeiFedorov960d1612023-04-25 13:23:39 +01001218 long level;
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001219 unsigned long index;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001220 unsigned int s2ttes_per_s2tt;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001221
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001222 if (top <= base) {
1223 res->x[0] = RMI_ERROR_INPUT;
1224 return;
1225 }
1226
Soby Mathewb4c6df42022-11-09 11:13:29 +00001227 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
1228 if (g_rd == NULL) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001229 res->x[0] = RMI_ERROR_INPUT;
1230 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001231 }
1232
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001233 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001234 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001235
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001236 if (!validate_map_addr(base, S2TT_PAGE_LEVEL, rd) ||
1237 !validate_map_addr(top, S2TT_PAGE_LEVEL, rd) ||
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001238 !addr_in_par(rd, base) || !addr_in_par(rd, top - GRANULE_SIZE)) {
1239 buffer_unmap(rd);
1240 granule_unlock(g_rd);
1241 res->x[0] = RMI_ERROR_INPUT;
1242 return;
1243 }
1244
Mate Toth-Pal988dfcb2024-01-19 10:52:06 +01001245 if (get_rd_state_locked(rd) != REALM_NEW) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001246 buffer_unmap(rd);
1247 granule_unlock(g_rd);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001248 res->x[0] = RMI_ERROR_REALM;
1249 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001250 }
1251
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001252 s2_ctx = &(rd->s2_ctx);
1253 granule_lock(s2_ctx->g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001254
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001255 s2tt_walk_lock_unlock(s2_ctx, base, S2TT_PAGE_LEVEL, &wi);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001256 level = wi.last_level;
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001257 s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001258 assert(s2tt != NULL);
1259
AlexeiFedorov960d1612023-04-25 13:23:39 +01001260 map_size = s2tte_map_size(level);
1261 addr = base & ~(map_size - 1UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001262
AlexeiFedorov960d1612023-04-25 13:23:39 +01001263 /*
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001264 * If the RTTE covers a range below "base", we need to go deeper.
AlexeiFedorov960d1612023-04-25 13:23:39 +01001265 */
1266 if (addr != base) {
1267 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001268 (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001269 goto out_unmap_llt;
1270 }
1271
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001272 s2ttes_per_s2tt =
1273 (unsigned int)((level == S2TT_MIN_STARTING_LEVEL_LPA2) ?
1274 S2TTES_PER_S2TT_LM1 : S2TTES_PER_S2TT);
1275 for (index = wi.index; index < s2ttes_per_s2tt; index++) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001276 unsigned long next = addr + map_size;
1277
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001278 /*
1279 * Break on "top_align" failure condition,
1280 * or if this entry crosses the range.
1281 */
AlexeiFedorov960d1612023-04-25 13:23:39 +01001282 if (next > top) {
1283 break;
1284 }
1285
1286 s2tte = s2tte_read(&s2tt[index]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001287 if (s2tte_is_unassigned_empty(s2_ctx, s2tte)) {
1288 s2tte = s2tte_create_unassigned_ram(s2_ctx);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001289 s2tte_write(&s2tt[index], s2tte);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001290 } else if (!s2tte_is_unassigned_ram(s2_ctx, s2tte)) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001291 break;
1292 }
Mate Toth-Palc7698312023-08-09 12:49:34 +02001293 measurement_init_ripas_measure(rd->measurement[RIM_MEASUREMENT_SLOT],
1294 rd->algorithm,
1295 addr,
1296 next);
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001297 addr = next;
AlexeiFedorov960d1612023-04-25 13:23:39 +01001298 }
1299
1300 if (addr > base) {
1301 res->x[0] = RMI_SUCCESS;
1302 res->x[1] = addr;
1303 } else {
1304 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001305 (unsigned char)level);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001306 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001307
1308out_unmap_llt:
1309 buffer_unmap(s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001310 buffer_unmap(rd);
1311 granule_unlock(wi.g_llt);
AlexeiFedorov80295e42023-07-10 13:11:14 +01001312 granule_unlock(g_rd);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001313}
1314
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +00001315static void rtt_set_ripas_range(struct s2tt_context *s2_ctx,
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001316 unsigned long *s2tt,
1317 unsigned long base,
1318 unsigned long top,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001319 struct s2tt_walk *wi,
AlexeiFedorov4faab852023-08-30 15:06:49 +01001320 enum ripas ripas_val,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001321 enum ripas_change_destroyed change_destroyed,
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001322 struct smc_result *res)
1323{
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001324 unsigned long index;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001325 long level = wi->last_level;
AlexeiFedorov4faab852023-08-30 15:06:49 +01001326 unsigned long map_size = s2tte_map_size((int)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001327
1328 /* Align to the RTT level */
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001329 unsigned long addr = base & ~(map_size - 1UL);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001330
1331 /* Make sure we don't touch a range below the requested range */
1332 if (addr != base) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001333 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001334 (unsigned char)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001335 return;
1336 }
1337
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001338 for (index = wi->index; index < S2TTES_PER_S2TT; index++) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001339 int ret;
1340
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001341 /*
1342 * Break on "top_align" failure condition,
1343 * or if this entry crosses the range.
1344 */
1345 if ((addr + map_size) > top) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001346 break;
1347 }
1348
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001349 ret = update_ripas(s2_ctx, &s2tt[index], level,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001350 ripas_val, change_destroyed);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001351 if (ret < 0) {
1352 break;
1353 }
1354
1355 /* Handle TLBI */
1356 if (ret != 0) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001357 if (level == S2TT_PAGE_LEVEL) {
1358 s2tt_invalidate_page(s2_ctx, addr);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001359 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001360 s2tt_invalidate_block(s2_ctx, addr);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001361 }
1362 }
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001363
1364 addr += map_size;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001365 }
1366
1367 if (addr > base) {
1368 res->x[0] = RMI_SUCCESS;
1369 res->x[1] = addr;
1370 } else {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001371 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001372 (unsigned char)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001373 }
1374}
1375
1376void smc_rtt_set_ripas(unsigned long rd_addr,
1377 unsigned long rec_addr,
1378 unsigned long base,
1379 unsigned long top,
1380 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001381{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001382 struct granule *g_rd, *g_rec;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001383 struct rec *rec;
1384 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001385 struct s2tt_walk wi;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001386 unsigned long *s2tt;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001387 struct s2tt_context *s2_ctx;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001388 enum ripas ripas_val;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001389 enum ripas_change_destroyed change_destroyed;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001390
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001391 if (top <= base) {
1392 res->x[0] = RMI_ERROR_INPUT;
1393 return;
1394 }
1395
Soby Mathewb4c6df42022-11-09 11:13:29 +00001396 if (!find_lock_two_granules(rd_addr,
1397 GRANULE_STATE_RD,
1398 &g_rd,
1399 rec_addr,
1400 GRANULE_STATE_REC,
1401 &g_rec)) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001402 res->x[0] = RMI_ERROR_INPUT;
1403 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001404 }
1405
AlexeiFedorovd6d93d82024-02-13 16:52:11 +00001406 if (granule_refcount_read_acquire(g_rec) != 0U) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001407 res->x[0] = RMI_ERROR_REC;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001408 goto out_unlock_rec_rd;
1409 }
1410
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001411 rec = buffer_granule_map(g_rec, SLOT_REC);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001412 assert(rec != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001413
1414 if (g_rd != rec->realm_info.g_rd) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001415 res->x[0] = RMI_ERROR_REC;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001416 goto out_unmap_rec;
1417 }
1418
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001419 ripas_val = rec->set_ripas.ripas_val;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001420 change_destroyed = rec->set_ripas.change_destroyed;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001421
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001422 /*
1423 * Return error in case of target region:
1424 * - is not the next chunk of requested region
1425 * - extends beyond the end of requested region
1426 */
1427 if ((base != rec->set_ripas.addr) || (top > rec->set_ripas.top)) {
1428 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001429 goto out_unmap_rec;
1430 }
1431
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001432 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001433 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001434
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001435 /*
1436 * At this point, we know base == rec->set_ripas.addr
1437 * and thus must be aligned to GRANULE size.
1438 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001439 assert(validate_map_addr(base, S2TT_PAGE_LEVEL, rd));
Soby Mathewb4c6df42022-11-09 11:13:29 +00001440
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001441 s2_ctx = &(rd->s2_ctx);
1442 granule_lock(s2_ctx->g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001443
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001444 /* Walk to the deepest level possible */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001445 s2tt_walk_lock_unlock(s2_ctx, base, S2TT_PAGE_LEVEL, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001446
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001447 /*
1448 * Base has to be aligned to the level at which
1449 * it is mapped in RTT.
1450 */
1451 if (!validate_map_addr(base, wi.last_level, rd)) {
1452 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001453 (unsigned char)wi.last_level);
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001454 goto out_unlock_llt;
1455 }
1456
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001457 s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001458 assert(s2tt != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001459
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001460 rtt_set_ripas_range(s2_ctx, s2tt, base, top, &wi,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001461 ripas_val, change_destroyed, res);
1462
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001463 if (res->x[0] == RMI_SUCCESS) {
1464 rec->set_ripas.addr = res->x[1];
Soby Mathewb4c6df42022-11-09 11:13:29 +00001465 }
1466
Soby Mathewb4c6df42022-11-09 11:13:29 +00001467 buffer_unmap(s2tt);
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001468out_unlock_llt:
Soby Mathewb4c6df42022-11-09 11:13:29 +00001469 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001470 buffer_unmap(rd);
1471out_unmap_rec:
1472 buffer_unmap(rec);
1473out_unlock_rec_rd:
1474 granule_unlock(g_rec);
1475 granule_unlock(g_rd);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001476}