blob: 85896dd81ea4b2c737c40d3ce78997ea258dbeec [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>
15#include <string.h>
16#include <utils_def.h>
17
18static struct granule granules[RMM_MAX_GRANULES];
19
20/*
21 * Takes a valid pointer to a struct granule, and returns the granule physical
22 * address.
23 *
24 * This is purely a lookup, and provides no guarantees about the attributes of
25 * the granule (i.e. whether it is locked, its state or its reference count).
26 */
Shruti Gupta9debb132022-12-13 14:38:49 +000027unsigned long granule_addr(const struct granule *g)
Soby Mathewb4c6df42022-11-09 11:13:29 +000028{
29 unsigned long idx;
30
31 assert(g != NULL);
Soby Mathewe02e0bd2023-01-18 10:57:18 +010032 assert(ALIGNED_TO_ARRAY(g, granules));
Soby Mathewb4c6df42022-11-09 11:13:29 +000033
AlexeiFedorov7c8bf6e2023-08-29 17:02:28 +010034 idx = ((unsigned long)g - (unsigned long)granules) /
35 sizeof(struct granule);
Soby Mathewb4c6df42022-11-09 11:13:29 +000036
37 return plat_granule_idx_to_addr(idx);
38}
39
40/*
41 * Takes a granule index, and returns a pointer to the struct granule.
42 *
43 * This is purely a lookup, and provides no guarantees about the attributes of
44 * the granule (i.e. whether it is locked, its state or its reference count).
45 */
46static struct granule *granule_from_idx(unsigned long idx)
47{
48 assert(idx < RMM_MAX_GRANULES);
49 return &granules[idx];
50}
51
52/*
53 * Takes an aligned granule address, and returns a pointer to the corresponding
54 * struct granule.
55 *
56 * This is purely a lookup, and provides no guarantees about the attributes of
57 * the granule (i.e. whether it is locked, its state or its reference count).
58 */
59struct granule *addr_to_granule(unsigned long addr)
60{
61 unsigned long idx;
62
63 assert(GRANULE_ALIGNED(addr));
64
65 idx = plat_granule_addr_to_idx(addr);
66 return granule_from_idx(idx);
67}
68
69/*
70 * Verifies whether @addr is a valid granule physical address, and returns a
71 * pointer to the corresponding struct granule.
72 *
73 * This is purely a lookup, and provides no guarantees w.r.t the state of the
74 * granule (e.g. locking).
75 *
76 * Returns:
77 * Pointer to the struct granule if @addr is a valid granule physical
78 * address.
79 * NULL if any of:
80 * - @addr is not aligned to the size of a granule.
81 * - @addr is out of range.
82 */
83struct granule *find_granule(unsigned long addr)
84{
85 unsigned long idx;
86
87 if (!GRANULE_ALIGNED(addr)) {
88 return NULL;
89 }
90
91 idx = plat_granule_addr_to_idx(addr);
92
93 if (idx >= RMM_MAX_GRANULES) {
94 return NULL;
95 }
96
97 return granule_from_idx(idx);
98}
99
100/*
101 * Obtain a pointer to a locked granule at @addr if @addr is a valid granule
102 * physical address and the state of the granule at @addr is @expected_state.
103 *
104 * Returns:
105 * A valid granule pointer if @addr is a valid granule physical address.
106 * NULL if any of:
107 * - @addr is not aligned to the size of a granule.
108 * - @addr is out of range.
109 * - if the state of the granule at @addr is not
110 * @expected_state.
111 */
112struct granule *find_lock_granule(unsigned long addr,
113 enum granule_state expected_state)
114{
115 struct granule *g;
116
117 g = find_granule(addr);
118 if (g == NULL) {
119 return NULL;
120 }
121
122 if (!granule_lock_on_state_match(g, expected_state)) {
123 return NULL;
124 }
125
126 return g;
127}
128
129struct granule_set {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000130 unsigned long addr;
131 enum granule_state state;
132 struct granule *g;
133 struct granule **g_ret;
134};
135
136/*
137 * Sort a set of granules by their address.
138 */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100139static void sort_granules(struct granule_set *gs, unsigned long n)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000140{
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100141 for (unsigned long i = 1UL; i < n; i++) {
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100142 struct granule_set temp = gs[i];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000143 unsigned long j = i;
144
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100145 while ((j > 0UL) && (gs[j - 1UL].addr > temp.addr)) {
146 gs[j] = gs[j - 1UL];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000147 j--;
148 }
149 if (i != j) {
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100150 gs[j] = temp;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000151 }
152 }
153}
154
155/*
156 * Find a set of granules and lock them in order of their address.
157 *
158 * @granules: Pointer to array of @n items. Each item must be pre-populated
159 * with ->addr set to the granule's address, and ->state set to
160 * the expected state of the granule, and ->g_ret pointing to
161 * a valid 'struct granule *'.
162 * This function sorts the supplied array in place.
163 * @n: Number of struct granule_set in array pointed to by @granules
164 *
165 * Returns:
166 * True if all granules in @granules were successfully locked.
167 *
168 * False if any two entries in @granules have the same ->addr, or
169 * if, for any entry in @granules, any of the following is true:
170 * - entry->addr is not aligned to the size of a granule
171 * - entry->addr is out of range
172 * - the state of the granule at entry->addr is not entry->state
173 *
174 * Locking only succeeds if the granules are in their expected states as per the
175 * locking rules in granule_types.h.
176 *
177 * If the function succeeds, for all items in @granules, ->g points to a locked
178 * granule in ->state and *->g_ret is set to the pointer value.
179 *
180 * If the function fails, no lock is held and no *->g_ret pointers are
181 * modified.
182 */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100183static bool find_lock_granules(struct granule_set *gs, unsigned long n)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000184{
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100185 unsigned long i;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000186
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100187 sort_granules(gs, n);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000188
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100189 for (i = 0UL; i < n; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000190 /* Check for duplicates */
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100191 if ((i != 0UL) &&
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100192 (gs[i].addr == gs[i - 1UL].addr)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000193 goto out_err;
194 }
195
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100196 gs[i].g = find_lock_granule(gs[i].addr, gs[i].state);
197 if (gs[i].g == NULL) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000198 goto out_err;
199 }
200 }
201
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100202 for (i = 0UL; i < n; i++) {
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100203 *gs[i].g_ret = gs[i].g;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000204 }
205
206 return true;
207
208out_err:
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100209 while (i-- != 0UL) {
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100210 granule_unlock(gs[i].g);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000211 }
212
213 return false;
214}
215
216/*
217 * Find two granules and lock them in order of their address.
218 *
219 * See find_lock_granules().
220 */
221bool find_lock_two_granules(
222 unsigned long addr1,
223 enum granule_state expected_state1,
224 struct granule **g1,
225 unsigned long addr2,
226 enum granule_state expected_state2,
227 struct granule **g2)
228{
Shruti Gupta9debb132022-12-13 14:38:49 +0000229 struct granule_set gs[] = {
shaxio0173f21122023-07-21 16:30:31 +0100230 {addr1, expected_state1, NULL, g1},
231 {addr2, expected_state2, NULL, g2}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000232 };
233
234 assert((g1 != NULL) && (g2 != NULL));
235
Shruti Gupta9debb132022-12-13 14:38:49 +0000236 return find_lock_granules(gs, ARRAY_SIZE(gs));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000237}
238
239void granule_memzero(struct granule *g, enum buffer_slot slot)
240{
241 unsigned long *buf;
242
243 assert(g != NULL);
244
245 buf = granule_map(g, slot);
AlexeiFedorov9a9062c2023-08-21 15:41:48 +0100246 assert(buf != NULL);
247
Soby Mathewb4c6df42022-11-09 11:13:29 +0000248 (void)memset(buf, 0, GRANULE_SIZE);
249 buffer_unmap(buf);
250}
251
252void granule_memzero_mapped(void *buf)
253{
254 (void)memset(buf, 0, GRANULE_SIZE);
255}
Arunachalam Ganapathy40b3bf02023-06-12 12:19:55 +0100256
257/*
258 * The parent REC granules lock is expected to be acquired before functions
259 * aux_granules_map() and aux_granules_unmap() are called.
260 */
261void *aux_granules_map(struct granule *rec_aux_pages[], unsigned int num_aux)
262{
263 void *rec_aux = NULL;
264
265 assert(rec_aux_pages != NULL);
266 assert(num_aux <= MAX_REC_AUX_GRANULES);
267
268 for (unsigned int i = 0U; i < num_aux; i++) {
269 void *aux = granule_map(rec_aux_pages[i],
270 (enum buffer_slot)((unsigned int)
271 SLOT_REC_AUX0 + i));
272
273 assert(aux != NULL);
274
275 if (i == 0UL) {
276 rec_aux = aux;
277 }
278 }
279 return rec_aux;
280}
281
282void aux_granules_unmap(void *rec_aux, unsigned int num_aux)
283{
284 unsigned char *rec_aux_vaddr = (unsigned char *)rec_aux;
285
286 assert(rec_aux != NULL);
287 assert(num_aux <= MAX_REC_AUX_GRANULES);
288
289 for (unsigned int i = 0U; i < num_aux; i++) {
290 buffer_unmap(rec_aux_vaddr + (i * GRANULE_SIZE));
291 }
292}