5
5
#include " arith.h"
6
6
#include " simif.h"
7
7
#include " processor.h"
8
+ #include " decode_macros.h"
8
9
9
10
mmu_t ::mmu_t (simif_t * sim, endianness_t endianness, processor_t * proc)
10
11
: sim(sim), proc(proc),
@@ -54,7 +55,7 @@ void throw_access_exception(bool virt, reg_t addr, access_type type)
54
55
55
56
reg_t mmu_t::translate (mem_access_info_t access_info, reg_t len)
56
57
{
57
- reg_t addr = access_info.vaddr ;
58
+ reg_t addr = access_info.transformed_vaddr ;
58
59
access_type type = access_info.type ;
59
60
if (!proc)
60
61
return addr;
@@ -192,17 +193,18 @@ void mmu_t::check_triggers(triggers::operation_t operation, reg_t address, bool
192
193
void mmu_t::load_slow_path_intrapage (reg_t len, uint8_t * bytes, mem_access_info_t access_info)
193
194
{
194
195
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;
196
198
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 ;
198
200
memcpy (bytes, host_addr, len);
199
201
return ;
200
202
}
201
203
202
204
reg_t paddr = translate (access_info, len);
203
205
204
206
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 );
206
208
}
207
209
208
210
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_
213
215
refill_tlb (addr, paddr, host_addr, LOAD);
214
216
215
217
} 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 );
217
219
}
218
220
219
221
if (access_info.flags .lr ) {
220
222
load_reservation_address = paddr;
221
223
}
222
224
}
223
225
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)
225
227
{
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 );
228
231
229
- if ((addr & (len - 1 )) == 0 ) {
232
+ if ((transformed_addr & (len - 1 )) == 0 ) {
230
233
load_slow_path_intrapage (len, bytes, access_info);
231
234
} else {
232
235
bool gva = access_info.effective_virt ;
233
236
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 );
235
238
236
239
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 );
238
241
239
- reg_t len_page0 = std::min (len, PGSIZE - addr % PGSIZE);
242
+ reg_t len_page0 = std::min (len, PGSIZE - transformed_addr % PGSIZE);
240
243
load_slow_path_intrapage (len_page0, bytes, access_info);
241
244
if (len_page0 != len)
242
245
load_slow_path_intrapage (len - len_page0, bytes + len_page0, access_info.split_misaligned_access (len_page0));
243
246
}
244
247
245
248
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));
247
250
len -= sizeof (reg_t );
248
251
bytes += sizeof (reg_t );
249
252
}
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));
251
254
}
252
255
253
256
void mmu_t::store_slow_path_intrapage (reg_t len, const uint8_t * bytes, mem_access_info_t access_info, bool actually_store)
254
257
{
255
258
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;
257
261
if (!access_info.flags .is_special_access () && vpn == (tlb_store_tag[vpn % TLB_ENTRIES] & ~TLB_CHECK_TRIGGERS)) {
258
262
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 ;
260
264
memcpy (host_addr, bytes, len);
261
265
}
262
266
return ;
@@ -272,34 +276,35 @@ void mmu_t::store_slow_path_intrapage(reg_t len, const uint8_t* bytes, mem_acces
272
276
else if (!access_info.flags .is_special_access ())
273
277
refill_tlb (addr, paddr, host_addr, STORE);
274
278
} 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 );
276
280
}
277
281
}
278
282
}
279
283
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)
281
285
{
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 ;
283
288
if (actually_store) {
284
289
reg_t trig_len = len;
285
290
const uint8_t * trig_bytes = bytes;
286
291
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));
288
293
trig_len -= sizeof (reg_t );
289
294
trig_bytes += sizeof (reg_t );
290
295
}
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));
292
297
}
293
298
294
- if (addr & (len - 1 )) {
299
+ if (transformed_addr & (len - 1 )) {
295
300
bool gva = access_info.effective_virt ;
296
301
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 );
298
303
299
304
if (require_alignment)
300
- throw trap_store_access_fault (gva, addr , 0 , 0 );
305
+ throw trap_store_access_fault (gva, transformed_addr , 0 , 0 );
301
306
302
- reg_t len_page0 = std::min (len, PGSIZE - addr % PGSIZE);
307
+ reg_t len_page0 = std::min (len, PGSIZE - transformed_addr % PGSIZE);
303
308
store_slow_path_intrapage (len_page0, bytes, access_info, actually_store);
304
309
if (len_page0 != len)
305
310
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
484
489
reg_t mmu_t::walk (mem_access_info_t access_info)
485
490
{
486
491
access_type type = access_info.type ;
487
- reg_t addr = access_info.vaddr ;
492
+ reg_t addr = access_info.transformed_vaddr ;
488
493
bool virt = access_info.effective_virt ;
489
494
bool hlvx = access_info.flags .hlvx ;
490
495
reg_t mode = access_info.effective_priv ;
@@ -607,3 +612,51 @@ void mmu_t::register_memtracer(memtracer_t* t)
607
612
flush_tlb ();
608
613
tracer.hook (t);
609
614
}
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