Don't set dirty/referenced bits w/o permission
authorAndrew Waterman <waterman@cs.berkeley.edu>
Sat, 14 Mar 2015 09:05:15 +0000 (02:05 -0700)
committerAndrew Waterman <waterman@cs.berkeley.edu>
Sat, 14 Mar 2015 09:05:15 +0000 (02:05 -0700)
riscv/mmu.cc
riscv/mmu.h

index 9bbb4e47b9525f934da5d4071e7b391c0ce94fad..001c414de62a7674046345e53268a8e2e78032b4 100644 (file)
@@ -43,6 +43,10 @@ void* mmu_t::refill_tlb(reg_t addr, reg_t bytes, bool store, bool fetch)
   bool mprv_m = get_field(mstatus, MSTATUS_MPRV) == PRV_M;
   bool mprv_s = get_field(mstatus, MSTATUS_MPRV) == PRV_S;
 
+  reg_t want_perm = store  ? (mode_s || (mode_m && mprv_s) ? PTE_SW : PTE_UW) :
+                    !fetch ? (mode_s || (mode_m && mprv_s) ? PTE_SR : PTE_UR) :
+                    (mode_s ? PTE_SX : PTE_UX);
+
   if (vm_disabled || (mode_m && (mprv_m || fetch))) {
     // virtual memory is disabled.  merely check legality of physical address.
     if (addr < memsz) {
@@ -52,17 +56,10 @@ void* mmu_t::refill_tlb(reg_t addr, reg_t bytes, bool store, bool fetch)
         pte |= PTE_UR | PTE_SR | PTE_UW | PTE_SW;
     }
   } else {
-    pte = walk(addr, store);
+    pte = walk(addr, want_perm);
   }
 
-  reg_t pte_perm = pte & PTE_PERM;
-  if (mode_s || (mode_m && mprv_s && !fetch))
-    pte_perm = (pte_perm/(PTE_SX/PTE_UX)) & PTE_PERM;
-  pte_perm |= pte & PTE_V;
-
-  reg_t perm = (fetch ? PTE_UX : store ? PTE_UW : PTE_UR) | PTE_V;
-  if(unlikely((pte_perm & perm) != perm))
-  {
+  if (!(pte & PTE_V) || !(pte & want_perm)) {
     if (fetch)
       throw trap_instruction_access_fault(addr);
     if (store)
@@ -78,16 +75,16 @@ void* mmu_t::refill_tlb(reg_t addr, reg_t bytes, bool store, bool fetch)
     tracer.trace(paddr, bytes, store, fetch);
   else
   {
-    tlb_load_tag[idx] = (pte_perm & PTE_UR) ? expected_tag : -1;
-    tlb_store_tag[idx] = (pte_perm & PTE_UW) && store ? expected_tag : -1;
-    tlb_insn_tag[idx] = (pte_perm & PTE_UX) ? expected_tag : -1;
+    tlb_load_tag[idx] = (pte & (PTE_UR|PTE_SR)) ? expected_tag : -1;
+    tlb_store_tag[idx] = (pte & (PTE_UW|PTE_SW)) && store ? expected_tag : -1;
+    tlb_insn_tag[idx] = (pte & (PTE_UX|PTE_SX)) ? expected_tag : -1;
     tlb_data[idx] = mem + pgbase - (addr & ~(PGSIZE-1));
   }
 
   return mem + paddr;
 }
 
-pte_t mmu_t::walk(reg_t addr, bool store)
+pte_t mmu_t::walk(reg_t addr, reg_t perm)
 {
   reg_t msb_mask = -(reg_t(1) << (VA_BITS-1));
   if ((addr & msb_mask) != 0 && (addr & msb_mask) != msb_mask)
@@ -112,7 +109,11 @@ pte_t mmu_t::walk(reg_t addr, bool store)
       base = (*ppte >> PGSHIFT) << PGSHIFT;
     } else {
       // we've found the PTE.  set referenced and possibly dirty bits.
-      *ppte |= PTE_R | (store ? PTE_D : 0);
+      if (*ppte & perm) {
+        *ppte |= PTE_R;
+        if (perm & (PTE_SW | PTE_UW))
+          *ppte |= PTE_D;
+      }
       // for superpage mappings, make a fake leaf PTE for the TLB's benefit.
       reg_t vpn = addr >> PGSHIFT;
       reg_t pte = *ppte | ((vpn & ((1<<(ptshift))-1)) << PGSHIFT);
index 0803d0f0bc3f69ce1b74ec07c5b5ba1e659aa8f4..8f1635dafeed9d5cf1b73f278322bbb13b30b4ef 100644 (file)
@@ -155,7 +155,7 @@ private:
   void* refill_tlb(reg_t addr, reg_t bytes, bool store, bool fetch);
 
   // perform a page table walk for a given VA; set referenced/dirty bits
-  pte_t walk(reg_t addr, bool store);
+  pte_t walk(reg_t addr, reg_t perm);
 
   // translate a virtual address to a physical address
   void* translate(reg_t addr, reg_t bytes, bool store, bool fetch)