8ebee60f43972f1e3a8ae669c2aa2dab206d87eb
1 // See LICENSE for license details.
7 #define LEVELS(xlen) ((xlen) == 32 ? 2 : 3)
8 #define PPN_SHIFT(xlen) ((xlen) == 32 ? 10 : 26)
9 #define PTIDXBITS(xlen) ((xlen) == 32 ? 10 : 9)
10 #define VPN_BITS(xlen) (PTIDXBITS(xlen) * LEVELS(xlen))
11 #define VA_BITS(xlen) (VPN_BITS(xlen) + PGSHIFT)
13 mmu_t::mmu_t(char* _mem
, size_t _memsz
)
14 : mem(_mem
), memsz(_memsz
), proc(NULL
)
23 void mmu_t::flush_icache()
25 for (size_t i
= 0; i
< ICACHE_ENTRIES
; i
++)
29 void mmu_t::flush_tlb()
31 memset(tlb_insn_tag
, -1, sizeof(tlb_insn_tag
));
32 memset(tlb_load_tag
, -1, sizeof(tlb_load_tag
));
33 memset(tlb_store_tag
, -1, sizeof(tlb_store_tag
));
38 void* mmu_t::refill_tlb(reg_t addr
, reg_t bytes
, bool store
, bool fetch
)
40 reg_t idx
= (addr
>> PGSHIFT
) % TLB_ENTRIES
;
41 reg_t expected_tag
= addr
>> PGSHIFT
;
43 reg_t mstatus
= proc
? proc
->state
.mstatus
: 0;
45 bool vm_disabled
= get_field(mstatus
, MSTATUS_VM
) == VM_MBARE
;
46 bool mode_m
= get_field(mstatus
, MSTATUS_PRV
) == PRV_M
;
47 bool mode_s
= get_field(mstatus
, MSTATUS_PRV
) == PRV_S
;
48 bool mprv_m
= get_field(mstatus
, MSTATUS_MPRV
) == PRV_M
;
49 bool mprv_s
= get_field(mstatus
, MSTATUS_MPRV
) == PRV_S
;
52 if (vm_disabled
|| (mode_m
&& (mprv_m
|| fetch
))) {
53 pgbase
= addr
& -PGSIZE
;
54 // virtual memory is disabled. merely check legality of physical address.
58 pgbase
= walk(addr
, mode_s
|| (mode_m
&& mprv_s
), store
, fetch
);
61 reg_t pgoff
= addr
& (PGSIZE
-1);
62 reg_t paddr
= pgbase
+ pgoff
;
64 if (pgbase
== reg_t(-1)) {
65 if (fetch
) throw trap_instruction_access_fault(addr
);
66 else if (store
) throw trap_store_access_fault(addr
);
67 else throw trap_load_access_fault(addr
);
70 bool trace
= tracer
.interested_in_range(pgbase
, pgbase
+ PGSIZE
, store
, fetch
);
71 if (unlikely(!fetch
&& trace
))
72 tracer
.trace(paddr
, bytes
, store
, fetch
);
75 if (tlb_load_tag
[idx
] != expected_tag
) tlb_load_tag
[idx
] = -1;
76 if (tlb_store_tag
[idx
] != expected_tag
) tlb_store_tag
[idx
] = -1;
77 if (tlb_insn_tag
[idx
] != expected_tag
) tlb_insn_tag
[idx
] = -1;
79 if (fetch
) tlb_insn_tag
[idx
] = expected_tag
;
80 else if (store
) tlb_store_tag
[idx
] = expected_tag
;
81 else tlb_load_tag
[idx
] = expected_tag
;
83 tlb_data
[idx
] = mem
+ pgbase
- (addr
& ~(PGSIZE
-1));
89 reg_t
mmu_t::walk(reg_t addr
, bool supervisor
, bool store
, bool fetch
)
91 reg_t msb_mask
= -(reg_t(1) << (VA_BITS(proc
->xlen
) - 1));
92 if ((addr
& msb_mask
) != 0 && (addr
& msb_mask
) != msb_mask
)
93 return -1; // address isn't properly sign-extended
95 reg_t base
= proc
->get_state()->sptbr
;
97 int xlen
= proc
->max_xlen
;
98 int ptshift
= (LEVELS(xlen
) - 1) * PTIDXBITS(xlen
);
99 for (reg_t i
= 0; i
< LEVELS(xlen
); i
++, ptshift
-= PTIDXBITS(xlen
)) {
100 reg_t idx
= (addr
>> (PGSHIFT
+ptshift
)) & ((1<<PTIDXBITS(xlen
))-1);
102 // check that physical address of PTE is legal
103 reg_t pte_addr
= base
+ idx
*sizeof(reg_t
);
104 if (pte_addr
>= memsz
)
107 reg_t
* ppte
= (reg_t
*)(mem
+pte_addr
);
108 reg_t ppn
= *ppte
>> PPN_SHIFT(xlen
);
110 if ((*ppte
& PTE_TYPE
) == PTE_TYPE_TABLE
) { // next level of page table
111 base
= ppn
<< PGSHIFT
;
113 // we've found the PTE. check the permissions.
114 if (!PTE_CHECK_PERM(*ppte
, supervisor
, store
, fetch
))
116 // set referenced and possibly dirty bits.
120 // for superpage mappings, make a fake leaf PTE for the TLB's benefit.
121 reg_t vpn
= addr
>> PGSHIFT
;
122 reg_t addr
= (ppn
| (vpn
& ((reg_t(1) << ptshift
) - 1))) << PGSHIFT
;
124 // check that physical address is legal
135 void mmu_t::register_memtracer(memtracer_t
* t
)