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