5 mmu_t::mmu_t(char* _mem
, size_t _memsz
)
6 : mem(_mem
), memsz(_memsz
), badvaddr(0),
7 ptbr(0), supervisor(true), vm_enabled(false)
16 void mmu_t::flush_tlb()
18 memset(tlb_insn_tag
, -1, sizeof(tlb_insn_tag
));
19 memset(tlb_load_tag
, -1, sizeof(tlb_load_tag
));
20 memset(tlb_store_tag
, -1, sizeof(tlb_store_tag
));
25 void mmu_t::flush_icache()
27 memset(icache_tag
, -1, sizeof(icache_tag
));
30 void* mmu_t::refill(reg_t addr
, bool store
, bool fetch
)
32 reg_t idx
= (addr
>> PGSHIFT
) % TLB_ENTRIES
;
33 reg_t expected_tag
= addr
& ~(PGSIZE
-1);
35 reg_t pte
= walk(addr
);
37 reg_t pte_perm
= pte
& PTE_PERM
;
38 if(supervisor
) // shift supervisor permission bits into user perm bits
39 pte_perm
= (pte_perm
/(PTE_SX
/PTE_UX
)) & PTE_PERM
;
40 pte_perm
|= pte
& PTE_E
;
42 reg_t perm
= (fetch
? PTE_UX
: store
? PTE_UW
: PTE_UR
) | PTE_E
;
43 if(unlikely((pte_perm
& perm
) != perm
))
46 throw store
? trap_store_access_fault
47 : fetch
? trap_instruction_access_fault
48 : trap_load_access_fault
;
51 tlb_load_tag
[idx
] = (pte_perm
& PTE_UR
) ? expected_tag
: -1;
52 tlb_store_tag
[idx
] = (pte_perm
& PTE_UW
) ? expected_tag
: -1;
53 tlb_insn_tag
[idx
] = (pte_perm
& PTE_UX
) ? expected_tag
: -1;
54 tlb_data
[idx
] = (long)(pte
>> PTE_PPN_SHIFT
<< PGSHIFT
) + (long)mem
;
56 return (void*)(((long)addr
& (PGSIZE
-1)) + tlb_data
[idx
]);
59 pte_t
mmu_t::walk(reg_t addr
)
63 // the address must be a canonical sign-extended VA_BITS-bit number
64 int shift
= 8*sizeof(reg_t
) - VA_BITS
;
65 if (((sreg_t
)addr
<< shift
>> shift
) != addr
)
70 pte
= PTE_E
| PTE_PERM
| ((addr
>> PGSHIFT
) << PTE_PPN_SHIFT
);
77 int ptshift
= (LEVELS
-1)*PTIDXBITS
;
78 for(reg_t i
= 0; i
< LEVELS
; i
++, ptshift
-= PTIDXBITS
)
80 reg_t idx
= (addr
>> (PGSHIFT
+ptshift
)) & ((1<<PTIDXBITS
)-1);
82 reg_t pte_addr
= base
+ idx
*sizeof(pte_t
);
86 ptd
= *(pte_t
*)(mem
+pte_addr
);
89 // if this PTE is from a larger PT, fake a leaf
90 // PTE so the TLB will work right
91 reg_t vpn
= addr
>> PGSHIFT
;
92 ptd
|= (vpn
& ((1<<(ptshift
))-1)) << PTE_PPN_SHIFT
;
94 // fault if physical addr is invalid
95 reg_t ppn
= ptd
>> PTE_PPN_SHIFT
;
96 if((ppn
<< PGSHIFT
) + (addr
& (PGSIZE
-1)) < memsz
)
100 else if(!(ptd
& PTE_T
))
103 base
= (ptd
>> PTE_PPN_SHIFT
) << PGSHIFT
;