Implement PTE referenced/dirty bits
authorAndrew Waterman <waterman@cs.berkeley.edu>
Fri, 13 Mar 2015 03:00:09 +0000 (20:00 -0700)
committerAndrew Waterman <waterman@cs.berkeley.edu>
Fri, 13 Mar 2015 03:00:09 +0000 (20:00 -0700)
riscv/encoding.h
riscv/mmu.cc
riscv/mmu.h

index 4b929d395e81c1ddfd150a2606faa826e42743d6..25091cf64c40f7f04ae4b85ec810d05b01b5df7d 100644 (file)
@@ -72,6 +72,8 @@
 #define PTE_SR   0x040 // Supervisor Read permission
 #define PTE_SW   0x080 // Supervisor Write permission
 #define PTE_SX   0x100 // Supervisor eXecute permission
+#define PTE_R    0x200 // Referenced
+#define PTE_D    0x400 // Dirty
 #define PTE_PERM (PTE_SR | PTE_SW | PTE_SX | PTE_UR | PTE_UW | PTE_UX)
 
 #ifdef __riscv
index 779383db1bcbba1701a2d978eb4eefca901c9cda..9bbb4e47b9525f934da5d4071e7b391c0ce94fad 100644 (file)
@@ -52,7 +52,7 @@ 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);
+    pte = walk(addr, store);
   }
 
   reg_t pte_perm = pte & PTE_PERM;
@@ -79,7 +79,7 @@ void* mmu_t::refill_tlb(reg_t addr, reg_t bytes, bool store, bool fetch)
   else
   {
     tlb_load_tag[idx] = (pte_perm & PTE_UR) ? expected_tag : -1;
-    tlb_store_tag[idx] = (pte_perm & PTE_UW) ? 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_data[idx] = mem + pgbase - (addr & ~(PGSIZE-1));
   }
@@ -87,14 +87,13 @@ void* mmu_t::refill_tlb(reg_t addr, reg_t bytes, bool store, bool fetch)
   return mem + paddr;
 }
 
-pte_t mmu_t::walk(reg_t addr)
+pte_t mmu_t::walk(reg_t addr, bool store)
 {
   reg_t msb_mask = -(reg_t(1) << (VA_BITS-1));
   if ((addr & msb_mask) != 0 && (addr & msb_mask) != msb_mask)
     return 0; // address isn't properly sign-extended
 
   reg_t base = proc->get_state()->sptbr;
-  reg_t ptd;
 
   int ptshift = (LEVELS-1)*PTIDXBITS;
   for (reg_t i = 0; i < LEVELS; i++, ptshift -= PTIDXBITS) {
@@ -105,23 +104,24 @@ pte_t mmu_t::walk(reg_t addr)
     if (pte_addr >= memsz)
       return 0;
 
-    ptd = *(pte_t*)(mem+pte_addr);
+    pte_t* ppte = (pte_t*)(mem+pte_addr);
 
-    if (!(ptd & PTE_V)) { // invalid mapping
+    if (!(*ppte & PTE_V)) { // invalid mapping
       return 0;
-    } else if (ptd & PTE_T) { // next level of page table
-      base = (ptd >> PGSHIFT) << PGSHIFT;
+    } else if (*ppte & PTE_T) { // next level of page table
+      base = (*ppte >> PGSHIFT) << PGSHIFT;
     } else {
-      // we've found the PTE.
+      // we've found the PTE.  set referenced and possibly dirty bits.
+      *ppte |= PTE_R | (store ? PTE_D : 0);
       // for superpage mappings, make a fake leaf PTE for the TLB's benefit.
       reg_t vpn = addr >> PGSHIFT;
-      ptd |= (vpn & ((1<<(ptshift))-1)) << PGSHIFT;
+      reg_t pte = *ppte | ((vpn & ((1<<(ptshift))-1)) << PGSHIFT);
 
       // check that physical address is legal
-      if (((ptd >> PGSHIFT) << PGSHIFT) >= memsz)
+      if (((pte >> PGSHIFT) << PGSHIFT) >= memsz)
         return 0;
 
-      return ptd;
+      return pte;
     }
   }
   return 0;
index 329f29140ec485212c0f5d81c4bb226dec7d26e2..0803d0f0bc3f69ce1b74ec07c5b5ba1e659aa8f4 100644 (file)
@@ -154,8 +154,8 @@ private:
   // finish translation on a TLB miss and upate the TLB
   void* refill_tlb(reg_t addr, reg_t bytes, bool store, bool fetch);
 
-  // perform a page table walk for a given virtual address
-  pte_t walk(reg_t addr);
+  // perform a page table walk for a given VA; set referenced/dirty bits
+  pte_t walk(reg_t addr, bool store);
 
   // translate a virtual address to a physical address
   void* translate(reg_t addr, reg_t bytes, bool store, bool fetch)