blob: 2e4671071e214d0d711830ce3a3a73e04d45b21b [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 /*
115 * Lock the RTT root. Enforcing locking order RD->RTT is enough to
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000116 * ensure deadlock free locking guarantee.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000117 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000118 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000119
120 /* Unlock RD after locking RTT Root */
121 granule_unlock(g_rd);
122
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000123 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level - 1L, &wi);
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100124 if (wi.last_level != (level - 1L)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100125 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000126 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000127 goto out_unlock_llt;
128 }
129
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000130 parent_s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100131 assert(parent_s2tt != NULL);
132
Soby Mathewb4c6df42022-11-09 11:13:29 +0000133 parent_s2tte = s2tte_read(&parent_s2tt[wi.index]);
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000134 s2tt = buffer_granule_map(g_tbl, SLOT_DELEGATED);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100135 assert(s2tt != NULL);
136
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000137 if (s2tte_is_unassigned_empty(&s2_ctx, parent_s2tte)) {
138 s2tt_init_unassigned_empty(&s2_ctx, s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000139
140 /*
AlexeiFedorov745499d2024-04-25 16:52:44 +0100141 * Atomically increase the refcount of the parent, the granule
142 * was locked while table walking and hand-over-hand locking.
143 * Acquire/release semantics not required because the table is
144 * accessed always locked.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000145 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100146 atomic_granule_get(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000147
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000148 } else if (s2tte_is_unassigned_ram(&s2_ctx, parent_s2tte)) {
149 s2tt_init_unassigned_ram(&s2_ctx, s2tt);
AlexeiFedorov745499d2024-04-25 16:52:44 +0100150 atomic_granule_get(wi.g_llt);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100151
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000152 } else if (s2tte_is_unassigned_ns(&s2_ctx, parent_s2tte)) {
153 s2tt_init_unassigned_ns(&s2_ctx, s2tt);
AlexeiFedorov745499d2024-04-25 16:52:44 +0100154 atomic_granule_get(wi.g_llt);
AlexeiFedorov5ceff352023-04-12 16:17:00 +0100155
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000156 } else if (s2tte_is_unassigned_destroyed(&s2_ctx, parent_s2tte)) {
157 s2tt_init_unassigned_destroyed(&s2_ctx, s2tt);
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_assigned_destroyed(&s2_ctx, parent_s2tte,
161 level - 1L)) {
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100162 unsigned long block_pa;
163
164 /*
165 * We should observe parent assigned s2tte only when
166 * we create tables above this level.
167 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100168 assert(level > S2TT_MIN_BLOCK_LEVEL);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100169
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000170 block_pa = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100171
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000172 s2tt_init_assigned_destroyed(&s2_ctx, s2tt, block_pa, level);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100173
174 /*
175 * Increase the refcount to mark the granule as in-use. refcount
176 * is incremented by S2TTES_PER_S2TT (ref RTT unfolding).
177 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100178 granule_refcount_inc(g_tbl, (unsigned short)S2TTES_PER_S2TT);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +0100179
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000180 } else if (s2tte_is_assigned_empty(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000181 unsigned long block_pa;
182
183 /*
184 * We should observe parent assigned s2tte only when
185 * we create tables above this level.
186 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100187 assert(level > S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000188
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000189 block_pa = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000190
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000191 s2tt_init_assigned_empty(&s2_ctx, s2tt, block_pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000192
193 /*
194 * Increase the refcount to mark the granule as in-use. refcount
195 * is incremented by S2TTES_PER_S2TT (ref RTT unfolding).
196 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100197 granule_refcount_inc(g_tbl, (unsigned short)S2TTES_PER_S2TT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000198
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000199 } else if (s2tte_is_assigned_ram(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000200 unsigned long block_pa;
201
202 /*
203 * We should observe parent valid s2tte only when
204 * we create tables above this level.
205 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100206 assert(level > S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000207
208 /*
209 * Break before make. This may cause spurious S2 aborts.
210 */
211 s2tte_write(&parent_s2tt[wi.index], 0UL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100212 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000213
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000214 block_pa = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000215
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000216 s2tt_init_assigned_ram(&s2_ctx, s2tt, block_pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000217
218 /*
219 * Increase the refcount to mark the granule as in-use. refcount
220 * is incremented by S2TTES_PER_S2TT (ref RTT unfolding).
221 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100222 granule_refcount_inc(g_tbl, (unsigned short)S2TTES_PER_S2TT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000223
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000224 } else if (s2tte_is_assigned_ns(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000225 unsigned long block_pa;
226
227 /*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100228 * We should observe parent assigned_ns s2tte only when
Soby Mathewb4c6df42022-11-09 11:13:29 +0000229 * we create tables above this level.
230 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100231 assert(level > S2TT_MIN_BLOCK_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000232
233 /*
234 * Break before make. This may cause spurious S2 aborts.
235 */
236 s2tte_write(&parent_s2tt[wi.index], 0UL);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100237 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000238
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000239 block_pa = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000240
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000241 s2tt_init_assigned_ns(&s2_ctx, s2tt, parent_s2tte,
242 block_pa, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000243
244 /*
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100245 * Increment the refcount on the parent for the new RTT we are
246 * about to add. The NS block entry doesn't have a refcount
247 * on the parent RTT.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000248 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100249 atomic_granule_get(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000250
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000251 } else if (s2tte_is_table(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000252 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000253 (unsigned char)(level - 1L));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000254 goto out_unmap_table;
255
256 } else {
257 assert(false);
258 }
259
260 ret = RMI_SUCCESS;
261
262 granule_set_state(g_tbl, GRANULE_STATE_RTT);
263
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000264 parent_s2tte = s2tte_create_table(&s2_ctx, rtt_addr, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000265 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
266
267out_unmap_table:
268 buffer_unmap(s2tt);
269 buffer_unmap(parent_s2tt);
270out_unlock_llt:
271 granule_unlock(wi.g_llt);
272 granule_unlock(g_tbl);
273 return ret;
274}
275
AlexeiFedorove2002be2023-04-19 17:20:12 +0100276void smc_rtt_fold(unsigned long rd_addr,
277 unsigned long map_addr,
278 unsigned long ulevel,
279 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000280{
281 struct granule *g_rd;
282 struct granule *g_tbl;
283 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100284 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000285 unsigned long *table, *parent_s2tt, parent_s2tte;
286 long level = (long)ulevel;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000287 unsigned long rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000288 unsigned long ret;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000289 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000290
291 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
292 if (g_rd == NULL) {
AlexeiFedorove2002be2023-04-19 17:20:12 +0100293 res->x[0] = RMI_ERROR_INPUT;
294 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000295 }
296
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000297 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100298 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000299
300 if (!validate_rtt_structure_cmds(map_addr, level, rd)) {
301 buffer_unmap(rd);
302 granule_unlock(g_rd);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100303 res->x[0] = RMI_ERROR_INPUT;
304 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000305 }
306
Soby Mathewb4c6df42022-11-09 11:13:29 +0000307 s2_ctx = rd->s2_ctx;
308 buffer_unmap(rd);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000309 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000310 granule_unlock(g_rd);
311
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000312 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level - 1L, &wi);
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100313 if (wi.last_level != (level - 1L)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100314 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000315 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000316 goto out_unlock_parent_table;
317 }
318
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000319 parent_s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100320 assert(parent_s2tt != NULL);
321
Soby Mathewb4c6df42022-11-09 11:13:29 +0000322 parent_s2tte = s2tte_read(&parent_s2tt[wi.index]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000323 if (!s2tte_is_table(&s2_ctx, parent_s2tte, level - 1L)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000324 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000325 (unsigned char)(level - 1L));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000326 goto out_unmap_parent_table;
327 }
328
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000329 rtt_addr = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000330 g_tbl = find_lock_granule(rtt_addr, GRANULE_STATE_RTT);
331
332 /*
333 * A table descriptor S2TTE always points to a TABLE granule.
334 */
AlexeiFedorov63b71692023-04-19 11:18:42 +0100335 assert(g_tbl != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000336
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000337 table = buffer_granule_map(g_tbl, SLOT_RTT2);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100338 assert(table != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000339
340 /*
341 * The command can succeed only if all 512 S2TTEs are of the same type.
342 * We first check the table's ref. counter to speed up the case when
343 * the host makes a guess whether a memory region can be folded.
344 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100345 if (granule_refcount_read(g_tbl) == 0U) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000346 if (s2tt_is_unassigned_destroyed_block(&s2_ctx, table)) {
347 parent_s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
348 } else if (s2tt_is_unassigned_empty_block(&s2_ctx, table)) {
349 parent_s2tte = s2tte_create_unassigned_empty(&s2_ctx);
350 } else if (s2tt_is_unassigned_ram_block(&s2_ctx, table)) {
351 parent_s2tte = s2tte_create_unassigned_ram(&s2_ctx);
352 } else if (s2tt_is_unassigned_ns_block(&s2_ctx, table)) {
353 parent_s2tte = s2tte_create_unassigned_ns(&s2_ctx);
354 } else if (s2tt_maps_assigned_ns_block(&s2_ctx, table, level)) {
Shruti Gupta3105c3f2024-02-26 14:06:11 +0000355
356 /*
357 * The RMM specification does not allow creating block entries less than
358 * S2TT_MIN_BLOCK_LEVEL for ASSIGNED_NS state.
359 */
360 if (level <= S2TT_MIN_BLOCK_LEVEL) {
361 ret = pack_return_code(RMI_ERROR_RTT,
362 (unsigned char)wi.last_level);
363 goto out_unmap_table;
364 }
AlexeiFedorov49752c62023-04-24 14:31:14 +0100365 unsigned long s2tte = s2tte_read(&table[0]);
AlexeiFedorovc07a6382023-04-14 11:59:18 +0100366
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100367 /*
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100368 * Since s2tt_maps_assigned_ns_block() has succedded,
Javier Almansa Sobrino15fc44e2023-09-29 13:52:04 +0100369 * the PA in first entry of the table is aligned at
370 * parent level. Use the TTE from the first entry
371 * directly as it also has the NS attributes to be used
372 * for the parent block entry.
373 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000374 parent_s2tte = s2tte_create_assigned_ns(&s2_ctx, s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000375 } else {
376 /*
377 * The table holds a mixture of destroyed and
378 * unassigned entries.
379 */
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100380 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000381 (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000382 goto out_unmap_table;
383 }
AlexeiFedorov745499d2024-04-25 16:52:44 +0100384 atomic_granule_put(wi.g_llt);
385 } else if (granule_refcount_read(g_tbl) ==
386 (unsigned short)S2TTES_PER_S2TT) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000387
388 unsigned long s2tte, block_pa;
389
390 /* The RMM specification does not allow creating block
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100391 * entries less than S2TT_MIN_BLOCK_LEVEL even though
Soby Mathewb4c6df42022-11-09 11:13:29 +0000392 * permitted by the Arm Architecture.
393 * Hence ensure that the table being folded is at a level
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100394 * higher than the S2TT_MIN_BLOCK_LEVEL.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000395 *
396 * A fully populated table cannot be destroyed if that
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100397 * would create a block mapping below S2TT_MIN_BLOCK_LEVEL.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000398 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100399 if (level <= S2TT_MIN_BLOCK_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100400 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000401 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000402 goto out_unmap_table;
403 }
404
405 s2tte = s2tte_read(&table[0]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000406 block_pa = s2tte_pa(&s2_ctx, s2tte, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000407
408 /*
AlexeiFedorov3a739332023-04-13 13:54:04 +0100409 * The table must also refer to a contiguous block through the
AlexeiFedorov3f840a02023-07-19 10:55:05 +0100410 * same type of s2tte, either Assigned or Valid.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000411 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000412 if (s2tt_maps_assigned_empty_block(&s2_ctx, table, level)) {
413 parent_s2tte = s2tte_create_assigned_empty(&s2_ctx,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100414 block_pa, level - 1L);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000415 } else if (s2tt_maps_assigned_ram_block(&s2_ctx,
416 table, level)) {
417 parent_s2tte = s2tte_create_assigned_ram(&s2_ctx,
418 block_pa,
AlexeiFedorov3a739332023-04-13 13:54:04 +0100419 level - 1L);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000420 } else if (s2tt_maps_assigned_destroyed_block(&s2_ctx,
421 table, level)) {
422 parent_s2tte = s2tte_create_assigned_destroyed(&s2_ctx,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100423 block_pa, level - 1L);
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000424 /* The table contains mixed entries that cannot be folded */
Soby Mathewb4c6df42022-11-09 11:13:29 +0000425 } else {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100426 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000427 (unsigned char)level);
AlexeiFedorov80c2f042022-11-25 14:54:46 +0000428 goto out_unmap_table;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000429 }
430
AlexeiFedorov745499d2024-04-25 16:52:44 +0100431 granule_refcount_dec(g_tbl, (unsigned short)S2TTES_PER_S2TT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000432 } else {
433 /*
434 * The table holds a mixture of different types of s2ttes.
435 */
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100436 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000437 (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000438 goto out_unmap_table;
439 }
440
441 ret = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100442 res->x[1] = rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000443
444 /*
445 * Break before make.
446 */
447 s2tte_write(&parent_s2tt[wi.index], 0UL);
448
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000449 if (s2tte_is_assigned_ram(&s2_ctx, parent_s2tte, level - 1L) ||
450 s2tte_is_assigned_ns(&s2_ctx, parent_s2tte, level - 1L)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100451 s2tt_invalidate_pages_in_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000452 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100453 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000454 }
455
456 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
457
458 granule_memzero_mapped(table);
459 granule_set_state(g_tbl, GRANULE_STATE_DELEGATED);
460
461out_unmap_table:
462 buffer_unmap(table);
463 granule_unlock(g_tbl);
464out_unmap_parent_table:
465 buffer_unmap(parent_s2tt);
466out_unlock_parent_table:
467 granule_unlock(wi.g_llt);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100468 res->x[0] = ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000469}
470
AlexeiFedorove2002be2023-04-19 17:20:12 +0100471void smc_rtt_destroy(unsigned long rd_addr,
472 unsigned long map_addr,
473 unsigned long ulevel,
474 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000475{
476 struct granule *g_rd;
477 struct granule *g_tbl;
478 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100479 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000480 unsigned long *table, *parent_s2tt, parent_s2tte;
481 long level = (long)ulevel;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000482 unsigned long rtt_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000483 unsigned long ret;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000484 struct s2tt_context s2_ctx;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100485 bool in_par, skip_non_live = false;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000486
487 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
488 if (g_rd == NULL) {
AlexeiFedorove2002be2023-04-19 17:20:12 +0100489 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100490 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100491 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000492 }
493
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000494 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100495 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000496
497 if (!validate_rtt_structure_cmds(map_addr, level, rd)) {
498 buffer_unmap(rd);
499 granule_unlock(g_rd);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100500 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100501 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100502 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000503 }
504
Soby Mathewb4c6df42022-11-09 11:13:29 +0000505 s2_ctx = rd->s2_ctx;
506 in_par = addr_in_par(rd, map_addr);
507 buffer_unmap(rd);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000508 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000509 granule_unlock(g_rd);
510
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000511 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level - 1L, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000512
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000513 parent_s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100514 assert(parent_s2tt != NULL);
515
Soby Mathewb4c6df42022-11-09 11:13:29 +0000516 parent_s2tte = s2tte_read(&parent_s2tt[wi.index]);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100517
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100518 if ((wi.last_level != (level - 1L)) ||
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000519 !s2tte_is_table(&s2_ctx, parent_s2tte, level - 1L)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100520 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000521 (unsigned char)wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100522 skip_non_live = true;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000523 goto out_unmap_parent_table;
524 }
525
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000526 rtt_addr = s2tte_pa(&s2_ctx, parent_s2tte, level - 1L);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000527
528 /*
529 * Lock the RTT granule. The 'rtt_addr' is verified, thus can be treated
530 * as an internal granule.
531 */
532 g_tbl = find_lock_granule(rtt_addr, GRANULE_STATE_RTT);
533
534 /*
535 * A table descriptor S2TTE always points to a TABLE granule.
536 */
537 assert(g_tbl != NULL);
538
539 /*
540 * Read the refcount value. RTT granule is always accessed locked, thus
541 * the refcount can be accessed without atomic operations.
542 */
AlexeiFedorov745499d2024-04-25 16:52:44 +0100543 if (granule_refcount_read(g_tbl) != 0U) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000544 ret = pack_return_code(RMI_ERROR_RTT, (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000545 goto out_unlock_table;
546 }
547
548 ret = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +0100549 res->x[1] = rtt_addr;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100550 skip_non_live = true;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000551
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000552 table = buffer_granule_map(g_tbl, SLOT_RTT2);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100553 assert(table != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000554
555 if (in_par) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000556 parent_s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000557 } else {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000558 parent_s2tte = s2tte_create_unassigned_ns(&s2_ctx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000559 }
560
AlexeiFedorov745499d2024-04-25 16:52:44 +0100561 atomic_granule_put(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000562
563 /*
564 * Break before make. Note that this may cause spurious S2 aborts.
565 */
566 s2tte_write(&parent_s2tt[wi.index], 0UL);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000567
568 if (in_par) {
569 /* For protected IPA, all S2TTEs in the RTT will be invalid */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100570 s2tt_invalidate_block(&s2_ctx, map_addr);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000571 } else {
572 /*
573 * For unprotected IPA, invalidate the TLB for the entire range
574 * mapped by the RTT as it may have valid NS mappings.
575 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100576 s2tt_invalidate_pages_in_block(&s2_ctx, map_addr);
AlexeiFedorov22ba1062023-11-15 16:23:37 +0000577 }
578
Soby Mathewb4c6df42022-11-09 11:13:29 +0000579 s2tte_write(&parent_s2tt[wi.index], parent_s2tte);
580
581 granule_memzero_mapped(table);
582 granule_set_state(g_tbl, GRANULE_STATE_DELEGATED);
583
584 buffer_unmap(table);
585out_unlock_table:
586 granule_unlock(g_tbl);
587out_unmap_parent_table:
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100588 if (skip_non_live) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000589 res->x[2] = s2tt_skip_non_live_entries(&s2_ctx, map_addr,
590 parent_s2tt, &wi);
AlexeiFedorov3ebd4622023-07-18 16:27:39 +0100591 } else {
592 res->x[2] = map_addr;
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100593 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000594 buffer_unmap(parent_s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000595 granule_unlock(wi.g_llt);
AlexeiFedorove2002be2023-04-19 17:20:12 +0100596 res->x[0] = ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000597}
598
599enum map_unmap_ns_op {
600 MAP_NS,
601 UNMAP_NS
602};
603
604/*
605 * We don't hold a reference on the NS granule when it is
606 * mapped into a realm. Instead we rely on the guarantees
607 * provided by the architecture to ensure that a NS access
608 * to a protected granule is prohibited even within the realm.
609 */
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100610static void map_unmap_ns(unsigned long rd_addr,
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000611 unsigned long map_addr,
612 long level,
613 unsigned long host_s2tte,
614 enum map_unmap_ns_op op,
615 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000616{
617 struct granule *g_rd;
618 struct rd *rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000619 unsigned long *s2tt, s2tte;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100620 struct s2tt_walk wi;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +0000621 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000622
623 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
624 if (g_rd == NULL) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100625 res->x[0] = RMI_ERROR_INPUT;
626 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000627 }
628
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000629 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100630 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000631
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000632 s2_ctx = rd->s2_ctx;
633
634 if (op == MAP_NS) {
635 if (!host_ns_s2tte_is_valid(&s2_ctx, host_s2tte, level)) {
636 buffer_unmap(rd);
637 granule_unlock(g_rd);
638 res->x[0] = RMI_ERROR_INPUT;
639 return;
640 }
641 }
642
643
Soby Mathewb4c6df42022-11-09 11:13:29 +0000644 if (!validate_rtt_map_cmds(map_addr, level, rd)) {
645 buffer_unmap(rd);
646 granule_unlock(g_rd);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100647 res->x[0] = RMI_ERROR_INPUT;
648 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000649 }
650
AlexeiFedorovc34e3242023-04-12 11:30:33 +0100651 /* Check if map_addr is outside PAR */
652 if (addr_in_par(rd, map_addr)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000653 buffer_unmap(rd);
654 granule_unlock(g_rd);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100655 res->x[0] = RMI_ERROR_INPUT;
656 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000657 }
658
Soby Mathewb4c6df42022-11-09 11:13:29 +0000659 buffer_unmap(rd);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000660 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000661 granule_unlock(g_rd);
662
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000663 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level, &wi);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100664
665 /*
666 * For UNMAP_NS, we need to map the table and look
667 * for the end of the non-live region.
668 */
AlexeiFedorov14d47ae2023-07-19 15:26:50 +0100669 if ((op == MAP_NS) && (wi.last_level != level)) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100670 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000671 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000672 goto out_unlock_llt;
673 }
674
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000675 s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100676 assert(s2tt != NULL);
677
Soby Mathewb4c6df42022-11-09 11:13:29 +0000678 s2tte = s2tte_read(&s2tt[wi.index]);
679
680 if (op == MAP_NS) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000681 if (!s2tte_is_unassigned_ns(&s2_ctx, s2tte)) {
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100682 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000683 (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000684 goto out_unmap_table;
685 }
686
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000687 s2tte = s2tte_create_assigned_ns(&s2_ctx, host_s2tte, level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000688 s2tte_write(&s2tt[wi.index], s2tte);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000689
690 } else if (op == UNMAP_NS) {
691 /*
692 * The following check also verifies that map_addr is outside
693 * PAR, as valid_NS s2tte may only cover outside PAR IPA range.
694 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000695 bool assigned_ns = s2tte_is_assigned_ns(&s2_ctx, s2tte,
696 wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100697
698 if ((wi.last_level != level) || !assigned_ns) {
699 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000700 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000701 goto out_unmap_table;
702 }
703
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000704 s2tte = s2tte_create_unassigned_ns(&s2_ctx);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000705 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100706 if (level == S2TT_PAGE_LEVEL) {
707 s2tt_invalidate_page(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000708 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100709 s2tt_invalidate_block(&s2_ctx, map_addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000710 }
711 }
712
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100713 res->x[0] = RMI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000714
715out_unmap_table:
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100716 if (op == UNMAP_NS) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000717 res->x[1] = s2tt_skip_non_live_entries(&s2_ctx, map_addr,
718 s2tt, &wi);
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100719 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000720 buffer_unmap(s2tt);
721out_unlock_llt:
722 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000723}
724
725unsigned long smc_rtt_map_unprotected(unsigned long rd_addr,
726 unsigned long map_addr,
727 unsigned long ulevel,
728 unsigned long s2tte)
729{
730 long level = (long)ulevel;
Shruti Gupta9e966b82024-03-21 13:45:24 +0000731 struct smc_result res;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000732
Shruti Gupta9e966b82024-03-21 13:45:24 +0000733 (void)memset(&res, 0, sizeof(struct smc_result));
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100734 if ((level < S2TT_MIN_BLOCK_LEVEL) || (level > S2TT_PAGE_LEVEL)) {
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100735 return RMI_ERROR_INPUT;
736 }
737
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100738 map_unmap_ns(rd_addr, map_addr, level, s2tte, MAP_NS, &res);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000739
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100740 return res.x[0];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000741}
742
AlexeiFedorov917eabf2023-04-24 12:20:41 +0100743void smc_rtt_unmap_unprotected(unsigned long rd_addr,
744 unsigned long map_addr,
745 unsigned long ulevel,
746 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000747{
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100748 long level = (long)ulevel;
749
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100750 if ((level < S2TT_MIN_BLOCK_LEVEL) || (level > S2TT_PAGE_LEVEL)) {
AlexeiFedorov7a2f5882023-09-14 11:41:32 +0100751 res->x[0] = RMI_ERROR_INPUT;
752 return;
753 }
754
755 map_unmap_ns(rd_addr, map_addr, level, 0UL, UNMAP_NS, res);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000756}
757
758void smc_rtt_read_entry(unsigned long rd_addr,
759 unsigned long map_addr,
760 unsigned long ulevel,
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100761 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000762{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000763 struct granule *g_rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000764 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100765 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000766 unsigned long *s2tt, s2tte;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000767 long level = (long)ulevel;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000768 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000769
770 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
771 if (g_rd == NULL) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100772 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000773 return;
774 }
775
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000776 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100777 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000778
779 if (!validate_rtt_entry_cmds(map_addr, level, rd)) {
780 buffer_unmap(rd);
781 granule_unlock(g_rd);
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100782 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000783 return;
784 }
785
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000786 s2_ctx = rd->s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000787 buffer_unmap(rd);
788
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000789 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000790 granule_unlock(g_rd);
791
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000792 s2tt_walk_lock_unlock(&s2_ctx, map_addr, level, &wi);
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000793 s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100794 assert(s2tt != NULL);
795
Soby Mathewb4c6df42022-11-09 11:13:29 +0000796 s2tte = s2tte_read(&s2tt[wi.index]);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100797 res->x[1] = (unsigned long)wi.last_level;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000798
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000799 if (s2tte_is_unassigned_empty(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100800 res->x[2] = RMI_UNASSIGNED;
801 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100802 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000803 } else if (s2tte_is_unassigned_ram(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100804 res->x[2] = RMI_UNASSIGNED;
805 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100806 res->x[4] = (unsigned long)RIPAS_RAM;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000807 } else if (s2tte_is_unassigned_destroyed(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100808 res->x[2] = RMI_UNASSIGNED;
809 res->x[3] = 0UL;
AlexeiFedorov4faab852023-08-30 15:06:49 +0100810 res->x[4] = (unsigned long)RIPAS_DESTROYED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000811 } else if (s2tte_is_assigned_empty(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100812 res->x[2] = RMI_ASSIGNED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000813 res->x[3] = s2tte_pa(&s2_ctx, s2tte, wi.last_level);
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_assigned_ram(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100816 res->x[2] = RMI_ASSIGNED;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000817 res->x[3] = s2tte_pa(&s2_ctx, s2tte, wi.last_level);
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_assigned_destroyed(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100820 res->x[2] = RMI_ASSIGNED;
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_unassigned_ns(&s2_ctx, s2tte)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100824 res->x[2] = RMI_UNASSIGNED;
825 res->x[3] = 0UL;
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_ns(&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] = host_ns_s2tte(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100830 res->x[4] = (unsigned long)RIPAS_EMPTY;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000831 } else if (s2tte_is_table(&s2_ctx, s2tte, wi.last_level)) {
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100832 res->x[2] = RMI_TABLE;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000833 res->x[3] = s2tte_pa(&s2_ctx, s2tte, wi.last_level);
AlexeiFedorov4faab852023-08-30 15:06:49 +0100834 res->x[4] = (unsigned long)RIPAS_EMPTY;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000835 } else {
836 assert(false);
837 }
838
839 buffer_unmap(s2tt);
840 granule_unlock(wi.g_llt);
841
AlexeiFedorov64fd6c32023-07-20 12:33:00 +0100842 res->x[0] = RMI_SUCCESS;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000843}
844
Soby Mathewb4c6df42022-11-09 11:13:29 +0000845static unsigned long validate_data_create_unknown(unsigned long map_addr,
846 struct rd *rd)
847{
848 if (!addr_in_par(rd, map_addr)) {
849 return RMI_ERROR_INPUT;
850 }
851
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100852 if (!validate_map_addr(map_addr, S2TT_PAGE_LEVEL, rd)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000853 return RMI_ERROR_INPUT;
854 }
855
856 return RMI_SUCCESS;
857}
858
859static unsigned long validate_data_create(unsigned long map_addr,
860 struct rd *rd)
861{
Mate Toth-Pal988dfcb2024-01-19 10:52:06 +0100862 if (get_rd_state_locked(rd) != REALM_NEW) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000863 return RMI_ERROR_REALM;
864 }
865
866 return validate_data_create_unknown(map_addr, rd);
867}
868
869/*
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100870 * Implements both RMI_DATA_CREATE and RMI_DATA_CREATE_UNKNOWN
Soby Mathewb4c6df42022-11-09 11:13:29 +0000871 *
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100872 * if @g_src == NULL, implements RMI_DATA_CREATE_UNKNOWN
873 * and RMI_DATA_CREATE otherwise.
Soby Mathewb4c6df42022-11-09 11:13:29 +0000874 */
AlexeiFedorovac923c82023-04-06 15:12:04 +0100875static unsigned long data_create(unsigned long rd_addr,
876 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000877 unsigned long map_addr,
878 struct granule *g_src,
879 unsigned long flags)
880{
881 struct granule *g_data;
882 struct granule *g_rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000883 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100884 struct s2tt_walk wi;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000885 struct s2tt_context *s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000886 unsigned long s2tte, *s2tt;
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000887 unsigned char new_data_state = GRANULE_STATE_DELEGATED;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000888 unsigned long ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000889
890 if (!find_lock_two_granules(data_addr,
891 GRANULE_STATE_DELEGATED,
892 &g_data,
893 rd_addr,
894 GRANULE_STATE_RD,
895 &g_rd)) {
896 return RMI_ERROR_INPUT;
897 }
898
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000899 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100900 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000901
902 ret = (g_src != NULL) ?
903 validate_data_create(map_addr, rd) :
904 validate_data_create_unknown(map_addr, rd);
905
906 if (ret != RMI_SUCCESS) {
907 goto out_unmap_rd;
908 }
909
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000910 s2_ctx = &(rd->s2_ctx);
911 granule_lock(s2_ctx->g_rtt, GRANULE_STATE_RTT);
912
913 s2tt_walk_lock_unlock(s2_ctx, map_addr, S2TT_PAGE_LEVEL, &wi);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100914 if (wi.last_level != S2TT_PAGE_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +0100915 ret = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000916 (unsigned char)wi.last_level);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000917 goto out_unlock_ll_table;
918 }
919
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000920 s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100921 assert(s2tt != NULL);
922
Soby Mathewb4c6df42022-11-09 11:13:29 +0000923 s2tte = s2tte_read(&s2tt[wi.index]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000924 if (!s2tte_is_unassigned(s2_ctx, s2tte)) {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +0000925 ret = pack_return_code(RMI_ERROR_RTT,
926 (unsigned char)S2TT_PAGE_LEVEL);
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100927 goto out_unmap_ll_table;
928 }
Soby Mathewb4c6df42022-11-09 11:13:29 +0000929
Soby Mathewb4c6df42022-11-09 11:13:29 +0000930 if (g_src != NULL) {
931 bool ns_access_ok;
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +0000932 void *data = buffer_granule_map(g_data, SLOT_DELEGATED);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000933
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100934 assert(data != NULL);
935
Soby Mathewb4c6df42022-11-09 11:13:29 +0000936 ns_access_ok = ns_buffer_read(SLOT_NS, g_src, 0U,
937 GRANULE_SIZE, data);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000938 if (!ns_access_ok) {
939 /*
940 * Some data may be copied before the failure. Zero
941 * g_data granule as it will remain in delegated state.
942 */
AlexeiFedorov862f96c2024-03-01 16:26:48 +0000943 granule_memzero_mapped(data);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000944 buffer_unmap(data);
945 ret = RMI_ERROR_INPUT;
946 goto out_unmap_ll_table;
947 }
948
Mate Toth-Palc7698312023-08-09 12:49:34 +0200949 measurement_data_granule_measure(
950 rd->measurement[RIM_MEASUREMENT_SLOT],
951 rd->algorithm,
952 data,
953 map_addr,
954 flags);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000955 buffer_unmap(data);
AlexeiFedorov0f9cd1f2023-07-10 17:04:58 +0100956
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000957 s2tte = s2tte_create_assigned_ram(s2_ctx, data_addr,
958 S2TT_PAGE_LEVEL);
AlexeiFedorov4e2db162023-10-10 13:57:22 +0100959 } else {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +0000960 s2tte = s2tte_create_assigned_unchanged(s2_ctx, s2tte,
961 data_addr,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +0100962 S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000963 }
964
965 new_data_state = GRANULE_STATE_DATA;
966
Soby Mathewb4c6df42022-11-09 11:13:29 +0000967 s2tte_write(&s2tt[wi.index], s2tte);
AlexeiFedorov745499d2024-04-25 16:52:44 +0100968 atomic_granule_get(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000969
970 ret = RMI_SUCCESS;
971
972out_unmap_ll_table:
973 buffer_unmap(s2tt);
974out_unlock_ll_table:
975 granule_unlock(wi.g_llt);
976out_unmap_rd:
977 buffer_unmap(rd);
978 granule_unlock(g_rd);
979 granule_unlock_transition(g_data, new_data_state);
980 return ret;
981}
982
AlexeiFedorovac923c82023-04-06 15:12:04 +0100983unsigned long smc_data_create(unsigned long rd_addr,
984 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000985 unsigned long map_addr,
986 unsigned long src_addr,
987 unsigned long flags)
988{
989 struct granule *g_src;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000990
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100991 if ((flags != RMI_NO_MEASURE_CONTENT) &&
992 (flags != RMI_MEASURE_CONTENT)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000993 return RMI_ERROR_INPUT;
994 }
995
996 g_src = find_granule(src_addr);
AlexeiFedorov745499d2024-04-25 16:52:44 +0100997 if ((g_src == NULL) ||
998 (granule_unlocked_state(g_src) != GRANULE_STATE_NS)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000999 return RMI_ERROR_INPUT;
1000 }
1001
AlexeiFedorovac923c82023-04-06 15:12:04 +01001002 return data_create(rd_addr, data_addr, map_addr, g_src, flags);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001003}
1004
AlexeiFedorovac923c82023-04-06 15:12:04 +01001005unsigned long smc_data_create_unknown(unsigned long rd_addr,
1006 unsigned long data_addr,
Soby Mathewb4c6df42022-11-09 11:13:29 +00001007 unsigned long map_addr)
1008{
AlexeiFedorovac923c82023-04-06 15:12:04 +01001009 return data_create(rd_addr, data_addr, map_addr, NULL, 0);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001010}
1011
AlexeiFedorove2002be2023-04-19 17:20:12 +01001012void smc_data_destroy(unsigned long rd_addr,
1013 unsigned long map_addr,
1014 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001015{
1016 struct granule *g_data;
1017 struct granule *g_rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001018 struct s2tt_walk wi;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001019 unsigned long data_addr, s2tte, *s2tt;
1020 struct rd *rd;
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +00001021 struct s2tt_context s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001022
1023 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
1024 if (g_rd == NULL) {
AlexeiFedorove2002be2023-04-19 17:20:12 +01001025 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorova1b2a1d2023-07-18 15:08:47 +01001026 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001027 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001028 }
1029
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001030 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001031 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001032
AlexeiFedorov868a6512023-09-14 13:21:11 +01001033 if (!addr_in_par(rd, map_addr) ||
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001034 !validate_map_addr(map_addr, S2TT_PAGE_LEVEL, rd)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001035 buffer_unmap(rd);
1036 granule_unlock(g_rd);
AlexeiFedorove2002be2023-04-19 17:20:12 +01001037 res->x[0] = RMI_ERROR_INPUT;
AlexeiFedorova1b2a1d2023-07-18 15:08:47 +01001038 res->x[2] = 0UL;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001039 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001040 }
1041
Soby Mathewb4c6df42022-11-09 11:13:29 +00001042 s2_ctx = rd->s2_ctx;
1043 buffer_unmap(rd);
1044
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001045 granule_lock(s2_ctx.g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001046 granule_unlock(g_rd);
1047
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001048 s2tt_walk_lock_unlock(&s2_ctx, map_addr, S2TT_PAGE_LEVEL, &wi);
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001049 s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001050 assert(s2tt != NULL);
1051
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001052 if (wi.last_level != S2TT_PAGE_LEVEL) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001053 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001054 (unsigned char)wi.last_level);
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001055 goto out_unmap_ll_table;
1056 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001057
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001058 s2tte = s2tte_read(&s2tt[wi.index]);
AlexeiFedorovc53b1f72023-07-04 15:37:03 +01001059
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001060 if (s2tte_is_assigned_ram(&s2_ctx, s2tte, S2TT_PAGE_LEVEL)) {
1061 data_addr = s2tte_pa(&s2_ctx, s2tte, S2TT_PAGE_LEVEL);
1062 s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001063 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001064 s2tt_invalidate_page(&s2_ctx, map_addr);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001065 } else if (s2tte_is_assigned_empty(&s2_ctx, s2tte, S2TT_PAGE_LEVEL)) {
1066 data_addr = s2tte_pa(&s2_ctx, s2tte, S2TT_PAGE_LEVEL);
1067 s2tte = s2tte_create_unassigned_empty(&s2_ctx);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001068 s2tte_write(&s2tt[wi.index], s2tte);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001069 } else if (s2tte_is_assigned_destroyed(&s2_ctx, s2tte,
1070 S2TT_PAGE_LEVEL)) {
1071 data_addr = s2tte_pa(&s2_ctx, s2tte, S2TT_PAGE_LEVEL);
1072 s2tte = s2tte_create_unassigned_destroyed(&s2_ctx);
Javier Almansa Sobrino84a1b162023-09-26 17:32:44 +01001073 s2tte_write(&s2tt[wi.index], s2tte);
AlexeiFedorova43cd312023-04-17 11:42:25 +01001074 } else {
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001075 res->x[0] = pack_return_code(RMI_ERROR_RTT,
1076 (unsigned char)S2TT_PAGE_LEVEL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001077 goto out_unmap_ll_table;
1078 }
1079
AlexeiFedorov745499d2024-04-25 16:52:44 +01001080 atomic_granule_put(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001081
1082 /*
1083 * Lock the data granule and check expected state. Correct locking order
1084 * is guaranteed because granule address is obtained from a locked
1085 * granule by table walk. This lock needs to be acquired before a state
1086 * transition to or from GRANULE_STATE_DATA for granule address can happen.
1087 */
1088 g_data = find_lock_granule(data_addr, GRANULE_STATE_DATA);
AlexeiFedorov63b71692023-04-19 11:18:42 +01001089 assert(g_data != NULL);
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001090 buffer_granule_memzero(g_data, SLOT_DELEGATED);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001091 granule_unlock_transition(g_data, GRANULE_STATE_DELEGATED);
1092
AlexeiFedorov917eabf2023-04-24 12:20:41 +01001093 res->x[0] = RMI_SUCCESS;
AlexeiFedorove2002be2023-04-19 17:20:12 +01001094 res->x[1] = data_addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001095out_unmap_ll_table:
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001096 res->x[2] = s2tt_skip_non_live_entries(&s2_ctx, map_addr, s2tt, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001097 buffer_unmap(s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001098 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001099}
1100
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001101/*
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001102 * Update the ripas value for the entry pointed by @s2ttep.
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001103 *
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001104 * Returns:
1105 * < 0 - On error and the operation was aborted,
1106 * e.g., entry cannot have a ripas.
1107 * 0 - Operation was success and no TLBI is required.
1108 * > 0 - Operation was success and TLBI is required.
1109 * Sets:
1110 * @(*do_tlbi) to 'true' if the TLBs have to be invalidated.
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001111 */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001112static int update_ripas(const struct s2tt_context *s2_ctx,
1113 unsigned long *s2ttep, long level,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001114 enum ripas ripas_val,
1115 enum ripas_change_destroyed change_destroyed)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001116{
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001117 unsigned long pa, s2tte = s2tte_read(s2ttep);
1118 int ret = 0;
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001119
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001120 assert(s2_ctx != NULL);
1121
1122 if (!s2tte_has_ripas(s2_ctx, s2tte, level)) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001123 return -EPERM;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001124 }
1125
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001126 if (ripas_val == RIPAS_RAM) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001127 if (s2tte_is_unassigned_empty(s2_ctx, s2tte)) {
1128 s2tte = s2tte_create_unassigned_ram(s2_ctx);
1129 } else if (s2tte_is_unassigned_destroyed(s2_ctx, s2tte)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001130 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001131 s2tte = s2tte_create_unassigned_ram(s2_ctx);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001132 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001133 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001134 }
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001135 } else if (s2tte_is_assigned_empty(s2_ctx, s2tte, level)) {
1136 pa = s2tte_pa(s2_ctx, s2tte, level);
1137 s2tte = s2tte_create_assigned_ram(s2_ctx, pa, level);
1138 } else if (s2tte_is_assigned_destroyed(s2_ctx, s2tte, level)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001139 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001140 pa = s2tte_pa(s2_ctx, s2tte, level);
1141 s2tte = s2tte_create_assigned_ram(s2_ctx, pa,
1142 level);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001143 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001144 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001145 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001146 } else {
1147 /* No action is required */
1148 return 0;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001149 }
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001150 } else if (ripas_val == RIPAS_EMPTY) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001151 if (s2tte_is_unassigned_ram(s2_ctx, s2tte)) {
1152 s2tte = s2tte_create_unassigned_empty(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_empty(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_ram(s2_ctx, s2tte, level)) {
1160 pa = s2tte_pa(s2_ctx, s2tte, level);
1161 s2tte = s2tte_create_assigned_empty(s2_ctx, pa, level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001162 /* TLBI is required */
1163 ret = 1;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001164 } else if (s2tte_is_assigned_destroyed(s2_ctx, s2tte, level)) {
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001165 if (change_destroyed == CHANGE_DESTROYED) {
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001166 pa = s2tte_pa(s2_ctx, s2tte, level);
1167 s2tte = s2tte_create_assigned_empty(s2_ctx,
1168 pa, level);
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001169 /* TLBI is required */
1170 ret = 1;
1171 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001172 return -EINVAL;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001173 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001174 } else {
1175 /* No action is required */
1176 return 0;
AlexeiFedorov0fb44552023-04-14 15:37:58 +01001177 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001178 }
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001179 s2tte_write(s2ttep, s2tte);
1180 return ret;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001181}
1182
AlexeiFedorov960d1612023-04-25 13:23:39 +01001183void smc_rtt_init_ripas(unsigned long rd_addr,
1184 unsigned long base,
1185 unsigned long top,
1186 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001187{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001188 struct granule *g_rd;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001189 struct rd *rd;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001190 unsigned long addr, map_size;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001191 struct s2tt_walk wi;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001192 struct s2tt_context *s2_ctx;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001193 unsigned long s2tte, *s2tt;
AlexeiFedorov960d1612023-04-25 13:23:39 +01001194 long level;
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001195 unsigned long index;
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001196 unsigned int s2ttes_per_s2tt;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001197
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001198 if (top <= base) {
1199 res->x[0] = RMI_ERROR_INPUT;
1200 return;
1201 }
1202
Soby Mathewb4c6df42022-11-09 11:13:29 +00001203 g_rd = find_lock_granule(rd_addr, GRANULE_STATE_RD);
1204 if (g_rd == NULL) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001205 res->x[0] = RMI_ERROR_INPUT;
1206 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001207 }
1208
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001209 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001210 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001211
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001212 if (!validate_map_addr(base, S2TT_PAGE_LEVEL, rd) ||
1213 !validate_map_addr(top, S2TT_PAGE_LEVEL, rd) ||
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001214 !addr_in_par(rd, base) || !addr_in_par(rd, top - GRANULE_SIZE)) {
1215 buffer_unmap(rd);
1216 granule_unlock(g_rd);
1217 res->x[0] = RMI_ERROR_INPUT;
1218 return;
1219 }
1220
Mate Toth-Pal988dfcb2024-01-19 10:52:06 +01001221 if (get_rd_state_locked(rd) != REALM_NEW) {
Soby Mathewb4c6df42022-11-09 11:13:29 +00001222 buffer_unmap(rd);
1223 granule_unlock(g_rd);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001224 res->x[0] = RMI_ERROR_REALM;
1225 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001226 }
1227
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001228 s2_ctx = &(rd->s2_ctx);
1229 granule_lock(s2_ctx->g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001230
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001231 s2tt_walk_lock_unlock(s2_ctx, base, S2TT_PAGE_LEVEL, &wi);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001232 level = wi.last_level;
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001233 s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001234 assert(s2tt != NULL);
1235
AlexeiFedorov960d1612023-04-25 13:23:39 +01001236 map_size = s2tte_map_size(level);
1237 addr = base & ~(map_size - 1UL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001238
AlexeiFedorov960d1612023-04-25 13:23:39 +01001239 /*
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001240 * If the RTTE covers a range below "base", we need to go deeper.
AlexeiFedorov960d1612023-04-25 13:23:39 +01001241 */
1242 if (addr != base) {
1243 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001244 (unsigned char)level);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001245 goto out_unmap_llt;
1246 }
1247
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001248 s2ttes_per_s2tt =
1249 (unsigned int)((level == S2TT_MIN_STARTING_LEVEL_LPA2) ?
1250 S2TTES_PER_S2TT_LM1 : S2TTES_PER_S2TT);
1251 for (index = wi.index; index < s2ttes_per_s2tt; index++) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001252 unsigned long next = addr + map_size;
1253
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001254 /*
1255 * Break on "top_align" failure condition,
1256 * or if this entry crosses the range.
1257 */
AlexeiFedorov960d1612023-04-25 13:23:39 +01001258 if (next > top) {
1259 break;
1260 }
1261
1262 s2tte = s2tte_read(&s2tt[index]);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001263 if (s2tte_is_unassigned_empty(s2_ctx, s2tte)) {
1264 s2tte = s2tte_create_unassigned_ram(s2_ctx);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001265 s2tte_write(&s2tt[index], s2tte);
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001266 } else if (!s2tte_is_unassigned_ram(s2_ctx, s2tte)) {
AlexeiFedorov960d1612023-04-25 13:23:39 +01001267 break;
1268 }
Mate Toth-Palc7698312023-08-09 12:49:34 +02001269 measurement_init_ripas_measure(rd->measurement[RIM_MEASUREMENT_SLOT],
1270 rd->algorithm,
1271 addr,
1272 next);
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001273 addr = next;
AlexeiFedorov960d1612023-04-25 13:23:39 +01001274 }
1275
1276 if (addr > base) {
1277 res->x[0] = RMI_SUCCESS;
1278 res->x[1] = addr;
1279 } else {
1280 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001281 (unsigned char)level);
AlexeiFedorov960d1612023-04-25 13:23:39 +01001282 }
Soby Mathewb4c6df42022-11-09 11:13:29 +00001283
1284out_unmap_llt:
1285 buffer_unmap(s2tt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001286 buffer_unmap(rd);
1287 granule_unlock(wi.g_llt);
AlexeiFedorov80295e42023-07-10 13:11:14 +01001288 granule_unlock(g_rd);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001289}
1290
Javier Almansa Sobrino2eb98b02023-12-18 18:10:55 +00001291static void rtt_set_ripas_range(struct s2tt_context *s2_ctx,
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001292 unsigned long *s2tt,
1293 unsigned long base,
1294 unsigned long top,
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001295 struct s2tt_walk *wi,
AlexeiFedorov4faab852023-08-30 15:06:49 +01001296 enum ripas ripas_val,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001297 enum ripas_change_destroyed change_destroyed,
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001298 struct smc_result *res)
1299{
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001300 unsigned long index;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001301 long level = wi->last_level;
AlexeiFedorov4faab852023-08-30 15:06:49 +01001302 unsigned long map_size = s2tte_map_size((int)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001303
1304 /* Align to the RTT level */
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001305 unsigned long addr = base & ~(map_size - 1UL);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001306
1307 /* Make sure we don't touch a range below the requested range */
1308 if (addr != base) {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001309 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001310 (unsigned char)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001311 return;
1312 }
1313
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001314 for (index = wi->index; index < S2TTES_PER_S2TT; index++) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001315 int ret;
1316
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001317 /*
1318 * Break on "top_align" failure condition,
1319 * or if this entry crosses the range.
1320 */
1321 if ((addr + map_size) > top) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001322 break;
1323 }
1324
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001325 ret = update_ripas(s2_ctx, &s2tt[index], level,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001326 ripas_val, change_destroyed);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001327 if (ret < 0) {
1328 break;
1329 }
1330
1331 /* Handle TLBI */
1332 if (ret != 0) {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001333 if (level == S2TT_PAGE_LEVEL) {
1334 s2tt_invalidate_page(s2_ctx, addr);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001335 } else {
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001336 s2tt_invalidate_block(s2_ctx, addr);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001337 }
1338 }
AlexeiFedorovee2fc822023-10-31 14:54:39 +00001339
1340 addr += map_size;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001341 }
1342
1343 if (addr > base) {
1344 res->x[0] = RMI_SUCCESS;
1345 res->x[1] = addr;
1346 } else {
AlexeiFedorovbe37dee2023-07-18 10:44:01 +01001347 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001348 (unsigned char)level);
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001349 }
1350}
1351
1352void smc_rtt_set_ripas(unsigned long rd_addr,
1353 unsigned long rec_addr,
1354 unsigned long base,
1355 unsigned long top,
1356 struct smc_result *res)
Soby Mathewb4c6df42022-11-09 11:13:29 +00001357{
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001358 struct granule *g_rd, *g_rec;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001359 struct rec *rec;
1360 struct rd *rd;
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001361 struct s2tt_walk wi;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001362 unsigned long *s2tt;
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001363 struct s2tt_context *s2_ctx;
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001364 enum ripas ripas_val;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001365 enum ripas_change_destroyed change_destroyed;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001366
AlexeiFedorov14d47ae2023-07-19 15:26:50 +01001367 if (top <= base) {
1368 res->x[0] = RMI_ERROR_INPUT;
1369 return;
1370 }
1371
Soby Mathewb4c6df42022-11-09 11:13:29 +00001372 if (!find_lock_two_granules(rd_addr,
1373 GRANULE_STATE_RD,
1374 &g_rd,
1375 rec_addr,
1376 GRANULE_STATE_REC,
1377 &g_rec)) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001378 res->x[0] = RMI_ERROR_INPUT;
1379 return;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001380 }
1381
AlexeiFedorovd6d93d82024-02-13 16:52:11 +00001382 if (granule_refcount_read_acquire(g_rec) != 0U) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001383 res->x[0] = RMI_ERROR_REC;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001384 goto out_unlock_rec_rd;
1385 }
1386
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001387 rec = buffer_granule_map(g_rec, SLOT_REC);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001388 assert(rec != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001389
1390 if (g_rd != rec->realm_info.g_rd) {
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001391 res->x[0] = RMI_ERROR_REC;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001392 goto out_unmap_rec;
1393 }
1394
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001395 ripas_val = rec->set_ripas.ripas_val;
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001396 change_destroyed = rec->set_ripas.change_destroyed;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001397
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001398 /*
1399 * Return error in case of target region:
1400 * - is not the next chunk of requested region
1401 * - extends beyond the end of requested region
1402 */
1403 if ((base != rec->set_ripas.addr) || (top > rec->set_ripas.top)) {
1404 res->x[0] = RMI_ERROR_INPUT;
Soby Mathewb4c6df42022-11-09 11:13:29 +00001405 goto out_unmap_rec;
1406 }
1407
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001408 rd = buffer_granule_map(g_rd, SLOT_RD);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001409 assert(rd != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001410
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001411 /*
1412 * At this point, we know base == rec->set_ripas.addr
1413 * and thus must be aligned to GRANULE size.
1414 */
Javier Almansa Sobrino1e1781e2023-10-18 18:25:56 +01001415 assert(validate_map_addr(base, S2TT_PAGE_LEVEL, rd));
Soby Mathewb4c6df42022-11-09 11:13:29 +00001416
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001417 s2_ctx = &(rd->s2_ctx);
1418 granule_lock(s2_ctx->g_rtt, GRANULE_STATE_RTT);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001419
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001420 /* Walk to the deepest level possible */
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001421 s2tt_walk_lock_unlock(s2_ctx, base, S2TT_PAGE_LEVEL, &wi);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001422
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001423 /*
1424 * Base has to be aligned to the level at which
1425 * it is mapped in RTT.
1426 */
1427 if (!validate_map_addr(base, wi.last_level, rd)) {
1428 res->x[0] = pack_return_code(RMI_ERROR_RTT,
Javier Almansa Sobrinof6fff692024-02-02 17:13:57 +00001429 (unsigned char)wi.last_level);
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001430 goto out_unlock_llt;
1431 }
1432
Javier Almansa Sobrino2f717dd2024-02-12 20:49:46 +00001433 s2tt = buffer_granule_map(wi.g_llt, SLOT_RTT);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +01001434 assert(s2tt != NULL);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001435
Javier Almansa Sobrino2595cd82024-01-25 18:25:12 +00001436 rtt_set_ripas_range(s2_ctx, s2tt, base, top, &wi,
AlexeiFedorov63614ea2023-07-14 17:07:20 +01001437 ripas_val, change_destroyed, res);
1438
AlexeiFedorov5cf35ba2023-04-25 10:02:20 +01001439 if (res->x[0] == RMI_SUCCESS) {
1440 rec->set_ripas.addr = res->x[1];
Soby Mathewb4c6df42022-11-09 11:13:29 +00001441 }
1442
Soby Mathewb4c6df42022-11-09 11:13:29 +00001443 buffer_unmap(s2tt);
AlexeiFedorov64fd6c32023-07-20 12:33:00 +01001444out_unlock_llt:
Soby Mathewb4c6df42022-11-09 11:13:29 +00001445 granule_unlock(wi.g_llt);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001446 buffer_unmap(rd);
1447out_unmap_rec:
1448 buffer_unmap(rec);
1449out_unlock_rec_rd:
1450 granule_unlock(g_rec);
1451 granule_unlock(g_rd);
Soby Mathewb4c6df42022-11-09 11:13:29 +00001452}