blob: 78f0ba1a761f4c0b83938ea5e6fa6da91a03aee0 [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,
125 (unsigned int)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 */
177 __granule_refcount_inc(g_tbl, S2TTES_PER_S2TT);
178
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 */
196 __granule_refcount_inc(g_tbl, S2TTES_PER_S2TT);
197
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 */
221 __granule_refcount_inc(g_tbl, S2TTES_PER_S2TT);
222
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,
252 (unsigned int)(level - 1L));
253 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,
314 (unsigned int)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,
324 (unsigned int)(level - 1L));
325 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)) {
AlexeiFedorov49752c62023-04-24 14:31:14 +0100354 unsigned long s2tte = s2tte_read(&table[0]);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100355
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100356 /*
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100357 * Since s2tt_maps_assigned_ns_block() has succedded,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100358 * the PA in first entry of the table is aligned at
359 * parent level. Use the TTE from the first entry
360 * directly as it also has the NS attributes to be used
361 * for the parent block entry.
362 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000363 parent_s2tte = s2tte_create_assigned_ns(&s2_ctx, s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000364 } else {
365 /*
366 * The table holds a mixture of destroyed and
367 * unassigned entries.
368 */
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100369 ret = pack_return_code(RMI_ERROR_RTT,
370 (unsigned int)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000371 goto out_unmap_table;
372 }
AlexeiFedorov49752c62023-04-24 14:31:14 +0100373 __granule_put(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000374 } else if (g_tbl->refcount == S2TTES_PER_S2TT) {
375
376 unsigned long s2tte, block_pa;
377
378 /* The RMM specification does not allow creating block
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100379 * entries less than S2TT_MIN_BLOCK_LEVEL even though
Soby Mathewb4c6df42022-11-09 11:13:29 +0000380 * permitted by the Arm Architecture.
381 * Hence ensure that the table being folded is at a level
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100382 * higher than the S2TT_MIN_BLOCK_LEVEL.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000383 *
384 * A fully populated table cannot be destroyed if that
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100385 * would create a block mapping below S2TT_MIN_BLOCK_LEVEL.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000386 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100387 if (level <= S2TT_MIN_BLOCK_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100388 ret = pack_return_code(RMI_ERROR_RTT,
389 (unsigned int)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000390 goto out_unmap_table;
391 }
392
393 s2tte = s2tte_read(&table[0]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000394 block_pa = s2tte_pa(&s2_ctx, s2tte, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000395
396 /*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100397 * The table must also refer to a contiguous block through the
AlexeiFedorov3f840a02023-07-19 10:55:05 +0100398 * same type of s2tte, either Assigned or Valid.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000399 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000400 if (s2tt_maps_assigned_empty_block(&s2_ctx, table, level)) {
401 parent_s2tte = s2tte_create_assigned_empty(&s2_ctx,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100402 block_pa, level - 1L);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000403 } else if (s2tt_maps_assigned_ram_block(&s2_ctx,
404 table, level)) {
405 parent_s2tte = s2tte_create_assigned_ram(&s2_ctx,
406 block_pa,
AlexeiFedorov3a739332023-04-13 13:54:04 +0100407 level - 1L);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000408 } else if (s2tt_maps_assigned_destroyed_block(&s2_ctx,
409 table, level)) {
410 parent_s2tte = s2tte_create_assigned_destroyed(&s2_ctx,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100411 block_pa, level - 1L);
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000412 /* The table contains mixed entries that cannot be folded */
Soby Mathewb4c6df42022-11-09 11:13:29 +0000413 } else {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100414 ret = pack_return_code(RMI_ERROR_RTT,
415 (unsigned int)level);
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000416 goto out_unmap_table;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000417 }
418
419 __granule_refcount_dec(g_tbl, S2TTES_PER_S2TT);
420 } else {
421 /*
422 * The table holds a mixture of different types of s2ttes.
423 */
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100424 ret = pack_return_code(RMI_ERROR_RTT,
425 (unsigned int)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000426 goto out_unmap_table;
427 }
428
429 ret = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100430 res->x[1] = rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000431
432 /*
433 * Break before make.
434 */
435 s2tte_write(&parent_s2tt[wi.index], 0UL);
436
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000437 if (s2tte_is_assigned_ram(&s2_ctx, parent_s2tte, level - 1L) ||
438 s2tte_is_assigned_ns(&s2_ctx, parent_s2tte, level - 1L)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100439 s2tt_invalidate_pages_in_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000440 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100441 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000442 }
443
444 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
445
446 granule_memzero_mapped(table);
447 granule_set_state(g_tbl, GRANULE_STATE_DELEGATED);
448
449out_unmap_table:
450 buffer_unmap(table);
451 granule_unlock(g_tbl);
452out_unmap_parent_table:
453 buffer_unmap(parent_s2tt);
454out_unlock_parent_table:
455 granule_unlock(wi.g_llt);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100456 res->x[0] = ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000457}
458
AlexeiFedorove2002be2023-04-19 17:20:12 +0100459void smc_rtt_destroy(unsigned long rd_addr,
460 unsigned long map_addr,
461 unsigned long ulevel,
462 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000463{
464 struct granule *g_rd;
465 struct granule *g_tbl;
466 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100467 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000468 unsigned long *table, *parent_s2tt, parent_s2tte;
469 long level = (long)ulevel;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000470 unsigned long rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000471 unsigned long ret;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000472 struct s2tt_context s2_ctx;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100473 bool in_par, skip_non_live = false;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000474
475 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
476 if (g_rd == NULL) {
AlexeiFedorove2002be2023-04-19 17:20:12 +0100477 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100478 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100479 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000480 }
481
482 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100483 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000484
485 if (!validate_rtt_structure_cmds(map_addr, level, rd)) {
486 buffer_unmap(rd);
487 granule_unlock(g_rd);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100488 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100489 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100490 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000491 }
492
Soby Mathewb4c6df42022-11-09 11:13:29 +0000493 s2_ctx = rd->s2_ctx;
494 in_par = addr_in_par(rd, map_addr);
495 buffer_unmap(rd);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000496 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000497 granule_unlock(g_rd);
498
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000499 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level - 1L, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000500
501 parent_s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100502 assert(parent_s2tt != NULL);
503
Soby Mathewb4c6df42022-11-09 11:13:29 +0000504 parent_s2tte = s2tte_read(&parent_s2tt[wi.index]);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100505
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100506 if ((wi.last_level != (level - 1L)) ||
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000507 !s2tte_is_table(&s2_ctx, parent_s2tte, level - 1L)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100508 ret = pack_return_code(RMI_ERROR_RTT,
509 (unsigned int)wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100510 skip_non_live = true;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000511 goto out_unmap_parent_table;
512 }
513
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000514 rtt_addr = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000515
516 /*
517 * Lock the RTT granule. The 'rtt_addr' is verified, thus can be treated
518 * as an internal granule.
519 */
520 g_tbl = find_lock_granule(rtt_addr, GRANULE_STATE_RTT);
521
522 /*
523 * A table descriptor S2TTE always points to a TABLE granule.
524 */
525 assert(g_tbl != NULL);
526
527 /*
528 * Read the refcount value. RTT granule is always accessed locked, thus
529 * the refcount can be accessed without atomic operations.
530 */
531 if (g_tbl->refcount != 0UL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100532 ret = pack_return_code(RMI_ERROR_RTT, (unsigned int)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000533 goto out_unlock_table;
534 }
535
536 ret = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100537 res->x[1] = rtt_addr;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100538 skip_non_live = true;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000539
540 table = granule_map(g_tbl, SLOT_RTT2);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100541 assert(table != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000542
543 if (in_par) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000544 parent_s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000545 } else {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000546 parent_s2tte = s2tte_create_unassigned_ns(&s2_ctx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000547 }
548
549 __granule_put(wi.g_llt);
550
551 /*
552 * Break before make. Note that this may cause spurious S2 aborts.
553 */
554 s2tte_write(&parent_s2tt[wi.index], 0UL);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000555
556 if (in_par) {
557 /* For protected IPA, all S2TTEs in the RTT will be invalid */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100558 s2tt_invalidate_block(&s2_ctx, map_addr);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000559 } else {
560 /*
561 * For unprotected IPA, invalidate the TLB for the entire range
562 * mapped by the RTT as it may have valid NS mappings.
563 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100564 s2tt_invalidate_pages_in_block(&s2_ctx, map_addr);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000565 }
566
Soby Mathewb4c6df42022-11-09 11:13:29 +0000567 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
568
569 granule_memzero_mapped(table);
570 granule_set_state(g_tbl, GRANULE_STATE_DELEGATED);
571
572 buffer_unmap(table);
573out_unlock_table:
574 granule_unlock(g_tbl);
575out_unmap_parent_table:
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100576 if (skip_non_live) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000577 res->x[2] = s2tt_skip_non_live_entries(&s2_ctx, map_addr,
578 parent_s2tt, &wi);
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100579 } else {
580 res->x[2] = map_addr;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100581 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000582 buffer_unmap(parent_s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000583 granule_unlock(wi.g_llt);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100584 res->x[0] = ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000585}
586
587enum map_unmap_ns_op {
588 MAP_NS,
589 UNMAP_NS
590};
591
592/*
593 * We don't hold a reference on the NS granule when it is
594 * mapped into a realm. Instead we rely on the guarantees
595 * provided by the architecture to ensure that a NS access
596 * to a protected granule is prohibited even within the realm.
597 */
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100598static void map_unmap_ns(unsigned long rd_addr,
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000599 unsigned long map_addr,
600 long level,
601 unsigned long host_s2tte,
602 enum map_unmap_ns_op op,
603 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000604{
605 struct granule *g_rd;
606 struct rd *rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000607 unsigned long *s2tt, s2tte;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100608 struct s2tt_walk wi;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000609 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000610
611 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
612 if (g_rd == NULL) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100613 res->x[0] = RMI_ERROR_INPUT;
614 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000615 }
616
617 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100618 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000619
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000620 s2_ctx = rd->s2_ctx;
621
622 if (op == MAP_NS) {
623 if (!host_ns_s2tte_is_valid(&s2_ctx, host_s2tte, level)) {
624 buffer_unmap(rd);
625 granule_unlock(g_rd);
626 res->x[0] = RMI_ERROR_INPUT;
627 return;
628 }
629 }
630
631
Soby Mathewb4c6df42022-11-09 11:13:29 +0000632 if (!validate_rtt_map_cmds(map_addr, level, rd)) {
633 buffer_unmap(rd);
634 granule_unlock(g_rd);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100635 res->x[0] = RMI_ERROR_INPUT;
636 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000637 }
638
AlexeiFedorovc34e3242023-04-12 11:30:33 +0100639 /* Check if map_addr is outside PAR */
640 if (addr_in_par(rd, map_addr)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000641 buffer_unmap(rd);
642 granule_unlock(g_rd);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100643 res->x[0] = RMI_ERROR_INPUT;
644 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000645 }
646
Soby Mathewb4c6df42022-11-09 11:13:29 +0000647 buffer_unmap(rd);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000648 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000649 granule_unlock(g_rd);
650
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000651 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level, &wi);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100652
653 /*
654 * For UNMAP_NS, we need to map the table and look
655 * for the end of the non-live region.
656 */
AlexeiFedorov14d47ae2023-07-19 15:26:50 +0100657 if ((op == MAP_NS) && (wi.last_level != level)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100658 res->x[0] = pack_return_code(RMI_ERROR_RTT,
659 (unsigned int)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000660 goto out_unlock_llt;
661 }
662
663 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100664 assert(s2tt != NULL);
665
Soby Mathewb4c6df42022-11-09 11:13:29 +0000666 s2tte = s2tte_read(&s2tt[wi.index]);
667
668 if (op == MAP_NS) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000669 if (!s2tte_is_unassigned_ns(&s2_ctx, s2tte)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100670 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000671 (unsigned int)level);
672 goto out_unmap_table;
673 }
674
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000675 s2tte = s2tte_create_assigned_ns(&s2_ctx, host_s2tte, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000676 s2tte_write(&s2tt[wi.index], s2tte);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000677
678 } else if (op == UNMAP_NS) {
679 /*
680 * The following check also verifies that map_addr is outside
681 * PAR, as valid_NS s2tte may only cover outside PAR IPA range.
682 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000683 bool assigned_ns = s2tte_is_assigned_ns(&s2_ctx, s2tte,
684 wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100685
686 if ((wi.last_level != level) || !assigned_ns) {
687 res->x[0] = pack_return_code(RMI_ERROR_RTT,
688 (unsigned int)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000689 goto out_unmap_table;
690 }
691
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000692 s2tte = s2tte_create_unassigned_ns(&s2_ctx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000693 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100694 if (level == S2TT_PAGE_LEVEL) {
695 s2tt_invalidate_page(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000696 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100697 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000698 }
699 }
700
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100701 res->x[0] = RMI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000702
703out_unmap_table:
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100704 if (op == UNMAP_NS) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000705 res->x[1] = s2tt_skip_non_live_entries(&s2_ctx, map_addr,
706 s2tt, &wi);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100707 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000708 buffer_unmap(s2tt);
709out_unlock_llt:
710 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000711}
712
713unsigned long smc_rtt_map_unprotected(unsigned long rd_addr,
714 unsigned long map_addr,
715 unsigned long ulevel,
716 unsigned long s2tte)
717{
718 long level = (long)ulevel;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000719 struct smc_result res = {0UL};
Soby Mathewb4c6df42022-11-09 11:13:29 +0000720
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100721 if ((level < S2TT_MIN_BLOCK_LEVEL) || (level > S2TT_PAGE_LEVEL)) {
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100722 return RMI_ERROR_INPUT;
723 }
724
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100725 map_unmap_ns(rd_addr, map_addr, level, s2tte, MAP_NS, &res);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000726
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100727 return res.x[0];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000728}
729
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100730void smc_rtt_unmap_unprotected(unsigned long rd_addr,
731 unsigned long map_addr,
732 unsigned long ulevel,
733 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000734{
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100735 long level = (long)ulevel;
736
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100737 if ((level < S2TT_MIN_BLOCK_LEVEL) || (level > S2TT_PAGE_LEVEL)) {
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100738 res->x[0] = RMI_ERROR_INPUT;
739 return;
740 }
741
742 map_unmap_ns(rd_addr, map_addr, level, 0UL, UNMAP_NS, res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000743}
744
745void smc_rtt_read_entry(unsigned long rd_addr,
746 unsigned long map_addr,
747 unsigned long ulevel,
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100748 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000749{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000750 struct granule *g_rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000751 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100752 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000753 unsigned long *s2tt, s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000754 long level = (long)ulevel;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000755 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000756
757 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
758 if (g_rd == NULL) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100759 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000760 return;
761 }
762
763 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100764 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000765
766 if (!validate_rtt_entry_cmds(map_addr, level, rd)) {
767 buffer_unmap(rd);
768 granule_unlock(g_rd);
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100769 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000770 return;
771 }
772
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000773 s2_ctx = rd->s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000774 buffer_unmap(rd);
775
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000776 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000777 granule_unlock(g_rd);
778
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000779 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000780 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100781 assert(s2tt != NULL);
782
Soby Mathewb4c6df42022-11-09 11:13:29 +0000783 s2tte = s2tte_read(&s2tt[wi.index]);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100784 res->x[1] = (unsigned long)wi.last_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000785
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000786 if (s2tte_is_unassigned_empty(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100787 res->x[2] = RMI_UNASSIGNED;
788 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100789 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000790 } else if (s2tte_is_unassigned_ram(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100791 res->x[2] = RMI_UNASSIGNED;
792 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100793 res->x[4] = (unsigned long)RIPAS_RAM;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000794 } else if (s2tte_is_unassigned_destroyed(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100795 res->x[2] = RMI_UNASSIGNED;
796 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100797 res->x[4] = (unsigned long)RIPAS_DESTROYED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000798 } else if (s2tte_is_assigned_empty(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100799 res->x[2] = RMI_ASSIGNED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000800 res->x[3] = s2tte_pa(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100801 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000802 } else if (s2tte_is_assigned_ram(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100803 res->x[2] = RMI_ASSIGNED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000804 res->x[3] = s2tte_pa(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100805 res->x[4] = (unsigned long)RIPAS_RAM;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000806 } else if (s2tte_is_assigned_destroyed(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100807 res->x[2] = RMI_ASSIGNED;
808 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100809 res->x[4] = (unsigned long)RIPAS_DESTROYED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000810 } else if (s2tte_is_unassigned_ns(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100811 res->x[2] = RMI_UNASSIGNED;
812 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100813 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000814 } else if (s2tte_is_assigned_ns(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100815 res->x[2] = RMI_ASSIGNED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000816 res->x[3] = host_ns_s2tte(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100817 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000818 } else if (s2tte_is_table(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100819 res->x[2] = RMI_TABLE;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000820 res->x[3] = s2tte_pa(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100821 res->x[4] = (unsigned long)RIPAS_EMPTY;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000822 } else {
823 assert(false);
824 }
825
826 buffer_unmap(s2tt);
827 granule_unlock(wi.g_llt);
828
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100829 res->x[0] = RMI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000830}
831
Soby Mathewb4c6df42022-11-09 11:13:29 +0000832static unsigned long validate_data_create_unknown(unsigned long map_addr,
833 struct rd *rd)
834{
835 if (!addr_in_par(rd, map_addr)) {
836 return RMI_ERROR_INPUT;
837 }
838
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100839 if (!validate_map_addr(map_addr, S2TT_PAGE_LEVEL, rd)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000840 return RMI_ERROR_INPUT;
841 }
842
843 return RMI_SUCCESS;
844}
845
846static unsigned long validate_data_create(unsigned long map_addr,
847 struct rd *rd)
848{
Mate Toth-Pal988dfcb2024-01-19 10:52:06 +0100849 if (get_rd_state_locked(rd) != REALM_NEW) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000850 return RMI_ERROR_REALM;
851 }
852
853 return validate_data_create_unknown(map_addr, rd);
854}
855
856/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100857 * Implements both RMI_DATA_CREATE and RMI_DATA_CREATE_UNKNOWN
Soby Mathewb4c6df42022-11-09 11:13:29 +0000858 *
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100859 * if @g_src == NULL, implements RMI_DATA_CREATE_UNKNOWN
860 * and RMI_DATA_CREATE otherwise.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000861 */
AlexeiFedorovac923c82023-04-06 15:12:04 +0100862static unsigned long data_create(unsigned long rd_addr,
863 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000864 unsigned long map_addr,
865 struct granule *g_src,
866 unsigned long flags)
867{
868 struct granule *g_data;
869 struct granule *g_rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000870 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100871 struct s2tt_walk wi;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000872 struct s2tt_context *s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000873 unsigned long s2tte, *s2tt;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000874 enum granule_state new_data_state = GRANULE_STATE_DELEGATED;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000875 unsigned long ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000876
877 if (!find_lock_two_granules(data_addr,
878 GRANULE_STATE_DELEGATED,
879 &g_data,
880 rd_addr,
881 GRANULE_STATE_RD,
882 &g_rd)) {
883 return RMI_ERROR_INPUT;
884 }
885
886 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100887 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000888
889 ret = (g_src != NULL) ?
890 validate_data_create(map_addr, rd) :
891 validate_data_create_unknown(map_addr, rd);
892
893 if (ret != RMI_SUCCESS) {
894 goto out_unmap_rd;
895 }
896
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000897 s2_ctx = &(rd->s2_ctx);
898 granule_lock(s2_ctx->g_rtt, GRANULE_STATE_RTT);
899
900 s2tt_walk_lock_unlock(s2_ctx, map_addr, S2TT_PAGE_LEVEL, &wi);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100901 if (wi.last_level != S2TT_PAGE_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100902 ret = pack_return_code(RMI_ERROR_RTT,
903 (unsigned int)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000904 goto out_unlock_ll_table;
905 }
906
907 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100908 assert(s2tt != NULL);
909
Soby Mathewb4c6df42022-11-09 11:13:29 +0000910 s2tte = s2tte_read(&s2tt[wi.index]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000911 if (!s2tte_is_unassigned(s2_ctx, s2tte)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100912 ret = pack_return_code(RMI_ERROR_RTT, S2TT_PAGE_LEVEL);
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100913 goto out_unmap_ll_table;
914 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000915
Soby Mathewb4c6df42022-11-09 11:13:29 +0000916 if (g_src != NULL) {
917 bool ns_access_ok;
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100918 void *data = granule_map(g_data, SLOT_DELEGATED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000919
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100920 assert(data != NULL);
921
Soby Mathewb4c6df42022-11-09 11:13:29 +0000922 ns_access_ok = ns_buffer_read(SLOT_NS, g_src, 0U,
923 GRANULE_SIZE, data);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000924 if (!ns_access_ok) {
925 /*
926 * Some data may be copied before the failure. Zero
927 * g_data granule as it will remain in delegated state.
928 */
929 (void)memset(data, 0, GRANULE_SIZE);
930 buffer_unmap(data);
931 ret = RMI_ERROR_INPUT;
932 goto out_unmap_ll_table;
933 }
934
Mate Toth-Palc7698312023-08-09 12:49:34 +0200935 measurement_data_granule_measure(
936 rd->measurement[RIM_MEASUREMENT_SLOT],
937 rd->algorithm,
938 data,
939 map_addr,
940 flags);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000941 buffer_unmap(data);
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100942
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000943 s2tte = s2tte_create_assigned_ram(s2_ctx, data_addr,
944 S2TT_PAGE_LEVEL);
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100945 } else {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000946 s2tte = s2tte_create_assigned_unchanged(s2_ctx, s2tte,
947 data_addr,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100948 S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000949 }
950
951 new_data_state = GRANULE_STATE_DATA;
952
Soby Mathewb4c6df42022-11-09 11:13:29 +0000953 s2tte_write(&s2tt[wi.index], s2tte);
954 __granule_get(wi.g_llt);
955
956 ret = RMI_SUCCESS;
957
958out_unmap_ll_table:
959 buffer_unmap(s2tt);
960out_unlock_ll_table:
961 granule_unlock(wi.g_llt);
962out_unmap_rd:
963 buffer_unmap(rd);
964 granule_unlock(g_rd);
965 granule_unlock_transition(g_data, new_data_state);
966 return ret;
967}
968
AlexeiFedorovac923c82023-04-06 15:12:04 +0100969unsigned long smc_data_create(unsigned long rd_addr,
970 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000971 unsigned long map_addr,
972 unsigned long src_addr,
973 unsigned long flags)
974{
975 struct granule *g_src;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000976
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100977 if ((flags != RMI_NO_MEASURE_CONTENT) &&
978 (flags != RMI_MEASURE_CONTENT)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000979 return RMI_ERROR_INPUT;
980 }
981
982 g_src = find_granule(src_addr);
983 if ((g_src == NULL) || (g_src->state != GRANULE_STATE_NS)) {
984 return RMI_ERROR_INPUT;
985 }
986
AlexeiFedorovac923c82023-04-06 15:12:04 +0100987 return data_create(rd_addr, data_addr, map_addr, g_src, flags);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000988}
989
AlexeiFedorovac923c82023-04-06 15:12:04 +0100990unsigned long smc_data_create_unknown(unsigned long rd_addr,
991 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000992 unsigned long map_addr)
993{
AlexeiFedorovac923c82023-04-06 15:12:04 +0100994 return data_create(rd_addr, data_addr, map_addr, NULL, 0);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000995}
996
AlexeiFedorove2002be2023-04-19 17:20:12 +0100997void smc_data_destroy(unsigned long rd_addr,
998 unsigned long map_addr,
999 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001000{
1001 struct granule *g_data;
1002 struct granule *g_rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001003 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001004 unsigned long data_addr, s2tte, *s2tt;
1005 struct rd *rd;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +00001006 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001007
1008 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
1009 if (g_rd == NULL) {
AlexeiFedorove2002be2023-04-19 17:20:12 +01001010 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorova1b2a1d2023-07-18 15:08:47 +01001011 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001012 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001013 }
1014
1015 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001016 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001017
AlexeiFedorov868a6512023-09-14 13:21:11 +01001018 if (!addr_in_par(rd, map_addr) ||
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001019 !validate_map_addr(map_addr, S2TT_PAGE_LEVEL, rd)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001020 buffer_unmap(rd);
1021 granule_unlock(g_rd);
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
Soby Mathewb4c6df42022-11-09 11:13:29 +00001027 s2_ctx = rd->s2_ctx;
1028 buffer_unmap(rd);
1029
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001030 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001031 granule_unlock(g_rd);
1032
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001033 s2tt_walk_lock_unlock(&s2_ctx, map_addr, S2TT_PAGE_LEVEL, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001034 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001035 assert(s2tt != NULL);
1036
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001037 if (wi.last_level != S2TT_PAGE_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001038 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1039 (unsigned int)wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001040 goto out_unmap_ll_table;
1041 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001042
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001043 s2tte = s2tte_read(&s2tt[wi.index]);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001044
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001045 if (s2tte_is_assigned_ram(&s2_ctx, s2tte, S2TT_PAGE_LEVEL)) {
1046 data_addr = s2tte_pa(&s2_ctx, s2tte, S2TT_PAGE_LEVEL);
1047 s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001048 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001049 s2tt_invalidate_page(&s2_ctx, map_addr);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001050 } else if (s2tte_is_assigned_empty(&s2_ctx, s2tte, S2TT_PAGE_LEVEL)) {
1051 data_addr = s2tte_pa(&s2_ctx, s2tte, S2TT_PAGE_LEVEL);
1052 s2tte = s2tte_create_unassigned_empty(&s2_ctx);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001053 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001054 } else if (s2tte_is_assigned_destroyed(&s2_ctx, s2tte,
1055 S2TT_PAGE_LEVEL)) {
1056 data_addr = s2tte_pa(&s2_ctx, s2tte, S2TT_PAGE_LEVEL);
1057 s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +01001058 s2tte_write(&s2tt[wi.index], s2tte);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001059 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001060 res->x[0] = pack_return_code(RMI_ERROR_RTT, S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001061 goto out_unmap_ll_table;
1062 }
1063
Soby Mathewb4c6df42022-11-09 11:13:29 +00001064 __granule_put(wi.g_llt);
1065
1066 /*
1067 * Lock the data granule and check expected state. Correct locking order
1068 * is guaranteed because granule address is obtained from a locked
1069 * granule by table walk. This lock needs to be acquired before a state
1070 * transition to or from GRANULE_STATE_DATA for granule address can happen.
1071 */
1072 g_data = find_lock_granule(data_addr, GRANULE_STATE_DATA);
AlexeiFedorov63b71692023-04-19 11:18:42 +01001073 assert(g_data != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001074 granule_memzero(g_data, SLOT_DELEGATED);
1075 granule_unlock_transition(g_data, GRANULE_STATE_DELEGATED);
1076
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001077 res->x[0] = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001078 res->x[1] = data_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001079out_unmap_ll_table:
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001080 res->x[2] = s2tt_skip_non_live_entries(&s2_ctx, map_addr, s2tt, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001081 buffer_unmap(s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001082 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001083}
1084
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001085/*
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001086 * Update the ripas value for the entry pointed by @s2ttep.
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001087 *
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001088 * Returns:
1089 * < 0 - On error and the operation was aborted,
1090 * e.g., entry cannot have a ripas.
1091 * 0 - Operation was success and no TLBI is required.
1092 * > 0 - Operation was success and TLBI is required.
1093 * Sets:
1094 * @(*do_tlbi) to 'true' if the TLBs have to be invalidated.
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001095 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001096static int update_ripas(const struct s2tt_context *s2_ctx,
1097 unsigned long *s2ttep, long level,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001098 enum ripas ripas_val,
1099 enum ripas_change_destroyed change_destroyed)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001100{
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001101 unsigned long pa, s2tte = s2tte_read(s2ttep);
1102 int ret = 0;
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001103
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001104 assert(s2_ctx != NULL);
1105
1106 if (!s2tte_has_ripas(s2_ctx, s2tte, level)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001107 return -EPERM;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001108 }
1109
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001110 if (ripas_val == RIPAS_RAM) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001111 if (s2tte_is_unassigned_empty(s2_ctx, s2tte)) {
1112 s2tte = s2tte_create_unassigned_ram(s2_ctx);
1113 } else if (s2tte_is_unassigned_destroyed(s2_ctx, s2tte)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001114 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001115 s2tte = s2tte_create_unassigned_ram(s2_ctx);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001116 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001117 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001118 }
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001119 } else if (s2tte_is_assigned_empty(s2_ctx, s2tte, level)) {
1120 pa = s2tte_pa(s2_ctx, s2tte, level);
1121 s2tte = s2tte_create_assigned_ram(s2_ctx, pa, level);
1122 } else if (s2tte_is_assigned_destroyed(s2_ctx, s2tte, level)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001123 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001124 pa = s2tte_pa(s2_ctx, s2tte, level);
1125 s2tte = s2tte_create_assigned_ram(s2_ctx, pa,
1126 level);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001127 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001128 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001129 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001130 } else {
1131 /* No action is required */
1132 return 0;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001133 }
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001134 } else if (ripas_val == RIPAS_EMPTY) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001135 if (s2tte_is_unassigned_ram(s2_ctx, s2tte)) {
1136 s2tte = s2tte_create_unassigned_empty(s2_ctx);
1137 } else if (s2tte_is_unassigned_destroyed(s2_ctx, s2tte)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001138 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001139 s2tte = s2tte_create_unassigned_empty(s2_ctx);
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 }
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001143 } else if (s2tte_is_assigned_ram(s2_ctx, s2tte, level)) {
1144 pa = s2tte_pa(s2_ctx, s2tte, level);
1145 s2tte = s2tte_create_assigned_empty(s2_ctx, pa, level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001146 /* TLBI is required */
1147 ret = 1;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001148 } else if (s2tte_is_assigned_destroyed(s2_ctx, s2tte, level)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001149 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001150 pa = s2tte_pa(s2_ctx, s2tte, level);
1151 s2tte = s2tte_create_assigned_empty(s2_ctx,
1152 pa, level);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001153 /* TLBI is required */
1154 ret = 1;
1155 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001156 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001157 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001158 } else {
1159 /* No action is required */
1160 return 0;
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001161 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001162 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001163 s2tte_write(s2ttep, s2tte);
1164 return ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001165}
1166
AlexeiFedorov960d1612023-04-25 13:23:39 +01001167void smc_rtt_init_ripas(unsigned long rd_addr,
1168 unsigned long base,
1169 unsigned long top,
1170 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001171{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001172 struct granule *g_rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001173 struct rd *rd;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001174 unsigned long addr, map_size;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001175 struct s2tt_walk wi;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001176 struct s2tt_context *s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001177 unsigned long s2tte, *s2tt;
AlexeiFedorov960d1612023-04-25 13:23:39 +01001178 long level;
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001179 unsigned long index;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001180
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001181 if (top <= base) {
1182 res->x[0] = RMI_ERROR_INPUT;
1183 return;
1184 }
1185
Soby Mathewb4c6df42022-11-09 11:13:29 +00001186 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
1187 if (g_rd == NULL) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001188 res->x[0] = RMI_ERROR_INPUT;
1189 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001190 }
1191
1192 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001193 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001194
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001195 if (!validate_map_addr(base, S2TT_PAGE_LEVEL, rd) ||
1196 !validate_map_addr(top, S2TT_PAGE_LEVEL, rd) ||
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001197 !addr_in_par(rd, base) || !addr_in_par(rd, top - GRANULE_SIZE)) {
1198 buffer_unmap(rd);
1199 granule_unlock(g_rd);
1200 res->x[0] = RMI_ERROR_INPUT;
1201 return;
1202 }
1203
Mate Toth-Pal988dfcb2024-01-19 10:52:06 +01001204 if (get_rd_state_locked(rd) != REALM_NEW) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001205 buffer_unmap(rd);
1206 granule_unlock(g_rd);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001207 res->x[0] = RMI_ERROR_REALM;
1208 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001209 }
1210
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001211 s2_ctx = &(rd->s2_ctx);
1212 granule_lock(s2_ctx->g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001213
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001214 s2tt_walk_lock_unlock(s2_ctx, base, S2TT_PAGE_LEVEL, &wi);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001215 level = wi.last_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001216 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001217 assert(s2tt != NULL);
1218
AlexeiFedorov960d1612023-04-25 13:23:39 +01001219 map_size = s2tte_map_size(level);
1220 addr = base & ~(map_size - 1UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001221
AlexeiFedorov960d1612023-04-25 13:23:39 +01001222 /*
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001223 * If the RTTE covers a range below "base", we need to go deeper.
AlexeiFedorov960d1612023-04-25 13:23:39 +01001224 */
1225 if (addr != base) {
1226 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1227 (unsigned int)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001228 goto out_unmap_llt;
1229 }
1230
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001231 for (index = wi.index; index < S2TTES_PER_S2TT; index++) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001232 unsigned long next = addr + map_size;
1233
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001234 /*
1235 * Break on "top_align" failure condition,
1236 * or if this entry crosses the range.
1237 */
AlexeiFedorov960d1612023-04-25 13:23:39 +01001238 if (next > top) {
1239 break;
1240 }
1241
1242 s2tte = s2tte_read(&s2tt[index]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001243 if (s2tte_is_unassigned_empty(s2_ctx, s2tte)) {
1244 s2tte = s2tte_create_unassigned_ram(s2_ctx);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001245 s2tte_write(&s2tt[index], s2tte);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001246 } else if (!s2tte_is_unassigned_ram(s2_ctx, s2tte)) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001247 break;
1248 }
Mate Toth-Palc7698312023-08-09 12:49:34 +02001249 measurement_init_ripas_measure(rd->measurement[RIM_MEASUREMENT_SLOT],
1250 rd->algorithm,
1251 addr,
1252 next);
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001253 addr = next;
AlexeiFedorov960d1612023-04-25 13:23:39 +01001254 }
1255
1256 if (addr > base) {
1257 res->x[0] = RMI_SUCCESS;
1258 res->x[1] = addr;
1259 } else {
1260 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1261 (unsigned int)level);
1262 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001263
1264out_unmap_llt:
1265 buffer_unmap(s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001266 buffer_unmap(rd);
1267 granule_unlock(wi.g_llt);
AlexeiFedorov80295e42023-07-10 13:11:14 +01001268 granule_unlock(g_rd);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001269}
1270
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +00001271static void rtt_set_ripas_range(struct s2tt_context *s2_ctx,
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001272 unsigned long *s2tt,
1273 unsigned long base,
1274 unsigned long top,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001275 struct s2tt_walk *wi,
AlexeiFedorov4faab852023-08-30 15:06:49 +01001276 enum ripas ripas_val,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001277 enum ripas_change_destroyed change_destroyed,
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001278 struct smc_result *res)
1279{
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001280 unsigned long index;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001281 long level = wi->last_level;
AlexeiFedorov4faab852023-08-30 15:06:49 +01001282 unsigned long map_size = s2tte_map_size((int)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001283
1284 /* Align to the RTT level */
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001285 unsigned long addr = base & ~(map_size - 1UL);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001286
1287 /* Make sure we don't touch a range below the requested range */
1288 if (addr != base) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001289 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1290 (unsigned int)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001291 return;
1292 }
1293
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001294 for (index = wi->index; index < S2TTES_PER_S2TT; index++) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001295 int ret;
1296
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001297 /*
1298 * Break on "top_align" failure condition,
1299 * or if this entry crosses the range.
1300 */
1301 if ((addr + map_size) > top) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001302 break;
1303 }
1304
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001305 ret = update_ripas(s2_ctx, &s2tt[index], level,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001306 ripas_val, change_destroyed);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001307 if (ret < 0) {
1308 break;
1309 }
1310
1311 /* Handle TLBI */
1312 if (ret != 0) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001313 if (level == S2TT_PAGE_LEVEL) {
1314 s2tt_invalidate_page(s2_ctx, addr);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001315 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001316 s2tt_invalidate_block(s2_ctx, addr);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001317 }
1318 }
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001319
1320 addr += map_size;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001321 }
1322
1323 if (addr > base) {
1324 res->x[0] = RMI_SUCCESS;
1325 res->x[1] = addr;
1326 } else {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001327 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1328 (unsigned int)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001329 }
1330}
1331
1332void smc_rtt_set_ripas(unsigned long rd_addr,
1333 unsigned long rec_addr,
1334 unsigned long base,
1335 unsigned long top,
1336 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001337{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001338 struct granule *g_rd, *g_rec;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001339 struct rec *rec;
1340 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001341 struct s2tt_walk wi;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001342 unsigned long *s2tt;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001343 struct s2tt_context *s2_ctx;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001344 enum ripas ripas_val;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001345 enum ripas_change_destroyed change_destroyed;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001346
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001347 if (top <= base) {
1348 res->x[0] = RMI_ERROR_INPUT;
1349 return;
1350 }
1351
Soby Mathewb4c6df42022-11-09 11:13:29 +00001352 if (!find_lock_two_granules(rd_addr,
1353 GRANULE_STATE_RD,
1354 &g_rd,
1355 rec_addr,
1356 GRANULE_STATE_REC,
1357 &g_rec)) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001358 res->x[0] = RMI_ERROR_INPUT;
1359 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001360 }
1361
1362 if (granule_refcount_read_acquire(g_rec) != 0UL) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001363 res->x[0] = RMI_ERROR_REC;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001364 goto out_unlock_rec_rd;
1365 }
1366
1367 rec = granule_map(g_rec, SLOT_REC);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001368 assert(rec != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001369
1370 if (g_rd != rec->realm_info.g_rd) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001371 res->x[0] = RMI_ERROR_REC;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001372 goto out_unmap_rec;
1373 }
1374
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001375 ripas_val = rec->set_ripas.ripas_val;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001376 change_destroyed = rec->set_ripas.change_destroyed;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001377
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001378 /*
1379 * Return error in case of target region:
1380 * - is not the next chunk of requested region
1381 * - extends beyond the end of requested region
1382 */
1383 if ((base != rec->set_ripas.addr) || (top > rec->set_ripas.top)) {
1384 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001385 goto out_unmap_rec;
1386 }
1387
1388 rd = granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001389 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001390
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001391 /*
1392 * At this point, we know base == rec->set_ripas.addr
1393 * and thus must be aligned to GRANULE size.
1394 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001395 assert(validate_map_addr(base, S2TT_PAGE_LEVEL, rd));
Soby Mathewb4c6df42022-11-09 11:13:29 +00001396
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001397 s2_ctx = &(rd->s2_ctx);
1398 granule_lock(s2_ctx->g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001399
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001400 /* Walk to the deepest level possible */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001401 s2tt_walk_lock_unlock(s2_ctx, base, S2TT_PAGE_LEVEL, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001402
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001403 /*
1404 * Base has to be aligned to the level at which
1405 * it is mapped in RTT.
1406 */
1407 if (!validate_map_addr(base, wi.last_level, rd)) {
1408 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1409 (unsigned int)wi.last_level);
1410 goto out_unlock_llt;
1411 }
1412
Soby Mathewb4c6df42022-11-09 11:13:29 +00001413 s2tt = granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001414 assert(s2tt != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001415
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001416 rtt_set_ripas_range(s2_ctx, s2tt, base, top, &wi,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001417 ripas_val, change_destroyed, res);
1418
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001419 if (res->x[0] == RMI_SUCCESS) {
1420 rec->set_ripas.addr = res->x[1];
Soby Mathewb4c6df42022-11-09 11:13:29 +00001421 }
1422
Soby Mathewb4c6df42022-11-09 11:13:29 +00001423 buffer_unmap(s2tt);
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001424out_unlock_llt:
Soby Mathewb4c6df42022-11-09 11:13:29 +00001425 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001426 buffer_unmap(rd);
1427out_unmap_rec:
1428 buffer_unmap(rec);
1429out_unlock_rec_rd:
1430 granule_unlock(g_rec);
1431 granule_unlock(g_rd);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001432}