1 // See LICENSE for license details.
7 mmu_t::mmu_t(char* _mem
, size_t _memsz
)
8 : mem(_mem
), memsz(_memsz
), proc(NULL
)
17 void mmu_t::flush_icache()
19 for (size_t i
= 0; i
< ICACHE_ENTRIES
; i
++)
23 void mmu_t::flush_tlb()
25 memset(tlb_insn_tag
, -1, sizeof(tlb_insn_tag
));
26 memset(tlb_load_tag
, -1, sizeof(tlb_load_tag
));
27 memset(tlb_store_tag
, -1, sizeof(tlb_store_tag
));
32 void* mmu_t::refill_tlb(reg_t addr
, reg_t bytes
, bool store
, bool fetch
)
34 reg_t idx
= (addr
>> PGSHIFT
) % TLB_ENTRIES
;
35 reg_t expected_tag
= addr
>> PGSHIFT
;
37 reg_t pte
= walk(addr
);
39 reg_t pte_perm
= pte
& PTE_PERM
;
40 if (proc
== NULL
|| (proc
->state
.sr
& SR_S
))
41 pte_perm
= (pte_perm
/(PTE_SX
/PTE_UX
)) & PTE_PERM
;
42 pte_perm
|= pte
& PTE_V
;
44 reg_t perm
= (fetch
? PTE_UX
: store
? PTE_UW
: PTE_UR
) | PTE_V
;
45 if(unlikely((pte_perm
& perm
) != perm
))
48 throw trap_instruction_access_fault(addr
);
50 throw trap_store_access_fault(addr
);
51 throw trap_load_access_fault(addr
);
54 reg_t pgoff
= addr
& (PGSIZE
-1);
55 reg_t pgbase
= pte
>> PGSHIFT
<< PGSHIFT
;
56 reg_t paddr
= pgbase
+ pgoff
;
58 if (unlikely(tracer
.interested_in_range(pgbase
, pgbase
+ PGSIZE
, store
, fetch
)))
59 tracer
.trace(paddr
, bytes
, store
, fetch
);
62 tlb_load_tag
[idx
] = (pte_perm
& PTE_UR
) ? expected_tag
: -1;
63 tlb_store_tag
[idx
] = (pte_perm
& PTE_UW
) ? expected_tag
: -1;
64 tlb_insn_tag
[idx
] = (pte_perm
& PTE_UX
) ? expected_tag
: -1;
65 tlb_data
[idx
] = mem
+ pgbase
- (addr
& ~(PGSIZE
-1));
71 pte_t
mmu_t::walk(reg_t addr
)
75 // the address must be a canonical sign-extended VA_BITS-bit number
76 int shift
= 8*sizeof(reg_t
) - VA_BITS
;
77 if (((sreg_t
)addr
<< shift
>> shift
) != (sreg_t
)addr
)
79 else if (proc
== NULL
|| !(proc
->state
.sr
& SR_VM
))
82 pte
= PTE_V
| PTE_PERM
| ((addr
>> PGSHIFT
) << PGSHIFT
);
86 reg_t base
= proc
->get_state()->ptbr
;
89 int ptshift
= (LEVELS
-1)*PTIDXBITS
;
90 for(reg_t i
= 0; i
< LEVELS
; i
++, ptshift
-= PTIDXBITS
)
92 reg_t idx
= (addr
>> (PGSHIFT
+ptshift
)) & ((1<<PTIDXBITS
)-1);
94 reg_t pte_addr
= base
+ idx
*sizeof(pte_t
);
98 ptd
= *(pte_t
*)(mem
+pte_addr
);
100 if (!(ptd
& PTE_V
)) // invalid mapping
102 else if (ptd
& PTE_T
) // next level of page table
103 base
= (ptd
>> PGSHIFT
) << PGSHIFT
;
104 else // the actual PTE
106 // if this PTE is from a larger PT, fake a leaf
107 // PTE so the TLB will work right
108 reg_t vpn
= addr
>> PGSHIFT
;
109 ptd
|= (vpn
& ((1<<(ptshift
))-1)) << PGSHIFT
;
111 // fault if physical addr is out of range
112 if (((ptd
>> PGSHIFT
) << PGSHIFT
) < memsz
)
122 void mmu_t::register_memtracer(memtracer_t
* t
)