blob: 94e5d4945ebb9331417f74b995c7a35f9bfed7d8 [file] [log] [blame]
Soby Mathewb4c6df42022-11-09 11:13:29 +00001/*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
6#include <assert.h>
7#include <buffer.h>
8#include <debug.h>
9#include <granule.h>
10#include <mmio.h>
11#include <platform_api.h>
12#include <smc.h>
13#include <status.h>
14#include <stddef.h>
Mate Toth-Pal2755d692023-09-28 17:15:58 +020015/* According to the C standard, the memset function used in this file is declared in string.h */
16/* coverity[unnecessary_header: SUPPRESS] */
Soby Mathewb4c6df42022-11-09 11:13:29 +000017#include <string.h>
18#include <utils_def.h>
19
Mate Toth-Pal0e936512023-10-19 15:02:20 +020020IF_NCBMC(static) struct granule granules[RMM_MAX_GRANULES];
Soby Mathewb4c6df42022-11-09 11:13:29 +000021
22/*
23 * Takes a valid pointer to a struct granule, and returns the granule physical
24 * address.
25 *
26 * This is purely a lookup, and provides no guarantees about the attributes of
27 * the granule (i.e. whether it is locked, its state or its reference count).
28 */
Shruti Gupta9debb132022-12-13 14:38:49 +000029unsigned long granule_addr(const struct granule *g)
Soby Mathewb4c6df42022-11-09 11:13:29 +000030{
31 unsigned long idx;
32
33 assert(g != NULL);
Soby Mathewe02e0bd2023-01-18 10:57:18 +010034 assert(ALIGNED_TO_ARRAY(g, granules));
Soby Mathewb4c6df42022-11-09 11:13:29 +000035
AlexeiFedorov7c8bf6e2023-08-29 17:02:28 +010036 idx = ((unsigned long)g - (unsigned long)granules) /
37 sizeof(struct granule);
Soby Mathewb4c6df42022-11-09 11:13:29 +000038
39 return plat_granule_idx_to_addr(idx);
40}
41
42/*
43 * Takes a granule index, and returns a pointer to the struct granule.
44 *
45 * This is purely a lookup, and provides no guarantees about the attributes of
46 * the granule (i.e. whether it is locked, its state or its reference count).
47 */
48static struct granule *granule_from_idx(unsigned long idx)
49{
50 assert(idx < RMM_MAX_GRANULES);
51 return &granules[idx];
52}
53
54/*
55 * Takes an aligned granule address, and returns a pointer to the corresponding
56 * struct granule.
57 *
58 * This is purely a lookup, and provides no guarantees about the attributes of
59 * the granule (i.e. whether it is locked, its state or its reference count).
60 */
61struct granule *addr_to_granule(unsigned long addr)
62{
63 unsigned long idx;
64
65 assert(GRANULE_ALIGNED(addr));
66
67 idx = plat_granule_addr_to_idx(addr);
68 return granule_from_idx(idx);
69}
70
71/*
72 * Verifies whether @addr is a valid granule physical address, and returns a
73 * pointer to the corresponding struct granule.
74 *
75 * This is purely a lookup, and provides no guarantees w.r.t the state of the
76 * granule (e.g. locking).
77 *
78 * Returns:
79 * Pointer to the struct granule if @addr is a valid granule physical
80 * address.
81 * NULL if any of:
82 * - @addr is not aligned to the size of a granule.
83 * - @addr is out of range.
84 */
85struct granule *find_granule(unsigned long addr)
86{
87 unsigned long idx;
88
89 if (!GRANULE_ALIGNED(addr)) {
90 return NULL;
91 }
92
93 idx = plat_granule_addr_to_idx(addr);
94
95 if (idx >= RMM_MAX_GRANULES) {
96 return NULL;
97 }
98
99 return granule_from_idx(idx);
100}
101
102/*
103 * Obtain a pointer to a locked granule at @addr if @addr is a valid granule
104 * physical address and the state of the granule at @addr is @expected_state.
105 *
106 * Returns:
107 * A valid granule pointer if @addr is a valid granule physical address.
108 * NULL if any of:
109 * - @addr is not aligned to the size of a granule.
110 * - @addr is out of range.
111 * - if the state of the granule at @addr is not
112 * @expected_state.
113 */
114struct granule *find_lock_granule(unsigned long addr,
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000115 unsigned char expected_state)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000116{
117 struct granule *g;
118
119 g = find_granule(addr);
120 if (g == NULL) {
121 return NULL;
122 }
123
124 if (!granule_lock_on_state_match(g, expected_state)) {
125 return NULL;
126 }
127
128 return g;
129}
130
131struct granule_set {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000132 unsigned long addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000133 struct granule *g;
134 struct granule **g_ret;
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000135 unsigned char state;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000136};
137
138/*
139 * Sort a set of granules by their address.
140 */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100141static void sort_granules(struct granule_set *gs, unsigned long n)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000142{
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100143 for (unsigned long i = 1UL; i < n; i++) {
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100144 struct granule_set temp = gs[i];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000145 unsigned long j = i;
146
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100147 while ((j > 0UL) && (gs[j - 1UL].addr > temp.addr)) {
148 gs[j] = gs[j - 1UL];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000149 j--;
150 }
151 if (i != j) {
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100152 gs[j] = temp;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000153 }
154 }
155}
156
157/*
158 * Find a set of granules and lock them in order of their address.
159 *
160 * @granules: Pointer to array of @n items. Each item must be pre-populated
161 * with ->addr set to the granule's address, and ->state set to
162 * the expected state of the granule, and ->g_ret pointing to
163 * a valid 'struct granule *'.
164 * This function sorts the supplied array in place.
165 * @n: Number of struct granule_set in array pointed to by @granules
166 *
167 * Returns:
168 * True if all granules in @granules were successfully locked.
169 *
170 * False if any two entries in @granules have the same ->addr, or
171 * if, for any entry in @granules, any of the following is true:
172 * - entry->addr is not aligned to the size of a granule
173 * - entry->addr is out of range
174 * - the state of the granule at entry->addr is not entry->state
175 *
176 * Locking only succeeds if the granules are in their expected states as per the
177 * locking rules in granule_types.h.
178 *
179 * If the function succeeds, for all items in @granules, ->g points to a locked
180 * granule in ->state and *->g_ret is set to the pointer value.
181 *
182 * If the function fails, no lock is held and no *->g_ret pointers are
183 * modified.
184 */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100185static bool find_lock_granules(struct granule_set *gs, unsigned long n)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000186{
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100187 unsigned long i;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000188
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100189 sort_granules(gs, n);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000190
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100191 for (i = 0UL; i < n; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000192 /* Check for duplicates */
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100193 if ((i != 0UL) &&
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100194 (gs[i].addr == gs[i - 1UL].addr)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000195 goto out_err;
196 }
197
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100198 gs[i].g = find_lock_granule(gs[i].addr, gs[i].state);
199 if (gs[i].g == NULL) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000200 goto out_err;
201 }
202 }
203
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100204 for (i = 0UL; i < n; i++) {
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100205 *gs[i].g_ret = gs[i].g;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000206 }
207
208 return true;
209
210out_err:
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100211 while (i-- != 0UL) {
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100212 granule_unlock(gs[i].g);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000213 }
214
215 return false;
216}
217
218/*
219 * Find two granules and lock them in order of their address.
220 *
221 * See find_lock_granules().
222 */
223bool find_lock_two_granules(
224 unsigned long addr1,
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000225 unsigned char expected_state1,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000226 struct granule **g1,
227 unsigned long addr2,
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000228 unsigned char expected_state2,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000229 struct granule **g2)
230{
Shruti Gupta9debb132022-12-13 14:38:49 +0000231 struct granule_set gs[] = {
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000232 {addr1, NULL, g1, expected_state1},
233 {addr2, NULL, g2, expected_state2}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000234 };
235
236 assert((g1 != NULL) && (g2 != NULL));
237
Shruti Gupta9debb132022-12-13 14:38:49 +0000238 return find_lock_granules(gs, ARRAY_SIZE(gs));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000239}
240
241void granule_memzero(struct granule *g, enum buffer_slot slot)
242{
243 unsigned long *buf;
244
245 assert(g != NULL);
246
247 buf = granule_map(g, slot);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100248 assert(buf != NULL);
249
Soby Mathewb4c6df42022-11-09 11:13:29 +0000250 (void)memset(buf, 0, GRANULE_SIZE);
251 buffer_unmap(buf);
252}
253
254void granule_memzero_mapped(void *buf)
255{
256 (void)memset(buf, 0, GRANULE_SIZE);
257}
Arunachalam Ganapathy40b3bf02023-06-12 12:19:55 +0100258
259/*
260 * The parent REC granules lock is expected to be acquired before functions
261 * aux_granules_map() and aux_granules_unmap() are called.
262 */
263void *aux_granules_map(struct granule *rec_aux_pages[], unsigned int num_aux)
264{
265 void *rec_aux = NULL;
266
267 assert(rec_aux_pages != NULL);
268 assert(num_aux <= MAX_REC_AUX_GRANULES);
269
270 for (unsigned int i = 0U; i < num_aux; i++) {
271 void *aux = granule_map(rec_aux_pages[i],
272 (enum buffer_slot)((unsigned int)
273 SLOT_REC_AUX0 + i));
274
275 assert(aux != NULL);
276
277 if (i == 0UL) {
278 rec_aux = aux;
279 }
280 }
281 return rec_aux;
282}
283
284void aux_granules_unmap(void *rec_aux, unsigned int num_aux)
285{
286 unsigned char *rec_aux_vaddr = (unsigned char *)rec_aux;
287
288 assert(rec_aux != NULL);
289 assert(num_aux <= MAX_REC_AUX_GRANULES);
290
291 for (unsigned int i = 0U; i < num_aux; i++) {
AlexeiFedorov3f5d6272023-10-23 16:27:37 +0100292 buffer_unmap((void *)((uintptr_t)rec_aux_vaddr + (i * GRANULE_SIZE)));
Arunachalam Ganapathy40b3bf02023-06-12 12:19:55 +0100293 }
294}