mb/**/hda_verb.c: Drop empty files
[coreboot.git] / src / arch / riscv / pmp.c
blobee39ac44dc14a5a10826b7133e0df31c5a2be8b9
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <arch/encoding.h>
4 #include <stdint.h>
5 #include <arch/pmp.h>
6 #include <console/console.h>
7 #include <commonlib/helpers.h>
9 #define GRANULE (1 << PMP_SHIFT)
12 * This structure is used to temporarily record PMP
13 * configuration information.
15 typedef struct {
16 /* used to record the value of pmpcfg[i] */
17 uintptr_t cfg;
19 * When generating a TOR type configuration,
20 * the previous entry needs to record the starting address.
21 * used to record the value of pmpaddr[i - 1]
23 uintptr_t previous_address;
24 /* used to record the value of pmpaddr[i] */
25 uintptr_t address;
26 } pmpcfg_t;
28 /* This variable is used to record which entries have been used. */
29 static uintptr_t pmp_entry_used_mask;
31 /* helper function used to read pmpcfg[idx] */
32 static uintptr_t read_pmpcfg(int idx)
34 #if __riscv_xlen == 32
35 int shift = 8 * (idx & 3);
36 switch (idx >> 2) {
37 case 0:
38 return (read_csr(pmpcfg0) >> shift) & 0xff;
39 case 1:
40 return (read_csr(pmpcfg1) >> shift) & 0xff;
41 case 2:
42 return (read_csr(pmpcfg2) >> shift) & 0xff;
43 case 3:
44 return (read_csr(pmpcfg3) >> shift) & 0xff;
46 #elif __riscv_xlen == 64
47 int shift = 8 * (idx & 7);
48 switch (idx >> 3) {
49 case 0:
50 return (read_csr(pmpcfg0) >> shift) & 0xff;
51 case 1:
52 return (read_csr(pmpcfg2) >> shift) & 0xff;
54 #endif
55 return -1;
58 /* helper function used to write pmpcfg[idx] */
59 static void write_pmpcfg(int idx, uintptr_t cfg)
61 uintptr_t old;
62 uintptr_t new;
63 #if __riscv_xlen == 32
64 int shift = 8 * (idx & 3);
65 switch (idx >> 2) {
66 case 0:
67 old = read_csr(pmpcfg0);
68 new = (old & ~((uintptr_t)0xff << shift))
69 | ((cfg & 0xff) << shift);
70 write_csr(pmpcfg0, new);
71 break;
72 case 1:
73 old = read_csr(pmpcfg1);
74 new = (old & ~((uintptr_t)0xff << shift))
75 | ((cfg & 0xff) << shift);
76 write_csr(pmpcfg1, new);
77 break;
78 case 2:
79 old = read_csr(pmpcfg2);
80 new = (old & ~((uintptr_t)0xff << shift))
81 | ((cfg & 0xff) << shift);
82 write_csr(pmpcfg2, new);
83 break;
84 case 3:
85 old = read_csr(pmpcfg3);
86 new = (old & ~((uintptr_t)0xff << shift))
87 | ((cfg & 0xff) << shift);
88 write_csr(pmpcfg3, new);
89 break;
91 #elif __riscv_xlen == 64
92 int shift = 8 * (idx & 7);
93 switch (idx >> 3) {
94 case 0:
95 old = read_csr(pmpcfg0);
96 new = (old & ~((uintptr_t)0xff << shift))
97 | ((cfg & 0xff) << shift);
98 write_csr(pmpcfg0, new);
99 break;
100 case 1:
101 old = read_csr(pmpcfg2);
102 new = (old & ~((uintptr_t)0xff << shift))
103 | ((cfg & 0xff) << shift);
104 write_csr(pmpcfg2, new);
105 break;
107 #endif
108 if (read_pmpcfg(idx) != cfg)
109 die("write pmpcfg failure!");
112 /* helper function used to read pmpaddr[idx] */
113 static uintptr_t read_pmpaddr(int idx)
115 switch (idx) {
116 case 0:
117 return read_csr(pmpaddr0);
118 case 1:
119 return read_csr(pmpaddr1);
120 case 2:
121 return read_csr(pmpaddr2);
122 case 3:
123 return read_csr(pmpaddr3);
124 case 4:
125 return read_csr(pmpaddr4);
126 case 5:
127 return read_csr(pmpaddr5);
128 case 6:
129 return read_csr(pmpaddr6);
130 case 7:
131 return read_csr(pmpaddr7);
132 case 8:
133 return read_csr(pmpaddr8);
134 case 9:
135 return read_csr(pmpaddr9);
136 case 10:
137 return read_csr(pmpaddr10);
138 case 11:
139 return read_csr(pmpaddr11);
140 case 12:
141 return read_csr(pmpaddr12);
142 case 13:
143 return read_csr(pmpaddr13);
144 case 14:
145 return read_csr(pmpaddr14);
146 case 15:
147 return read_csr(pmpaddr15);
149 return -1;
152 /* helper function used to write pmpaddr[idx] */
153 static void write_pmpaddr(int idx, uintptr_t val)
155 switch (idx) {
156 case 0:
157 write_csr(pmpaddr0, val);
158 break;
159 case 1:
160 write_csr(pmpaddr1, val);
161 break;
162 case 2:
163 write_csr(pmpaddr2, val);
164 break;
165 case 3:
166 write_csr(pmpaddr3, val);
167 break;
168 case 4:
169 write_csr(pmpaddr4, val);
170 break;
171 case 5:
172 write_csr(pmpaddr5, val);
173 break;
174 case 6:
175 write_csr(pmpaddr6, val);
176 break;
177 case 7:
178 write_csr(pmpaddr7, val);
179 break;
180 case 8:
181 write_csr(pmpaddr8, val);
182 break;
183 case 9:
184 write_csr(pmpaddr9, val);
185 break;
186 case 10:
187 write_csr(pmpaddr10, val);
188 break;
189 case 11:
190 write_csr(pmpaddr11, val);
191 break;
192 case 12:
193 write_csr(pmpaddr12, val);
194 break;
195 case 13:
196 write_csr(pmpaddr13, val);
197 break;
198 case 14:
199 write_csr(pmpaddr14, val);
200 break;
201 case 15:
202 write_csr(pmpaddr15, val);
203 break;
205 if (read_pmpaddr(idx) != val)
206 die("write pmpaddr failure");
209 /* Generate a PMP configuration of type NA4/NAPOT */
210 static pmpcfg_t generate_pmp_napot(
211 uintptr_t base, uintptr_t size, uintptr_t flags)
213 pmpcfg_t p;
214 flags = flags & (PMP_R | PMP_W | PMP_X | PMP_L);
215 p.cfg = flags | (size > GRANULE ? PMP_NAPOT : PMP_NA4);
216 p.previous_address = 0;
217 p.address = (base + (size / 2 - 1)) >> PMP_SHIFT;
218 return p;
221 /* Generate a PMP configuration of type TOR */
222 static pmpcfg_t generate_pmp_range(
223 uintptr_t base, uintptr_t size, uintptr_t flags)
225 pmpcfg_t p;
226 flags = flags & (PMP_R | PMP_W | PMP_X | PMP_L);
227 p.cfg = flags | PMP_TOR;
228 p.previous_address = base >> PMP_SHIFT;
229 p.address = (base + size) >> PMP_SHIFT;
230 return p;
233 /* Generate a PMP configuration */
234 static pmpcfg_t generate_pmp(uintptr_t base, uintptr_t size, uintptr_t flags)
236 if (IS_POWER_OF_2(size) && (size >= 4) && ((base & (size - 1)) == 0))
237 return generate_pmp_napot(base, size, flags);
238 else
239 return generate_pmp_range(base, size, flags);
243 * find empty PMP entry by type
244 * TOR type configuration requires two consecutive PMP entries,
245 * others requires one.
247 static int find_empty_pmp_entry(int is_range)
249 int free_entries = 0;
250 for (int i = 0; i < pmp_entries_num(); i++) {
251 if (pmp_entry_used_mask & (1 << i))
252 free_entries = 0;
253 else
254 free_entries++;
255 if (is_range && (free_entries == 2))
256 return i;
257 if (!is_range && (free_entries == 1))
258 return i;
260 die("Too many PMP configurations, no free entries can be used!");
261 return -1;
265 * mark PMP entry has be used
266 * this function need be used with find_entry_pmp_entry
268 * n = find_empty_pmp_entry(is_range)
269 * ... // PMP set operate
270 * mask_pmp_entry_used(n);
272 static void mask_pmp_entry_used(int idx)
274 pmp_entry_used_mask |= 1 << idx;
277 /* reset PMP setting */
278 void reset_pmp(void)
280 for (int i = 0; i < pmp_entries_num(); i++) {
281 if (read_pmpcfg(i) & PMP_L)
282 die("Some PMP configurations are locked "
283 "and cannot be reset!");
284 write_pmpcfg(i, 0);
285 write_pmpaddr(i, 0);
289 /* set up PMP record */
290 void setup_pmp(uintptr_t base, uintptr_t size, uintptr_t flags)
292 pmpcfg_t p;
293 int is_range, n;
295 p = generate_pmp(base, size, flags);
296 is_range = ((p.cfg & PMP_A) == PMP_TOR);
298 n = find_empty_pmp_entry(is_range);
300 write_pmpaddr(n, p.address);
301 if (is_range)
302 write_pmpaddr(n - 1, p.previous_address);
303 write_pmpcfg(n, p.cfg);
305 mask_pmp_entry_used(n);
306 if (is_range)
307 mask_pmp_entry_used(n - 1);