aboutsummaryrefslogtreecommitdiff
path: root/riscv/mmu.cc
diff options
context:
space:
mode:
authorAndrew Waterman <waterman@cs.berkeley.edu>2015-03-14 02:05:15 -0700
committerAndrew Waterman <waterman@cs.berkeley.edu>2015-03-14 02:05:15 -0700
commit93892690a3127e1a895bb95c3952cee0b0b120e8 (patch)
tree733fe91c4f3c7da8ce6414fc0935d35c304d76c7 /riscv/mmu.cc
parent384e03dde463d77f2e032ef6ab56e0b4b8be5e65 (diff)
downloadspike-93892690a3127e1a895bb95c3952cee0b0b120e8.zip
spike-93892690a3127e1a895bb95c3952cee0b0b120e8.tar.gz
spike-93892690a3127e1a895bb95c3952cee0b0b120e8.tar.bz2
Don't set dirty/referenced bits w/o permission
Diffstat (limited to 'riscv/mmu.cc')
-rw-r--r--riscv/mmu.cc29
1 files changed, 15 insertions, 14 deletions
diff --git a/riscv/mmu.cc b/riscv/mmu.cc
index 9bbb4e4..001c414 100644
--- a/riscv/mmu.cc
+++ b/riscv/mmu.cc
@@ -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);