blob: 6ff1b640851834cfdfa0dddd8d497c012dbd9f81 [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
AlexeiFedorov862f96c2024-03-01 16:26:48 +00006#include <arch_helpers.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +00007#include <assert.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +00008#include <debug.h>
9#include <granule.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000010#include <platform_api.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000011#include <stddef.h>
Soby Mathewb4c6df42022-11-09 11:13:29 +000012#include <utils_def.h>
13
Shanker Donthineniea0213a2025-01-12 09:28:12 -060014IF_NCBMC(static) struct granule granules[RMM_MAX_GRANULES]
15 IF_NCBMC(__section("granules_memory"));
Soby Mathewb4c6df42022-11-09 11:13:29 +000016
17/*
AlexeiFedorov1faff542024-11-04 14:42:00 +000018 * Takes a granule index, and returns a pointer to the struct granule.
19 *
20 * This is purely a lookup, and provides no guarantees about the attributes of
21 * the granule (i.e. whether it is locked, its state or its reference count).
22 */
23static struct granule *granule_from_idx(unsigned long idx)
24{
25 assert(idx < RMM_MAX_GRANULES);
26 return &granules[idx];
27}
28
29/*
Soby Mathewb4c6df42022-11-09 11:13:29 +000030 * Takes a valid pointer to a struct granule, and returns the granule physical
31 * address.
32 *
33 * This is purely a lookup, and provides no guarantees about the attributes of
34 * the granule (i.e. whether it is locked, its state or its reference count).
35 */
Shruti Gupta9debb132022-12-13 14:38:49 +000036unsigned long granule_addr(const struct granule *g)
Soby Mathewb4c6df42022-11-09 11:13:29 +000037{
38 unsigned long idx;
39
40 assert(g != NULL);
Soby Mathewe02e0bd2023-01-18 10:57:18 +010041 assert(ALIGNED_TO_ARRAY(g, granules));
Soby Mathewb4c6df42022-11-09 11:13:29 +000042
AlexeiFedorov7c8bf6e2023-08-29 17:02:28 +010043 idx = ((unsigned long)g - (unsigned long)granules) /
44 sizeof(struct granule);
Soby Mathewb4c6df42022-11-09 11:13:29 +000045
46 return plat_granule_idx_to_addr(idx);
47}
48
49/*
Soby Mathewb4c6df42022-11-09 11:13:29 +000050 * Takes an aligned granule address, and returns a pointer to the corresponding
51 * struct granule.
52 *
53 * This is purely a lookup, and provides no guarantees about the attributes of
54 * the granule (i.e. whether it is locked, its state or its reference count).
55 */
56struct granule *addr_to_granule(unsigned long addr)
57{
58 unsigned long idx;
59
60 assert(GRANULE_ALIGNED(addr));
61
62 idx = plat_granule_addr_to_idx(addr);
63 return granule_from_idx(idx);
64}
65
66/*
67 * Verifies whether @addr is a valid granule physical address, and returns a
68 * pointer to the corresponding struct granule.
69 *
70 * This is purely a lookup, and provides no guarantees w.r.t the state of the
71 * granule (e.g. locking).
72 *
73 * Returns:
74 * Pointer to the struct granule if @addr is a valid granule physical
75 * address.
76 * NULL if any of:
77 * - @addr is not aligned to the size of a granule.
78 * - @addr is out of range.
79 */
80struct granule *find_granule(unsigned long addr)
81{
82 unsigned long idx;
83
84 if (!GRANULE_ALIGNED(addr)) {
85 return NULL;
86 }
87
88 idx = plat_granule_addr_to_idx(addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +000089 if (idx >= RMM_MAX_GRANULES) {
90 return NULL;
91 }
92
93 return granule_from_idx(idx);
94}
95
96/*
97 * Obtain a pointer to a locked granule at @addr if @addr is a valid granule
98 * physical address and the state of the granule at @addr is @expected_state.
99 *
100 * Returns:
101 * A valid granule pointer if @addr is a valid granule physical address.
102 * NULL if any of:
103 * - @addr is not aligned to the size of a granule.
104 * - @addr is out of range.
105 * - if the state of the granule at @addr is not
106 * @expected_state.
107 */
108struct granule *find_lock_granule(unsigned long addr,
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000109 unsigned char expected_state)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000110{
AlexeiFedorov745499d2024-04-25 16:52:44 +0100111 struct granule *g = find_granule(addr);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000112
Soby Mathewb4c6df42022-11-09 11:13:29 +0000113 if (g == NULL) {
114 return NULL;
115 }
116
117 if (!granule_lock_on_state_match(g, expected_state)) {
118 return NULL;
119 }
120
121 return g;
122}
123
124struct granule_set {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000125 unsigned long addr;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000126 struct granule *g;
127 struct granule **g_ret;
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000128 unsigned char state;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000129};
130
131/*
132 * Sort a set of granules by their address.
133 */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100134static void sort_granules(struct granule_set *gs, unsigned long n)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000135{
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100136 for (unsigned long i = 1UL; i < n; i++) {
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100137 struct granule_set temp = gs[i];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000138 unsigned long j = i;
139
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100140 while ((j > 0UL) && (gs[j - 1UL].addr > temp.addr)) {
141 gs[j] = gs[j - 1UL];
Soby Mathewb4c6df42022-11-09 11:13:29 +0000142 j--;
143 }
144 if (i != j) {
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100145 gs[j] = temp;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000146 }
147 }
148}
149
150/*
151 * Find a set of granules and lock them in order of their address.
152 *
153 * @granules: Pointer to array of @n items. Each item must be pre-populated
154 * with ->addr set to the granule's address, and ->state set to
155 * the expected state of the granule, and ->g_ret pointing to
156 * a valid 'struct granule *'.
157 * This function sorts the supplied array in place.
158 * @n: Number of struct granule_set in array pointed to by @granules
159 *
160 * Returns:
161 * True if all granules in @granules were successfully locked.
162 *
163 * False if any two entries in @granules have the same ->addr, or
164 * if, for any entry in @granules, any of the following is true:
165 * - entry->addr is not aligned to the size of a granule
166 * - entry->addr is out of range
167 * - the state of the granule at entry->addr is not entry->state
168 *
169 * Locking only succeeds if the granules are in their expected states as per the
170 * locking rules in granule_types.h.
171 *
172 * If the function succeeds, for all items in @granules, ->g points to a locked
173 * granule in ->state and *->g_ret is set to the pointer value.
174 *
175 * If the function fails, no lock is held and no *->g_ret pointers are
176 * modified.
177 */
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100178static bool find_lock_granules(struct granule_set *gs, unsigned long n)
Soby Mathewb4c6df42022-11-09 11:13:29 +0000179{
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100180 unsigned long i;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000181
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100182 sort_granules(gs, n);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000183
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100184 for (i = 0UL; i < n; i++) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000185 /* Check for duplicates */
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100186 if ((i != 0UL) &&
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100187 (gs[i].addr == gs[i - 1UL].addr)) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000188 goto out_err;
189 }
190
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100191 gs[i].g = find_lock_granule(gs[i].addr, gs[i].state);
192 if (gs[i].g == NULL) {
Soby Mathewb4c6df42022-11-09 11:13:29 +0000193 goto out_err;
194 }
195 }
196
AlexeiFedorov93f5ec52023-08-31 14:26:53 +0100197 for (i = 0UL; i < n; i++) {
AlexeiFedorov56e1a8e2023-09-01 17:06:13 +0100198 *gs[i].g_ret = gs[i].g;
Soby Mathewb4c6df42022-11-09 11:13:29 +0000199 }
200
201 return true;
202
203out_err:
AlexeiFedorove956db32024-04-04 14:36:21 +0100204 while (i != 0UL) {
205 granule_unlock(gs[--i].g);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000206 }
207
208 return false;
209}
210
211/*
212 * Find two granules and lock them in order of their address.
213 *
214 * See find_lock_granules().
215 */
216bool find_lock_two_granules(
217 unsigned long addr1,
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000218 unsigned char expected_state1,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000219 struct granule **g1,
220 unsigned long addr2,
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000221 unsigned char expected_state2,
Soby Mathewb4c6df42022-11-09 11:13:29 +0000222 struct granule **g2)
223{
Shruti Gupta9debb132022-12-13 14:38:49 +0000224 struct granule_set gs[] = {
AlexeiFedorovd6d93d82024-02-13 16:52:11 +0000225 {addr1, NULL, g1, expected_state1},
226 {addr2, NULL, g2, expected_state2}
Soby Mathewb4c6df42022-11-09 11:13:29 +0000227 };
228
229 assert((g1 != NULL) && (g2 != NULL));
230
Shruti Gupta9debb132022-12-13 14:38:49 +0000231 return find_lock_granules(gs, ARRAY_SIZE(gs));
Soby Mathewb4c6df42022-11-09 11:13:29 +0000232}
233
Soby Mathewb4c6df42022-11-09 11:13:29 +0000234void granule_memzero_mapped(void *buf)
235{
AlexeiFedorov862f96c2024-03-01 16:26:48 +0000236 unsigned long dczid_el0 = read_dczid_el0();
237 uintptr_t addr = (uintptr_t)buf;
238 unsigned int log2_size;
239 unsigned int block_size;
240 unsigned int cnt;
241
242 /* Check that use of DC ZVA instructions is permitted */
243 assert((dczid_el0 & DCZID_EL0_DZP_BIT) == 0UL);
244
245 /*
246 * Log2 of the block size in words.
247 * The maximum size supported is 2KB, indicated by value 0b1001.
248 */
249 log2_size = (unsigned int)EXTRACT(DCZID_EL0_BS, dczid_el0) + 2U;
250 block_size = U(1) << log2_size;
251
252 /* Number of iterations */
253 cnt = U(1) << (GRANULE_SHIFT - log2_size);
254
255 for (unsigned int i = 0U; i < cnt; i++) {
256 dczva(addr);
257 addr += block_size;
258 }
AlexeiFedorovd9aa2e72024-03-08 11:43:54 +0000259
260 dsb(ish);
Soby Mathewb4c6df42022-11-09 11:13:29 +0000261}
Arunachalam Ganapathy40b3bf02023-06-12 12:19:55 +0100262