1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <arch/encoding.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.
16 /* used to record the value of pmpcfg[i] */
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] */
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);
38 return (read_csr(pmpcfg0
) >> shift
) & 0xff;
40 return (read_csr(pmpcfg1
) >> shift
) & 0xff;
42 return (read_csr(pmpcfg2
) >> shift
) & 0xff;
44 return (read_csr(pmpcfg3
) >> shift
) & 0xff;
46 #elif __riscv_xlen == 64
47 int shift
= 8 * (idx
& 7);
50 return (read_csr(pmpcfg0
) >> shift
) & 0xff;
52 return (read_csr(pmpcfg2
) >> shift
) & 0xff;
58 /* helper function used to write pmpcfg[idx] */
59 static void write_pmpcfg(int idx
, uintptr_t cfg
)
63 #if __riscv_xlen == 32
64 int shift
= 8 * (idx
& 3);
67 old
= read_csr(pmpcfg0
);
68 new = (old
& ~((uintptr_t)0xff << shift
))
69 | ((cfg
& 0xff) << shift
);
70 write_csr(pmpcfg0
, new);
73 old
= read_csr(pmpcfg1
);
74 new = (old
& ~((uintptr_t)0xff << shift
))
75 | ((cfg
& 0xff) << shift
);
76 write_csr(pmpcfg1
, new);
79 old
= read_csr(pmpcfg2
);
80 new = (old
& ~((uintptr_t)0xff << shift
))
81 | ((cfg
& 0xff) << shift
);
82 write_csr(pmpcfg2
, new);
85 old
= read_csr(pmpcfg3
);
86 new = (old
& ~((uintptr_t)0xff << shift
))
87 | ((cfg
& 0xff) << shift
);
88 write_csr(pmpcfg3
, new);
91 #elif __riscv_xlen == 64
92 int shift
= 8 * (idx
& 7);
95 old
= read_csr(pmpcfg0
);
96 new = (old
& ~((uintptr_t)0xff << shift
))
97 | ((cfg
& 0xff) << shift
);
98 write_csr(pmpcfg0
, new);
101 old
= read_csr(pmpcfg2
);
102 new = (old
& ~((uintptr_t)0xff << shift
))
103 | ((cfg
& 0xff) << shift
);
104 write_csr(pmpcfg2
, new);
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
)
117 return read_csr(pmpaddr0
);
119 return read_csr(pmpaddr1
);
121 return read_csr(pmpaddr2
);
123 return read_csr(pmpaddr3
);
125 return read_csr(pmpaddr4
);
127 return read_csr(pmpaddr5
);
129 return read_csr(pmpaddr6
);
131 return read_csr(pmpaddr7
);
133 return read_csr(pmpaddr8
);
135 return read_csr(pmpaddr9
);
137 return read_csr(pmpaddr10
);
139 return read_csr(pmpaddr11
);
141 return read_csr(pmpaddr12
);
143 return read_csr(pmpaddr13
);
145 return read_csr(pmpaddr14
);
147 return read_csr(pmpaddr15
);
152 /* helper function used to write pmpaddr[idx] */
153 static void write_pmpaddr(int idx
, uintptr_t val
)
157 write_csr(pmpaddr0
, val
);
160 write_csr(pmpaddr1
, val
);
163 write_csr(pmpaddr2
, val
);
166 write_csr(pmpaddr3
, val
);
169 write_csr(pmpaddr4
, val
);
172 write_csr(pmpaddr5
, val
);
175 write_csr(pmpaddr6
, val
);
178 write_csr(pmpaddr7
, val
);
181 write_csr(pmpaddr8
, val
);
184 write_csr(pmpaddr9
, val
);
187 write_csr(pmpaddr10
, val
);
190 write_csr(pmpaddr11
, val
);
193 write_csr(pmpaddr12
, val
);
196 write_csr(pmpaddr13
, val
);
199 write_csr(pmpaddr14
, val
);
202 write_csr(pmpaddr15
, val
);
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
)
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
;
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
)
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
;
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
);
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
))
255 if (is_range
&& (free_entries
== 2))
257 if (!is_range
&& (free_entries
== 1))
260 die("Too many PMP configurations, no free entries can be used!");
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 */
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!");
289 /* set up PMP record */
290 void setup_pmp(uintptr_t base
, uintptr_t size
, uintptr_t flags
)
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
);
302 write_pmpaddr(n
- 1, p
.previous_address
);
303 write_pmpcfg(n
, p
.cfg
);
305 mask_pmp_entry_used(n
);
307 mask_pmp_entry_used(n
- 1);