1 #include "csi_core.h"
2 #include "rv_pmp.h"
3
rvpmp_reg_write(uintptr_t i,uintptr_t attr,uintptr_t pa)4 static void rvpmp_reg_write(uintptr_t i, uintptr_t attr, uintptr_t pa)
5 {
6 register uintptr_t cfg = 0;
7 uintptr_t offset = 0;
8 uintptr_t mask = ENTRY_FLAG_MASK;
9
10 switch (i) {
11 case 0:
12 __asm volatile("csrw pmpaddr0, %0"
13 :
14 : "r"(pa));
15 break;
16 #ifndef CONIFG_DISABLE_ALL_PMP_EXCEPT_PMPADDR0
17 case 1:
18 __asm volatile("csrw pmpaddr1, %0"
19 :
20 : "r"(pa));
21 break;
22
23 case 2:
24 __asm volatile("csrw pmpaddr2, %0"
25 :
26 : "r"(pa));
27 break;
28
29 case 3:
30 __asm volatile("csrw pmpaddr3, %0"
31 :
32 : "r"(pa));
33 break;
34
35 case 4:
36 __asm volatile("csrw pmpaddr4, %0"
37 :
38 : "r"(pa));
39 break;
40
41 case 5:
42 __asm volatile("csrw pmpaddr5, %0"
43 :
44 : "r"(pa));
45 break;
46
47 case 6:
48 __asm volatile("csrw pmpaddr6, %0"
49 :
50 : "r"(pa));
51 break;
52
53 case 7:
54 __asm volatile("csrw pmpaddr7, %0"
55 :
56 : "r"(pa));
57 break;
58
59 case 8:
60 __asm volatile("csrw pmpaddr8, %0"
61 :
62 : "r"(pa));
63 break;
64
65 case 9:
66 __asm volatile("csrw pmpaddr9, %0"
67 :
68 : "r"(pa));
69 break;
70
71 case 10:
72 __asm volatile("csrw pmpaddr10, %0"
73 :
74 : "r"(pa));
75 break;
76
77 case 11:
78 __asm volatile("csrw pmpaddr11, %0"
79 :
80 : "r"(pa));
81 break;
82
83 case 12:
84 __asm volatile("csrw pmpaddr12, %0"
85 :
86 : "r"(pa));
87 break;
88
89 case 13:
90 __asm volatile("csrw pmpaddr13, %0"
91 :
92 : "r"(pa));
93 break;
94
95 case 14:
96 __asm volatile("csrw pmpaddr14, %0"
97 :
98 : "r"(pa));
99 break;
100
101 case 15:
102 __asm volatile("csrw pmpaddr15, %0"
103 :
104 : "r"(pa));
105 break;
106 #endif
107 default:
108 break;
109 }
110
111 #if (__riscv_xlen == 32)
112
113 switch (i) {
114 case 0 ... 3:
115 __asm volatile("csrr %0, pmpcfg0"
116 : "=r"(cfg));
117 offset = i % ENTRY_IN_CFG_REG;
118 cfg &= ~(mask << (offset * ENTRY_FLAG_SIZE));
119 cfg |= attr << (offset * ENTRY_FLAG_SIZE);
120 __asm volatile("csrw pmpcfg0, %0"
121 :
122 : "r"(cfg));
123 break;
124 #ifndef CONIFG_DISABLE_ALL_PMP_EXCEPT_PMPADDR0
125 case 4 ... 7:
126 __asm volatile("csrr %0, pmpcfg1"
127 : "=r"(cfg));
128 offset = i % ENTRY_IN_CFG_REG;
129 cfg &= ~(mask << (offset * ENTRY_FLAG_SIZE));
130 cfg |= attr << (offset * ENTRY_FLAG_SIZE);
131 __asm volatile("csrw pmpcfg1, %0"
132 :
133 : "r"(cfg));
134 break;
135
136 case 8 ... 11:
137 __asm volatile("csrr %0, pmpcfg2"
138 : "=r"(cfg));
139 offset = i % ENTRY_IN_CFG_REG;
140 cfg &= ~(mask << (offset * ENTRY_FLAG_SIZE));
141 cfg |= attr << (offset * ENTRY_FLAG_SIZE);
142 __asm volatile("csrw pmpcfg2, %0"
143 :
144 : "r"(cfg));
145 break;
146
147 case 12 ... 15:
148 __asm volatile("csrr %0, pmpcfg3"
149 : "=r"(cfg));
150 offset = i % ENTRY_IN_CFG_REG;
151 cfg &= ~(mask << (offset * ENTRY_FLAG_SIZE));
152 cfg |= attr << (offset * ENTRY_FLAG_SIZE);
153 __asm volatile("csrw pmpcfg3, %0"
154 :
155 : "r"(cfg));
156 break;
157 #endif
158 default:
159 break;
160 }
161
162 #elif (__riscv_xlen == 64)
163
164 switch (i) {
165 case 0 ... 7:
166 __asm volatile("csrr %0, pmpcfg0"
167 : "=r"(cfg));
168 offset = i % ENTRY_IN_CFG_REG;
169 cfg &= (~(mask << (offset * ENTRY_FLAG_SIZE)));
170 cfg |= (attr << (offset * ENTRY_FLAG_SIZE));
171 __asm volatile("csrw pmpcfg0, %0"
172 :
173 : "r"(cfg));
174 break;
175 #ifndef CONIFG_DISABLE_ALL_PMP_EXCEPT_PMPADDR0
176 case 8 ... 15:
177 __asm volatile("csrr %0, pmpcfg2"
178 : "=r"(cfg));
179 offset = i % ENTRY_IN_CFG_REG;
180 cfg &= ~(mask << (offset * ENTRY_FLAG_SIZE));
181 cfg |= attr << (offset * ENTRY_FLAG_SIZE);
182 __asm volatile("csrw pmpcfg2, %0"
183 :
184 : "r"(cfg));
185 break;
186 #endif
187 default:
188 break;
189 }
190
191 #else
192 #error "XLEN of riscv not supported"
193 #endif
194 }
195
pmp_get_config(uintptr_t e)196 static uint32_t pmp_get_config(uintptr_t e)
197 {
198 uintptr_t cfg = 0;
199 uint32_t offset = 0;
200
201 #if (__riscv_xlen == 32)
202
203 switch (e) {
204 case 0 ... 3:
205 __asm volatile("csrr %0, pmpcfg0"
206 : "=r"(cfg));
207 break;
208 #ifndef CONIFG_DISABLE_ALL_PMP_EXCEPT_PMPADDR0
209 case 4 ... 7:
210 __asm volatile("csrr %0, pmpcfg1"
211 : "=r"(cfg));
212 break;
213
214 case 8 ... 11:
215 __asm volatile("csrr %0, pmpcfg2"
216 : "=r"(cfg));
217 break;
218
219 case 12 ... 15:
220 __asm volatile("csrr %0, pmpcfg3"
221 : "=r"(cfg));
222 break;
223 #endif
224 default:
225 break;
226 }
227
228 #elif (__riscv_xlen == 64)
229
230 switch (e) {
231 case 0 ... 7:
232 __asm volatile("csrr %0, pmpcfg0"
233 : "=r"(cfg));
234 break;
235 #ifndef CONIFG_DISABLE_ALL_PMP_EXCEPT_PMPADDR0
236 case 8 ... 15:
237 __asm volatile("csrr %0, pmpcfg2"
238 : "=r"(cfg));
239 break;
240 #endif
241 default:
242 break;
243 }
244
245 #else
246 #error "XLEN of riscv not supported"
247 #endif
248
249 offset = e % ENTRY_IN_CFG_REG;
250 cfg >>= (offset * ENTRY_FLAG_SIZE);
251
252 return cfg & ENTRY_FLAG_MASK;
253 }
254
rvpmp_fill_entry(const pmp_config_entry_t * entry,uintptr_t i,uintptr_t force)255 pmp_status_type_e rvpmp_fill_entry(const pmp_config_entry_t *entry, uintptr_t i, uintptr_t force)
256 {
257 uintptr_t am = 0;
258 uintptr_t attr = 0;
259 uintptr_t pa = 0;
260 pmp_status_type_e ret = PMP_STATUS_OK;
261 uint32_t cfg;
262
263 /* check entry */
264 cfg = pmp_get_config(i);
265 if (cfg & ENTRY_FLAG_M_MODE_L) {
266 return PMP_STATUS_DENIED;
267 } else if ((cfg & ENTRY_FLAG_ADDR_MASK) && (!force)) {
268 return PMP_STATUS_BUSY;
269 }
270
271 attr = entry->entry_flag;
272 pa = entry->entry_pa_base;
273
274 am = entry->entry_flag & ENTRY_FLAG_ADDR_MASK;
275
276 switch (am) {
277 case ENTRY_FLAG_ADDR_OFF:
278 break;
279 case ENTRY_FLAG_ADDR_TOR:
280 pa >>= 2;
281 break;
282
283 case ENTRY_FLAG_ADDR_NAPOT:
284 /* rule of NAPOT */
285 if (pa & (entry->entry_pa_length - 1))
286 ret = PMP_STATUS_INVALID;
287 pa |= (entry->entry_pa_length - 1) >> 1;
288 pa >>= 2;
289 break;
290
291 default:
292 attr = 0;
293 ret = PMP_STATUS_UNSUPPORTED;
294 break;
295 }
296
297 if (PMP_STATUS_OK == ret)
298 rvpmp_reg_write(i, attr, pa);
299
300 return ret;
301 }
302
rvpmp_init(const pmp_config_entry_t * entry,uintptr_t n)303 pmp_status_type_e rvpmp_init(const pmp_config_entry_t *entry, uintptr_t n)
304 {
305 uintptr_t i = 0;
306 pmp_status_type_e ret = PMP_STATUS_OK;
307
308 __asm volatile ("fence":::"memory");
309
310 for (; i < n; i++) {
311 ret = rvpmp_fill_entry(&entry[i], i, 0);
312 if (PMP_STATUS_OK != ret)
313 break;
314 }
315
316 __asm volatile ("fence":::"memory");
317
318 return ret;
319 }
320