Update to new PTE format
[riscv-isa-sim.git] / riscv / mmu.cc
index eb8fed5d42f4e87670ab3c74b335d242329c6b0c..602b09010399899a79c2db74248d310a5fe51e8b 100644 (file)
@@ -35,11 +35,9 @@ reg_t mmu_t::translate(reg_t addr, access_type type)
     return addr;
 
   reg_t mode = proc->state.prv;
-  bool pum = false;
   if (type != FETCH) {
     if (!proc->state.dcsr.cause && get_field(proc->state.mstatus, MSTATUS_MPRV))
       mode = get_field(proc->state.mstatus, MSTATUS_MPP);
-    pum = (mode == PRV_S && get_field(proc->state.mstatus, MSTATUS_PUM));
   }
   if (get_field(proc->state.mstatus, MSTATUS_VM) == VM_MBARE)
     mode = PRV_M;
@@ -48,7 +46,7 @@ reg_t mmu_t::translate(reg_t addr, access_type type)
     reg_t msb_mask = (reg_t(2) << (proc->xlen-1))-1; // zero-extend from xlen
     return addr & msb_mask;
   }
-  return walk(addr, type, mode > PRV_U, pum) | (addr & (PGSIZE-1));
+  return walk(addr, type, mode) | (addr & (PGSIZE-1));
 }
 
 const uint16_t* mmu_t::fetch_slow_path(reg_t vaddr)
@@ -115,7 +113,7 @@ void mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, access_type type)
   tlb_data[idx] = sim->addr_to_mem(paddr) - vaddr;
 }
 
-reg_t mmu_t::walk(reg_t addr, access_type type, bool supervisor, bool pum)
+reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode)
 {
   int levels, ptidxbits, ptesize;
   switch (get_field(proc->get_state()->mstatus, MSTATUS_VM))
@@ -126,6 +124,10 @@ reg_t mmu_t::walk(reg_t addr, access_type type, bool supervisor, bool pum)
     default: abort();
   }
 
+  bool supervisor = mode == PRV_S;
+  bool pum = get_field(proc->state.mstatus, MSTATUS_PUM);
+  bool mxr = get_field(proc->state.mstatus, MSTATUS_MXR);
+
   // verify bits xlen-1:va_bits-1 are all equal
   int va_bits = PGSHIFT + levels * ptidxbits;
   reg_t mask = (reg_t(1) << (proc->xlen - (va_bits-1))) - 1;
@@ -149,13 +151,17 @@ reg_t mmu_t::walk(reg_t addr, access_type type, bool supervisor, bool pum)
 
     if (PTE_TABLE(pte)) { // next level of page table
       base = ppn << PGSHIFT;
-    } else if (pum && PTE_CHECK_PERM(pte, 0, type == STORE, type == FETCH)) {
+    } else if ((pte & PTE_U) ? supervisor && pum : !supervisor) {
+      break;
+    } else if (!(pte & PTE_R) && (pte & PTE_W)) { // reserved
       break;
-    } else if (!PTE_CHECK_PERM(pte, supervisor, type == STORE, type == FETCH)) {
+    } else if (type == FETCH ? !(pte & PTE_X) :
+               type == LOAD ?  !(pte & PTE_R) && !(mxr && (pte & PTE_X)) :
+                               !((pte & PTE_R) && (pte & PTE_W))) {
       break;
     } else {
-      // set referenced and possibly dirty bits.
-      *(uint32_t*)ppte |= PTE_R | ((type == STORE) * PTE_D);
+      // set accessed and possibly dirty bits.
+      *(uint32_t*)ppte |= PTE_A | ((type == STORE) * PTE_D);
       // for superpage mappings, make a fake leaf PTE for the TLB's benefit.
       reg_t vpn = addr >> PGSHIFT;
       reg_t value = (ppn | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT;