aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--riscv/encoding.h2
-rw-r--r--riscv/mmu.cc24
-rw-r--r--riscv/mmu.h4
3 files changed, 16 insertions, 14 deletions
diff --git a/riscv/encoding.h b/riscv/encoding.h
index 4b929d3..25091cf 100644
--- a/riscv/encoding.h
+++ b/riscv/encoding.h
@@ -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
diff --git a/riscv/mmu.cc b/riscv/mmu.cc
index 779383d..9bbb4e4 100644
--- a/riscv/mmu.cc
+++ b/riscv/mmu.cc
@@ -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;
diff --git a/riscv/mmu.h b/riscv/mmu.h
index 329f291..0803d0f 100644
--- a/riscv/mmu.h
+++ b/riscv/mmu.h
@@ -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)