diff options
author | Andrew Waterman <waterman@s141.Millennium.Berkeley.EDU> | 2011-05-31 19:23:03 -0700 |
---|---|---|
committer | Andrew Waterman <waterman@s141.Millennium.Berkeley.EDU> | 2011-05-31 19:23:03 -0700 |
commit | f1bb8270a16a5bb24e674d48dfb0b86e42a6ed92 (patch) | |
tree | da55d8f3eade6b1e65f34d51265b7e2a8be94d55 /riscv/mmu.h | |
parent | 2641a9b24f176ca3edf83c471276fdc8f1d0ea86 (diff) | |
download | spike-f1bb8270a16a5bb24e674d48dfb0b86e42a6ed92.zip spike-f1bb8270a16a5bb24e674d48dfb0b86e42a6ed92.tar.gz spike-f1bb8270a16a5bb24e674d48dfb0b86e42a6ed92.tar.bz2 |
[sim] fault on failed addr translations
previously, a bad PTE would segfault the simulator, rather than sending
the fault to the OS.
Diffstat (limited to 'riscv/mmu.h')
-rw-r--r-- | riscv/mmu.h | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/riscv/mmu.h b/riscv/mmu.h index 21b493e..6033e98 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -49,7 +49,10 @@ public: #define load_func(type) \ type##_t load_##type(reg_t addr) { \ if(unlikely(addr % sizeof(type##_t))) \ + { \ + badvaddr = addr; \ throw trap_load_address_misaligned; \ + } \ addr = translate(addr, false, false); \ dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), false); \ return *(type##_t*)(mem+addr); \ @@ -58,7 +61,10 @@ public: #define store_func(type) \ void store_##type(reg_t addr, type##_t val) { \ if(unlikely(addr % sizeof(type##_t))) \ + { \ + badvaddr = addr; \ throw trap_store_address_misaligned; \ + } \ addr = translate(addr, true, false); \ dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), true); \ *(type##_t*)(mem+addr) = val; \ @@ -89,7 +95,10 @@ public: #endif { if(unlikely(addr % 4)) + { + badvaddr = addr; throw trap_instruction_address_misaligned; + } reg_t paddr = translate(addr, false, true); insn = *(insn_t*)(mem+paddr); @@ -174,7 +183,10 @@ private: { pte = walk(addr); if(!(pte & PTE_E)) + { + badvaddr = addr; throw trap; + } tlb_data[idx] = pte; tlb_tag[idx] = addr >> PGSHIFT; @@ -184,7 +196,10 @@ private: if(supervisor) access_type <<= 3; if(unlikely(!(access_type & pte & PTE_PERM))) + { + badvaddr = addr; throw trap; + } return (addr & (PGSIZE-1)) | ((pte >> PTE_PPN_SHIFT) << PGSHIFT); } @@ -218,7 +233,12 @@ private: // if this PTE is from a larger PT, fake a leaf // PTE so the TLB will work right reg_t vpn = addr >> PGSHIFT; - pte |= ptd | (vpn & ((1<<(ptshift))-1)) << PTE_PPN_SHIFT; + ptd |= (vpn & ((1<<(ptshift))-1)) << PTE_PPN_SHIFT; + + // fault if physical addr is invalid + reg_t ppn = ptd >> PTE_PPN_SHIFT; + if((ppn << PGSHIFT) + (addr & (PGSIZE-1)) < memsz) + pte = ptd; break; } else if(!(ptd & PTE_T)) |