master
c 807 lines 23.4 KB
Raw
1 /*
2 * QEMU RISC-V PMP (Physical Memory Protection)
3 *
4 * Author: Daire McNamara, daire.mcnamara@emdalo.com
5 * Ivan Griffin, ivan.griffin@emdalo.com
6 *
7 * This provides a RISC-V Physical Memory Protection implementation
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2 or later, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "qemu/osdep.h"
23 #include "qemu/log.h"
24 #include "qapi/error.h"
25 #include "cpu.h"
26 #include "target/riscv/tcg/csr.h"
27 #include "trace.h"
28 #include "exec/cputlb.h"
29 #include "exec/page-protection.h"
30 #include "exec/target_page.h"
31
32 static bool pmp_write_cfg(CPURISCVState *env, uint32_t addr_index,
33 uint8_t val);
34 static uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t addr_index);
35
36 /*
37 * Convert the PMP permissions to match the truth table in the Smepmp spec.
38 */
39 static inline uint8_t pmp_get_smepmp_operation(uint8_t cfg)
40 {
41 return ((cfg & PMP_LOCK) >> 4) | ((cfg & PMP_READ) << 2) |
42 (cfg & PMP_WRITE) | ((cfg & PMP_EXEC) >> 2);
43 }
44
45 /*
46 * Accessor method to extract address matching type 'a field' from cfg reg
47 */
48 static inline uint8_t pmp_get_a_field(uint8_t cfg)
49 {
50 uint8_t a = cfg >> 3;
51 return a & 0x3;
52 }
53
54 /*
55 * Check whether a PMP is locked or not.
56 */
57 static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
58 {
59 if (env->pmp_state.pmp[pmp_index].cfg_reg & PMP_LOCK) {
60 return 1;
61 }
62
63 return 0;
64 }
65
66 /*
67 * Check whether a PMP is locked for writing or not.
68 * (i.e. has LOCK flag and mseccfg.RLB is unset)
69 */
70 static int pmp_is_readonly(CPURISCVState *env, uint32_t pmp_index)
71 {
72 return pmp_is_locked(env, pmp_index) && !MSECCFG_RLB_ISSET(env);
73 }
74
75 /*
76 * Check whether `val` is an invalid Smepmp config value
77 */
78 static int pmp_is_invalid_smepmp_cfg(CPURISCVState *env, uint8_t val)
79 {
80 /* No check if mseccfg.MML is not set or if mseccfg.RLB is set */
81 if (!MSECCFG_MML_ISSET(env) || MSECCFG_RLB_ISSET(env)) {
82 return 0;
83 }
84
85 /*
86 * Adding a rule with executable privileges that either is M-mode-only
87 * or a locked Shared-Region is not possible
88 */
89 switch (pmp_get_smepmp_operation(val)) {
90 case 0:
91 case 1:
92 case 2:
93 case 3:
94 case 4:
95 case 5:
96 case 6:
97 case 7:
98 case 8:
99 case 12:
100 case 14:
101 case 15:
102 return 0;
103 case 9:
104 case 10:
105 case 11:
106 case 13:
107 return 1;
108 default:
109 g_assert_not_reached();
110 }
111 }
112 /*
113 * Calculate PMP granularity value 'g'
114 *
115 * The granularity value 'g' is defined as log2(granularity) - 2, where
116 * granularity is the minimum alignment requirement for PMP regions in bytes.
117 */
118 static inline int pmp_get_granularity_g(CPURISCVState *env)
119 {
120 return __builtin_ctz(riscv_cpu_cfg(env)->pmp_granularity >> 2);
121 }
122
123
124 /*
125 * Count the number of active rules.
126 */
127 uint32_t pmp_get_num_rules(CPURISCVState *env)
128 {
129 return env->pmp_state.num_rules;
130 }
131
132 /*
133 * Accessor to get the cfg reg for a specific PMP/HART
134 */
135 static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
136 {
137 uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
138
139 if (pmp_index < pmp_regions) {
140 return env->pmp_state.pmp[pmp_index].cfg_reg;
141 }
142
143 return 0;
144 }
145
146
147 /*
148 * Accessor to set the cfg reg for a specific PMP/HART
149 * Bounds checks and relevant lock bit.
150 */
151 static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
152 {
153 uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
154
155 if (pmp_index < pmp_regions) {
156 if (env->pmp_state.pmp[pmp_index].cfg_reg == val) {
157 /* no change */
158 return false;
159 }
160
161 if (pmp_is_readonly(env, pmp_index)) {
162 qemu_log_mask(LOG_GUEST_ERROR,
163 "ignoring pmpcfg write - read only\n");
164 } else if (pmp_is_invalid_smepmp_cfg(env, val)) {
165 qemu_log_mask(LOG_GUEST_ERROR,
166 "ignoring pmpcfg write - invalid\n");
167 } else {
168 uint8_t a_field = pmp_get_a_field(val);
169
170 if (!riscv_cpu_cfg(env)->ext_smpmpmt) {
171 /* If smpmpmt not supported, clear the MTMATCH bit */
172 val &= ~PMP_MTMATCH;
173 } else if ((val & PMP_MTMATCH) == PMP_MTMATCH) {
174 /*
175 * If trying to set reserved value (0x3) for MT field,
176 * preserve the original MT field from current config.
177 */
178 val = (val & ~PMP_MTMATCH) |
179 (env->pmp_state.pmp[pmp_index].cfg_reg & PMP_MTMATCH);
180 }
181 /*
182 * When granularity g >= 1 (i.e., granularity > 4 bytes),
183 * the NA4 (Naturally Aligned 4-byte) mode is not selectable.
184 * In this case, an NA4 setting is reinterpreted as a NAPOT mode.
185 */
186 if ((riscv_cpu_cfg(env)->pmp_granularity >
187 MIN_RISCV_PMP_GRANULARITY) && (a_field == PMP_AMATCH_NA4)) {
188 val |= PMP_AMATCH;
189 }
190 env->pmp_state.pmp[pmp_index].cfg_reg = val;
191 pmp_update_rule_addr(env, pmp_index);
192 return true;
193 }
194 } else {
195 qemu_log_mask(LOG_GUEST_ERROR,
196 "ignoring pmpcfg write - out of bounds\n");
197 }
198
199 return false;
200 }
201
202 void pmp_unlock_entries(CPURISCVState *env)
203 {
204 uint32_t pmp_num = pmp_get_num_rules(env);
205 int i;
206
207 for (i = 0; i < pmp_num; i++) {
208 env->pmp_state.pmp[i].cfg_reg &= ~(PMP_LOCK | PMP_AMATCH);
209 }
210 }
211
212 static void pmp_decode_napot(hwaddr a, hwaddr *sa, hwaddr *ea)
213 {
214 /*
215 * aaaa...aaa0 8-byte NAPOT range
216 * aaaa...aa01 16-byte NAPOT range
217 * aaaa...a011 32-byte NAPOT range
218 * ...
219 * aa01...1111 2^XLEN-byte NAPOT range
220 * a011...1111 2^(XLEN+1)-byte NAPOT range
221 * 0111...1111 2^(XLEN+2)-byte NAPOT range
222 * 1111...1111 Reserved
223 */
224 a = (a << 2) | 0x3;
225 *sa = a & (a + 1);
226 *ea = a | (a + 1);
227 }
228
229 void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index)
230 {
231 uint8_t this_cfg = env->pmp_state.pmp[pmp_index].cfg_reg;
232 hwaddr this_addr = env->pmp_state.pmp[pmp_index].addr_reg;
233 hwaddr prev_addr = 0u;
234 hwaddr sa = 0u;
235 hwaddr ea = 0u;
236 int g = pmp_get_granularity_g(env);
237
238 if (pmp_index >= 1u) {
239 prev_addr = env->pmp_state.pmp[pmp_index - 1].addr_reg;
240 }
241
242 switch (pmp_get_a_field(this_cfg)) {
243 case PMP_AMATCH_OFF:
244 sa = 0u;
245 ea = -1;
246 break;
247
248 case PMP_AMATCH_TOR:
249 /* Bits pmpaddr[G-1:0] do not affect the TOR address-matching logic. */
250 if (g >= 1) {
251 uint64_t granule = 1ULL << g;
252 prev_addr = ROUND_DOWN(prev_addr, granule);
253 this_addr = ROUND_DOWN(this_addr, granule);
254 }
255 if (prev_addr >= this_addr) {
256 sa = ea = 0u;
257 break;
258 }
259 sa = prev_addr << 2; /* shift up from [xx:0] to [xx+2:2] */
260 ea = (this_addr << 2) - 1u;
261 break;
262
263 case PMP_AMATCH_NA4:
264 sa = this_addr << 2; /* shift up from [xx:0] to [xx+2:2] */
265 ea = (sa + 4u) - 1u;
266 break;
267
268 case PMP_AMATCH_NAPOT:
269 /* Bits [g-2:0] need to be all one to align pmp granularity */
270 if (g >= 2) {
271 this_addr = deposit64(this_addr, 0, g - 1, -1ULL);
272 }
273
274 pmp_decode_napot(this_addr, &sa, &ea);
275 break;
276
277 default:
278 sa = 0u;
279 ea = 0u;
280 break;
281 }
282
283 env->pmp_state.addr[pmp_index].sa = sa;
284 env->pmp_state.addr[pmp_index].ea = ea;
285 }
286
287 void pmp_update_rule_nums(CPURISCVState *env)
288 {
289 int i;
290 uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
291
292 env->pmp_state.num_rules = 0;
293 for (i = 0; i < pmp_regions; i++) {
294 const uint8_t a_field =
295 pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
296 if (PMP_AMATCH_OFF != a_field) {
297 env->pmp_state.num_rules++;
298 }
299 }
300 }
301
302 static int pmp_is_in_range(CPURISCVState *env, int pmp_index, hwaddr addr)
303 {
304 int result = 0;
305
306 if ((addr >= env->pmp_state.addr[pmp_index].sa) &&
307 (addr <= env->pmp_state.addr[pmp_index].ea)) {
308 result = 1;
309 } else {
310 result = 0;
311 }
312
313 return result;
314 }
315
316 /*
317 * Check if the address has required RWX privs when no PMP entry is matched.
318 */
319 static bool pmp_hart_has_privs_default(CPURISCVState *env, pmp_priv_t privs,
320 pmp_priv_t *allowed_privs,
321 privilege_mode_t mode)
322 {
323 bool ret;
324
325 if (MSECCFG_MMWP_ISSET(env)) {
326 /*
327 * The Machine Mode Whitelist Policy (mseccfg.MMWP) is set
328 * so we default to deny all, even for M-mode.
329 */
330 *allowed_privs = 0;
331 return false;
332 } else if (MSECCFG_MML_ISSET(env)) {
333 /*
334 * The Machine Mode Lockdown (mseccfg.MML) bit is set
335 * so we can only execute code in M-mode with an applicable
336 * rule. Other modes are disabled.
337 */
338 if (mode == PRV_M && !(privs & PMP_EXEC)) {
339 ret = true;
340 *allowed_privs = PMP_READ | PMP_WRITE;
341 } else {
342 ret = false;
343 *allowed_privs = 0;
344 }
345
346 return ret;
347 }
348
349 if (!riscv_cpu_cfg(env)->pmp || (mode == PRV_M)) {
350 /*
351 * Privileged spec v1.10 states if HW doesn't implement any PMP entry
352 * or no PMP entry matches an M-Mode access, the access succeeds.
353 */
354 ret = true;
355 *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
356 } else {
357 /*
358 * Other modes are not allowed to succeed if they don't * match a rule,
359 * but there are rules. We've checked for no rule earlier in this
360 * function.
361 */
362 ret = false;
363 *allowed_privs = 0;
364 }
365
366 return ret;
367 }
368
369
370 /*
371 * Public Interface
372 */
373
374 /*
375 * Check if the address has required RWX privs to complete desired operation
376 * Return true if a pmp rule match or default match
377 * Return false if no match
378 *
379 * Note: The MT (Memory Type) field from Smpmpmt extension is stored in
380 * pmpcfg but is not acted upon during access checks. Cache attributes
381 * have no functional impact in QEMU emulation.
382 */
383 bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
384 int size, pmp_priv_t privs,
385 pmp_priv_t *allowed_privs,
386 privilege_mode_t mode)
387 {
388 int i = 0;
389 int pmp_size = 0;
390 hwaddr s = 0;
391 hwaddr e = 0;
392 uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
393
394 /* Short cut if no rules */
395 if (0 == pmp_get_num_rules(env)) {
396 return pmp_hart_has_privs_default(env, privs, allowed_privs, mode);
397 }
398
399 if (size == 0) {
400 if (riscv_cpu_cfg(env)->mmu) {
401 /*
402 * If size is unknown (0), assume that all bytes
403 * from addr to the end of the page will be accessed.
404 */
405 pmp_size = -(addr | TARGET_PAGE_MASK);
406 } else {
407 pmp_size = 2 << riscv_cpu_mxl(env);
408 }
409 } else {
410 pmp_size = size;
411 }
412
413 /*
414 * 1.10 draft priv spec states there is an implicit order
415 * from low to high
416 */
417 for (i = 0; i < pmp_regions; i++) {
418 s = pmp_is_in_range(env, i, addr);
419 e = pmp_is_in_range(env, i, addr + pmp_size - 1);
420
421 /* partially inside */
422 if ((s + e) == 1) {
423 qemu_log_mask(LOG_GUEST_ERROR,
424 "pmp violation - access is partially inside\n");
425 *allowed_privs = 0;
426 return false;
427 }
428
429 /* fully inside */
430 const uint8_t a_field =
431 pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
432
433 if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
434 /*
435 * If the PMP entry is not off and the address is in range,
436 * do the priv check
437 */
438 if (!MSECCFG_MML_ISSET(env)) {
439 /*
440 * If mseccfg.MML Bit is not set, do pmp priv check
441 * This will always apply to regular PMP.
442 */
443 *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
444 if ((mode != PRV_M) || pmp_is_locked(env, i)) {
445 *allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
446 }
447 } else {
448 /*
449 * If mseccfg.MML Bit set, do the enhanced pmp priv check
450 */
451 const uint8_t smepmp_operation =
452 pmp_get_smepmp_operation(env->pmp_state.pmp[i].cfg_reg);
453
454 if (mode == PRV_M) {
455 switch (smepmp_operation) {
456 case 0:
457 case 1:
458 case 4:
459 case 5:
460 case 6:
461 case 7:
462 case 8:
463 *allowed_privs = 0;
464 break;
465 case 2:
466 case 3:
467 case 14:
468 *allowed_privs = PMP_READ | PMP_WRITE;
469 break;
470 case 9:
471 case 10:
472 *allowed_privs = PMP_EXEC;
473 break;
474 case 11:
475 case 13:
476 *allowed_privs = PMP_READ | PMP_EXEC;
477 break;
478 case 12:
479 case 15:
480 *allowed_privs = PMP_READ;
481 break;
482 default:
483 g_assert_not_reached();
484 }
485 } else {
486 switch (smepmp_operation) {
487 case 0:
488 case 8:
489 case 9:
490 case 12:
491 case 13:
492 case 14:
493 *allowed_privs = 0;
494 break;
495 case 1:
496 case 10:
497 case 11:
498 *allowed_privs = PMP_EXEC;
499 break;
500 case 2:
501 case 4:
502 case 15:
503 *allowed_privs = PMP_READ;
504 break;
505 case 3:
506 case 6:
507 *allowed_privs = PMP_READ | PMP_WRITE;
508 break;
509 case 5:
510 *allowed_privs = PMP_READ | PMP_EXEC;
511 break;
512 case 7:
513 *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
514 break;
515 default:
516 g_assert_not_reached();
517 }
518 }
519 }
520
521 /*
522 * If matching address range was found, the protection bits
523 * defined with PMP must be used. We shouldn't fallback on
524 * finding default privileges.
525 */
526 return (privs & *allowed_privs) == privs;
527 }
528 }
529
530 /* No rule matched */
531 return pmp_hart_has_privs_default(env, privs, allowed_privs, mode);
532 }
533
534 /*
535 * Handle a write to a pmpcfg CSR
536 */
537 void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
538 target_ulong val)
539 {
540 int i;
541 uint8_t cfg_val;
542 int pmpcfg_nums = 2 << riscv_cpu_mxl(env);
543 bool modified = false;
544
545 trace_pmpcfg_csr_write(env->mhartid, reg_index, val);
546
547 for (i = 0; i < pmpcfg_nums; i++) {
548 cfg_val = (val >> 8 * i) & 0xff;
549 modified |= pmp_write_cfg(env, (reg_index * 4) + i, cfg_val);
550 }
551
552 /* If PMP permission of any addr has been changed, flush TLB pages. */
553 if (modified) {
554 pmp_update_rule_nums(env);
555 tlb_flush(env_cpu(env));
556 }
557 }
558
559
560 /*
561 * Handle a read from a pmpcfg CSR
562 */
563 target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index)
564 {
565 int i;
566 target_ulong cfg_val = 0;
567 target_ulong val = 0;
568 int pmpcfg_nums = 2 << riscv_cpu_mxl(env);
569
570 for (i = 0; i < pmpcfg_nums; i++) {
571 val = pmp_read_cfg(env, (reg_index * 4) + i);
572 cfg_val |= (val << (i * 8));
573 }
574 trace_pmpcfg_csr_read(env->mhartid, reg_index, cfg_val);
575
576 return cfg_val;
577 }
578
579
580 /*
581 * Handle a write to a pmpaddr CSR
582 */
583 void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
584 target_ulong val)
585 {
586 trace_pmpaddr_csr_write(env->mhartid, addr_index, val);
587 bool is_next_cfg_tor = false;
588 uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
589
590 if (addr_index < pmp_regions) {
591 if (env->pmp_state.pmp[addr_index].addr_reg == val) {
592 /* no change */
593 return;
594 }
595
596 /*
597 * In TOR mode, need to check the lock bit of the next pmp
598 * (if there is a next).
599 */
600 if (addr_index + 1 < pmp_regions) {
601 uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg;
602 is_next_cfg_tor = PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg);
603
604 if (pmp_is_readonly(env, addr_index + 1) && is_next_cfg_tor) {
605 qemu_log_mask(LOG_GUEST_ERROR,
606 "ignoring pmpaddr write - pmpcfg+1 read only\n");
607 return;
608 }
609 }
610
611 if (!pmp_is_readonly(env, addr_index)) {
612 env->pmp_state.pmp[addr_index].addr_reg = val;
613 pmp_update_rule_addr(env, addr_index);
614 if (is_next_cfg_tor) {
615 pmp_update_rule_addr(env, addr_index + 1);
616 }
617 tlb_flush(env_cpu(env));
618 } else {
619 qemu_log_mask(LOG_GUEST_ERROR,
620 "ignoring pmpaddr write - read only\n");
621 }
622 } else {
623 qemu_log_mask(LOG_GUEST_ERROR,
624 "ignoring pmpaddr write - out of bounds\n");
625 }
626 }
627
628
629 /*
630 * Handle a read from a pmpaddr CSR
631 * Change A field of pmpcfg affects the read value of pmpaddr
632 */
633 target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index)
634 {
635 target_ulong val = 0;
636 uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
637
638 if (addr_index < pmp_regions) {
639 val = env->pmp_state.pmp[addr_index].addr_reg;
640 int g = pmp_get_granularity_g(env);
641 switch (pmp_get_a_field(env->pmp_state.pmp[addr_index].cfg_reg)) {
642 case PMP_AMATCH_OFF:
643 /* fallthrough */
644 case PMP_AMATCH_TOR:
645 /* Bit [g-1:0] read all zero */
646 if (g >= 1 && g < TARGET_LONG_BITS) {
647 uint64_t granule = 1ULL << g;
648 val = ROUND_DOWN(val, granule);
649 }
650 break;
651 case PMP_AMATCH_NAPOT:
652 /* Bit [g-2:0] read all one */
653 if (g >= 2 && g < TARGET_LONG_BITS) {
654 val = deposit64(val, 0, g - 1, -1ULL);
655 }
656 break;
657 default:
658 break;
659 }
660 trace_pmpaddr_csr_read(env->mhartid, addr_index, val);
661 } else {
662 qemu_log_mask(LOG_GUEST_ERROR,
663 "ignoring pmpaddr read - out of bounds\n");
664 }
665
666 return val;
667 }
668
669 /*
670 * Handle a write to a mseccfg CSR
671 */
672 void mseccfg_csr_write(CPURISCVState *env, uint64_t val)
673 {
674 int i;
675 uint64_t mask = MSECCFG_MMWP | MSECCFG_MML;
676 uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
677 /* Update PMM field only if the value is valid according to Zjpm v1.0 */
678 if (riscv_cpu_cfg(env)->ext_smmpm &&
679 riscv_cpu_mxl(env) == MXL_RV64 &&
680 get_field(val, MSECCFG_PMM) != PMM_FIELD_RESERVED) {
681 mask |= MSECCFG_PMM;
682 }
683
684 trace_mseccfg_csr_write(env->mhartid, val);
685
686 /* RLB cannot be enabled if it's already 0 and if any regions are locked */
687 if (!MSECCFG_RLB_ISSET(env)) {
688 for (i = 0; i < pmp_regions; i++) {
689 if (pmp_is_locked(env, i)) {
690 val &= ~MSECCFG_RLB;
691 break;
692 }
693 }
694 }
695
696 if (riscv_cpu_cfg(env)->ext_smepmp) {
697 /* Sticky bits */
698 val |= (env->mseccfg & mask);
699 if ((val ^ env->mseccfg) & mask) {
700 tlb_flush(env_cpu(env));
701 }
702 } else {
703 mask |= MSECCFG_RLB;
704 val &= ~(mask);
705 }
706
707 /* M-mode forward cfi to be enabled if cfi extension is implemented */
708 if (env_archcpu(env)->cfg.ext_zicfilp) {
709 val |= (val & MSECCFG_MLPE);
710 }
711
712 env->mseccfg = val;
713 }
714
715 /*
716 * Handle a read from a mseccfg CSR
717 */
718 uint64_t mseccfg_csr_read(CPURISCVState *env)
719 {
720 trace_mseccfg_csr_read(env->mhartid, env->mseccfg);
721 return env->mseccfg;
722 }
723
724 /*
725 * Calculate the TLB size.
726 * It's possible that PMP regions only cover partial of the TLB page, and
727 * this may split the page into regions with different permissions.
728 * For example if PMP0 is (0x80000008~0x8000000F, R) and PMP1 is (0x80000000
729 * ~0x80000FFF, RWX), then region 0x80000008~0x8000000F has R permission, and
730 * the other regions in this page have RWX permissions.
731 * A write access to 0x80000000 will match PMP1. However we cannot cache the
732 * translation result in the TLB since this will make the write access to
733 * 0x80000008 bypass the check of PMP0.
734 * To avoid this we return a size of 1 (which means no caching) if the PMP
735 * region only covers partial of the TLB page.
736 */
737 uint64_t pmp_get_tlb_size(CPURISCVState *env, hwaddr addr)
738 {
739 hwaddr pmp_sa;
740 hwaddr pmp_ea;
741 hwaddr tlb_sa = addr & ~(TARGET_PAGE_SIZE - 1);
742 hwaddr tlb_ea = tlb_sa + TARGET_PAGE_SIZE - 1;
743 int i;
744 uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
745
746 /*
747 * If PMP is not supported or there are no PMP rules, the TLB page will not
748 * be split into regions with different permissions by PMP so we set the
749 * size to TARGET_PAGE_SIZE.
750 */
751 if (!riscv_cpu_cfg(env)->pmp || !pmp_get_num_rules(env)) {
752 return TARGET_PAGE_SIZE;
753 }
754
755 for (i = 0; i < pmp_regions; i++) {
756 if (pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg) == PMP_AMATCH_OFF) {
757 continue;
758 }
759
760 pmp_sa = env->pmp_state.addr[i].sa;
761 pmp_ea = env->pmp_state.addr[i].ea;
762
763 /*
764 * Only the first PMP entry that covers (whole or partial of) the TLB
765 * page really matters:
766 * If it covers the whole TLB page, set the size to TARGET_PAGE_SIZE,
767 * since the following PMP entries have lower priority and will not
768 * affect the permissions of the page.
769 * If it only covers partial of the TLB page, set the size to 1 since
770 * the allowed permissions of the region may be different from other
771 * region of the page.
772 */
773 if (pmp_sa <= tlb_sa && pmp_ea >= tlb_ea) {
774 return TARGET_PAGE_SIZE;
775 } else if ((pmp_sa >= tlb_sa && pmp_sa <= tlb_ea) ||
776 (pmp_ea >= tlb_sa && pmp_ea <= tlb_ea)) {
777 return 1;
778 }
779 }
780
781 /*
782 * If no PMP entry matches the TLB page, the TLB page will also not be
783 * split into regions with different permissions by PMP so we set the size
784 * to TARGET_PAGE_SIZE.
785 */
786 return TARGET_PAGE_SIZE;
787 }
788
789 /*
790 * Convert PMP privilege to TLB page privilege.
791 */
792 int pmp_priv_to_page_prot(pmp_priv_t pmp_priv)
793 {
794 int prot = 0;
795
796 if (pmp_priv & PMP_READ) {
797 prot |= PAGE_READ;
798 }
799 if (pmp_priv & PMP_WRITE) {
800 prot |= PAGE_WRITE;
801 }
802 if (pmp_priv & PMP_EXEC) {
803 prot |= PAGE_EXEC;
804 }
805
806 return prot;
807 }