diff options
author | Andrew Waterman <waterman@cs.berkeley.edu> | 2015-03-14 02:05:15 -0700 |
---|---|---|
committer | Andrew Waterman <waterman@cs.berkeley.edu> | 2015-03-14 02:05:15 -0700 |
commit | 93892690a3127e1a895bb95c3952cee0b0b120e8 (patch) | |
tree | 733fe91c4f3c7da8ce6414fc0935d35c304d76c7 /riscv | |
parent | 384e03dde463d77f2e032ef6ab56e0b4b8be5e65 (diff) | |
download | spike-93892690a3127e1a895bb95c3952cee0b0b120e8.zip spike-93892690a3127e1a895bb95c3952cee0b0b120e8.tar.gz spike-93892690a3127e1a895bb95c3952cee0b0b120e8.tar.bz2 |
Don't set dirty/referenced bits w/o permission
Diffstat (limited to 'riscv')
-rw-r--r-- | riscv/mmu.cc | 29 | ||||
-rw-r--r-- | riscv/mmu.h | 2 |
2 files changed, 16 insertions, 15 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); diff --git a/riscv/mmu.h b/riscv/mmu.h index 0803d0f..8f1635d 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -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) |