55#include " arith.h"
66#include " simif.h"
77#include " processor.h"
8+ #include " decode_macros.h"
89
910mmu_t ::mmu_t (simif_t * sim, endianness_t endianness, processor_t * proc)
1011 : sim(sim), proc(proc),
@@ -54,7 +55,7 @@ void throw_access_exception(bool virt, reg_t addr, access_type type)
5455
5556reg_t mmu_t::translate (mem_access_info_t access_info, reg_t len)
5657{
57- reg_t addr = access_info.vaddr ;
58+ reg_t addr = access_info.transformed_vaddr ;
5859 access_type type = access_info.type ;
5960 if (!proc)
6061 return addr;
@@ -192,17 +193,18 @@ void mmu_t::check_triggers(triggers::operation_t operation, reg_t address, bool
192193void mmu_t::load_slow_path_intrapage (reg_t len, uint8_t * bytes, mem_access_info_t access_info)
193194{
194195 reg_t addr = access_info.vaddr ;
195- reg_t vpn = addr >> PGSHIFT;
196+ reg_t transformed_addr = access_info.transformed_vaddr ;
197+ reg_t vpn = transformed_addr >> PGSHIFT;
196198 if (!access_info.flags .is_special_access () && vpn == (tlb_load_tag[vpn % TLB_ENTRIES] & ~TLB_CHECK_TRIGGERS)) {
197- auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + addr ;
199+ auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + transformed_addr ;
198200 memcpy (bytes, host_addr, len);
199201 return ;
200202 }
201203
202204 reg_t paddr = translate (access_info, len);
203205
204206 if (access_info.flags .lr && !sim->reservable (paddr)) {
205- throw trap_load_access_fault (access_info.effective_virt , addr , 0 , 0 );
207+ throw trap_load_access_fault (access_info.effective_virt , transformed_addr , 0 , 0 );
206208 }
207209
208210 if (auto host_addr = sim->addr_to_mem (paddr)) {
@@ -213,50 +215,52 @@ void mmu_t::load_slow_path_intrapage(reg_t len, uint8_t* bytes, mem_access_info_
213215 refill_tlb (addr, paddr, host_addr, LOAD);
214216
215217 } else if (!mmio_load (paddr, len, bytes)) {
216- throw trap_load_access_fault (access_info.effective_virt , addr , 0 , 0 );
218+ throw trap_load_access_fault (access_info.effective_virt , transformed_addr , 0 , 0 );
217219 }
218220
219221 if (access_info.flags .lr ) {
220222 load_reservation_address = paddr;
221223 }
222224}
223225
224- void mmu_t::load_slow_path (reg_t addr , reg_t len, uint8_t * bytes, xlate_flags_t xlate_flags)
226+ void mmu_t::load_slow_path (reg_t original_addr , reg_t len, uint8_t * bytes, xlate_flags_t xlate_flags)
225227{
226- auto access_info = generate_access_info (addr, LOAD, xlate_flags);
227- check_triggers (triggers::OPERATION_LOAD, addr, access_info.effective_virt );
228+ auto access_info = generate_access_info (original_addr, LOAD, xlate_flags);
229+ reg_t transformed_addr = access_info.transformed_vaddr ;
230+ check_triggers (triggers::OPERATION_LOAD, transformed_addr, access_info.effective_virt );
228231
229- if ((addr & (len - 1 )) == 0 ) {
232+ if ((transformed_addr & (len - 1 )) == 0 ) {
230233 load_slow_path_intrapage (len, bytes, access_info);
231234 } else {
232235 bool gva = access_info.effective_virt ;
233236 if (!is_misaligned_enabled ())
234- throw trap_load_address_misaligned (gva, addr , 0 , 0 );
237+ throw trap_load_address_misaligned (gva, transformed_addr , 0 , 0 );
235238
236239 if (access_info.flags .lr )
237- throw trap_load_access_fault (gva, addr , 0 , 0 );
240+ throw trap_load_access_fault (gva, transformed_addr , 0 , 0 );
238241
239- reg_t len_page0 = std::min (len, PGSIZE - addr % PGSIZE);
242+ reg_t len_page0 = std::min (len, PGSIZE - transformed_addr % PGSIZE);
240243 load_slow_path_intrapage (len_page0, bytes, access_info);
241244 if (len_page0 != len)
242245 load_slow_path_intrapage (len - len_page0, bytes + len_page0, access_info.split_misaligned_access (len_page0));
243246 }
244247
245248 while (len > sizeof (reg_t )) {
246- check_triggers (triggers::OPERATION_LOAD, addr , access_info.effective_virt , reg_from_bytes (sizeof (reg_t ), bytes));
249+ check_triggers (triggers::OPERATION_LOAD, transformed_addr , access_info.effective_virt , reg_from_bytes (sizeof (reg_t ), bytes));
247250 len -= sizeof (reg_t );
248251 bytes += sizeof (reg_t );
249252 }
250- check_triggers (triggers::OPERATION_LOAD, addr , access_info.effective_virt , reg_from_bytes (len, bytes));
253+ check_triggers (triggers::OPERATION_LOAD, transformed_addr , access_info.effective_virt , reg_from_bytes (len, bytes));
251254}
252255
253256void mmu_t::store_slow_path_intrapage (reg_t len, const uint8_t * bytes, mem_access_info_t access_info, bool actually_store)
254257{
255258 reg_t addr = access_info.vaddr ;
256- reg_t vpn = addr >> PGSHIFT;
259+ reg_t transformed_addr = access_info.transformed_vaddr ;
260+ reg_t vpn = transformed_addr >> PGSHIFT;
257261 if (!access_info.flags .is_special_access () && vpn == (tlb_store_tag[vpn % TLB_ENTRIES] & ~TLB_CHECK_TRIGGERS)) {
258262 if (actually_store) {
259- auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + addr ;
263+ auto host_addr = tlb_data[vpn % TLB_ENTRIES].host_offset + transformed_addr ;
260264 memcpy (host_addr, bytes, len);
261265 }
262266 return ;
@@ -272,34 +276,35 @@ void mmu_t::store_slow_path_intrapage(reg_t len, const uint8_t* bytes, mem_acces
272276 else if (!access_info.flags .is_special_access ())
273277 refill_tlb (addr, paddr, host_addr, STORE);
274278 } else if (!mmio_store (paddr, len, bytes)) {
275- throw trap_store_access_fault (access_info.effective_virt , addr , 0 , 0 );
279+ throw trap_store_access_fault (access_info.effective_virt , transformed_addr , 0 , 0 );
276280 }
277281 }
278282}
279283
280- void mmu_t::store_slow_path (reg_t addr , reg_t len, const uint8_t * bytes, xlate_flags_t xlate_flags, bool actually_store, bool UNUSED require_alignment)
284+ void mmu_t::store_slow_path (reg_t original_addr , reg_t len, const uint8_t * bytes, xlate_flags_t xlate_flags, bool actually_store, bool UNUSED require_alignment)
281285{
282- auto access_info = generate_access_info (addr, STORE, xlate_flags);
286+ auto access_info = generate_access_info (original_addr, STORE, xlate_flags);
287+ reg_t transformed_addr = access_info.transformed_vaddr ;
283288 if (actually_store) {
284289 reg_t trig_len = len;
285290 const uint8_t * trig_bytes = bytes;
286291 while (trig_len > sizeof (reg_t )) {
287- check_triggers (triggers::OPERATION_STORE, addr , access_info.effective_virt , reg_from_bytes (sizeof (reg_t ), trig_bytes));
292+ check_triggers (triggers::OPERATION_STORE, transformed_addr , access_info.effective_virt , reg_from_bytes (sizeof (reg_t ), trig_bytes));
288293 trig_len -= sizeof (reg_t );
289294 trig_bytes += sizeof (reg_t );
290295 }
291- check_triggers (triggers::OPERATION_STORE, addr , access_info.effective_virt , reg_from_bytes (trig_len, trig_bytes));
296+ check_triggers (triggers::OPERATION_STORE, transformed_addr , access_info.effective_virt , reg_from_bytes (trig_len, trig_bytes));
292297 }
293298
294- if (addr & (len - 1 )) {
299+ if (transformed_addr & (len - 1 )) {
295300 bool gva = access_info.effective_virt ;
296301 if (!is_misaligned_enabled ())
297- throw trap_store_address_misaligned (gva, addr , 0 , 0 );
302+ throw trap_store_address_misaligned (gva, transformed_addr , 0 , 0 );
298303
299304 if (require_alignment)
300- throw trap_store_access_fault (gva, addr , 0 , 0 );
305+ throw trap_store_access_fault (gva, transformed_addr , 0 , 0 );
301306
302- reg_t len_page0 = std::min (len, PGSIZE - addr % PGSIZE);
307+ reg_t len_page0 = std::min (len, PGSIZE - transformed_addr % PGSIZE);
303308 store_slow_path_intrapage (len_page0, bytes, access_info, actually_store);
304309 if (len_page0 != len)
305310 store_slow_path_intrapage (len - len_page0, bytes + len_page0, access_info.split_misaligned_access (len_page0), actually_store);
@@ -484,7 +489,7 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty
484489reg_t mmu_t::walk (mem_access_info_t access_info)
485490{
486491 access_type type = access_info.type ;
487- reg_t addr = access_info.vaddr ;
492+ reg_t addr = access_info.transformed_vaddr ;
488493 bool virt = access_info.effective_virt ;
489494 bool hlvx = access_info.flags .hlvx ;
490495 reg_t mode = access_info.effective_priv ;
@@ -607,3 +612,51 @@ void mmu_t::register_memtracer(memtracer_t* t)
607612 flush_tlb ();
608613 tracer.hook (t);
609614}
615+
616+ reg_t mmu_t::get_pmlen (bool effective_virt, reg_t effective_priv, xlate_flags_t flags) const {
617+ if (!proc || proc->get_xlen () != 64 || (in_mprv () && (proc->state .sstatus ->read () & MSTATUS_MXR)) || flags.hlvx )
618+ return 0 ;
619+
620+ reg_t pmm = 0 ;
621+ if (effective_priv == PRV_M)
622+ pmm = get_field (proc->state .mseccfg ->read (), MSECCFG_PMM);
623+ else if (!effective_virt && (effective_priv == PRV_S || (!proc->extension_enabled (' S' ) && effective_priv == PRV_U)))
624+ pmm = get_field (proc->state .menvcfg ->read (), MENVCFG_PMM);
625+ else if (effective_virt && effective_priv == PRV_S)
626+ pmm = get_field (proc->state .henvcfg ->read (), HENVCFG_PMM);
627+ else if (proc->state .prv == PRV_U && flags.forced_virt )
628+ pmm = get_field (proc->state .hstatus ->read (), HSTATUS_HUPMM);
629+ else if (effective_priv == PRV_U)
630+ pmm = get_field (proc->state .senvcfg ->read (), SENVCFG_PMM);
631+ else
632+ assert (false );
633+
634+ switch (pmm) {
635+ case 2 : return 7 ;
636+ case 3 : return 16 ;
637+ }
638+ return 0 ;
639+ }
640+
641+ mem_access_info_t mmu_t::generate_access_info (reg_t addr, access_type type, xlate_flags_t xlate_flags) {
642+ if (!proc)
643+ return {addr, addr, 0 , false , {}, type};
644+ bool virt = proc->state .v ;
645+ reg_t mode = proc->state .prv ;
646+ if (type != FETCH) {
647+ if (in_mprv ()) {
648+ mode = get_field (proc->state .mstatus ->read (), MSTATUS_MPP);
649+ if (get_field (proc->state .mstatus ->read (), MSTATUS_MPV) && mode != PRV_M)
650+ virt = true ;
651+ }
652+ if (xlate_flags.forced_virt ) {
653+ virt = true ;
654+ mode = get_field (proc->state .hstatus ->read (), HSTATUS_SPVP);
655+ }
656+ }
657+ reg_t pmlen = get_pmlen (virt, mode, xlate_flags);
658+ reg_t satp = proc->state .satp ->readvirt (virt);
659+ bool is_physical_addr = mode == PRV_M || get_field (satp, SATP64_MODE) == SATP_MODE_OFF;
660+ reg_t transformed_addr = is_physical_addr ? zext (addr, 64 - pmlen) : sext (addr, 64 - pmlen);
661+ return {addr, transformed_addr, mode, virt, xlate_flags, type};
662+ }
0 commit comments