@@ -362,6 +362,17 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
362362extern bool rvfi_debug_output ;
363363#endif
364364
365+ #ifndef RISCV_PTE_TRAPPY
366+ /*
367+ * The PTW logic below supports trapping on any subset of PTE_A, PTE_D, PTE_CD
368+ * being clear during an access that would have them be set. The RISC-V spec
369+ * says that PTE_A and PTE_D always go together, and it's probably most sensible
370+ * that PTE_CD implies PTE_A and PTE_D. So, sensible values for this constant
371+ * are 0, (PTE_A | PTE_D), or (PTE_A | PTE_D | PTE_CD).
372+ */
373+ #define RISCV_PTE_TRAPPY 0
374+ #endif
375+
365376/* get_physical_address - get the physical address for this virtual address
366377 *
367378 * Do a page table walk to obtain the physical address corresponding to a
@@ -618,6 +629,28 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
618629 } else if (access_type == MMU_DATA_CAP_STORE && !(pte & PTE_CW )) {
619630 /* CW inhibited */
620631 return TRANSLATE_CHERI_FAIL ;
632+ #endif
633+ #if RISCV_PTE_TRAPPY & PTE_A
634+ } else if (!(pte & PTE_A )) {
635+ /* PTE not marked as accessed */
636+ return TRANSLATE_FAIL ;
637+ #endif
638+ #if RISCV_PTE_TRAPPY & PTE_D
639+ } else if ((access_type == MMU_DATA_STORE ) && !(pte & PTE_D )) {
640+ /* PTE not marked as dirty */
641+ return TRANSLATE_FAIL ;
642+ #endif
643+ #if defined(TARGET_CHERI ) && !defined(TARGET_RISCV32 )
644+ #if RISCV_PTE_TRAPPY & PTE_D
645+ } else if (access_type == MMU_DATA_CAP_STORE && !(pte & PTE_D )) {
646+ /* PTE not marked as dirty for cap store */
647+ return TRANSLATE_FAIL ;
648+ #endif
649+ #if RISCV_PTE_TRAPPY & PTE_CD
650+ } else if (access_type == MMU_DATA_CAP_STORE && !(pte & PTE_CD )) {
651+ /* CD clear; force the software trap handler to get involved */
652+ return TRANSLATE_CHERI_FAIL ;
653+ #endif
621654#endif
622655 } else {
623656 /* if necessary, set accessed and dirty bits. */
0 commit comments