From: Andrew Waterman Date: Sat, 14 Mar 2015 09:05:15 +0000 (-0700) Subject: Don't set dirty/referenced bits w/o permission X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=93892690a3127e1a895bb95c3952cee0b0b120e8;p=riscv-isa-sim.git Don't set dirty/referenced bits w/o permission --- 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)