#define MSTATUS_FS 0x00006000
#define MSTATUS_XS 0x00018000
#define MSTATUS_MPRV 0x00020000
-#define MSTATUS_VM 0x007C0000
+#define MSTATUS_PUM 0x00040000
+#define MSTATUS_VM 0x1F000000
#define MSTATUS32_SD 0x80000000
#define MSTATUS64_SD 0x8000000000000000
#define SSTATUS_SPP 0x00000100
#define SSTATUS_FS 0x00006000
#define SSTATUS_XS 0x00018000
-#define SSTATUS_VM 0x007C0000
+#define SSTATUS_PUM 0x00040000
#define SSTATUS32_SD 0x80000000
#define SSTATUS64_SD 0x8000000000000000
#define CSR_MCPUID 0xf00
#define CSR_MIMPID 0xf01
#define CSR_MHARTID 0xf10
-#define CSR_MTOHOST 0x780
-#define CSR_MFROMHOST 0x781
-#define CSR_MRESET 0x782
-#define CSR_MIOBASE 0x784
+#define CSR_MTOHOST 0x7c0
+#define CSR_MFROMHOST 0x7c1
+#define CSR_MRESET 0x7c2
+#define CSR_MIOBASE 0x7c4
#define CSR_CYCLEH 0xc80
#define CSR_TIMEH 0xc81
#define CSR_INSTRETH 0xc82
#define CSR_STIMEH 0xd81
#define CSR_STIMEHW 0xa81
#define CSR_MTIMECMPH 0x361
-#define CSR_MTIMEH 0x741
+#define CSR_MTIMEH 0x781
#define CAUSE_MISALIGNED_FETCH 0x0
#define CAUSE_FAULT_FETCH 0x1
#define CAUSE_ILLEGAL_INSTRUCTION 0x2
return addr;
reg_t mode = proc->state.prv;
- if (type != FETCH && proc->state.prv == PRV_M &&
- get_field(proc->state.mstatus, MSTATUS_MPRV))
- mode = get_field(proc->state.mstatus, MSTATUS_MPP);
+ bool pum = false;
+ if (type != FETCH) {
+ if (get_field(proc->state.mstatus, MSTATUS_MPRV))
+ mode = get_field(proc->state.mstatus, MSTATUS_MPP);
+ pum = (mode == PRV_S && get_field(proc->state.mstatus, MSTATUS_PUM));
+ }
if (get_field(proc->state.mstatus, MSTATUS_VM) == VM_MBARE)
mode = PRV_M;
reg_t msb_mask = (reg_t(2) << (proc->xlen-1))-1; // zero-extend from xlen
return addr & msb_mask;
}
- return walk(addr, mode > PRV_U, type) | (addr & (PGSIZE-1));
+ return walk(addr, type, mode > PRV_U, pum) | (addr & (PGSIZE-1));
}
const uint16_t* mmu_t::fetch_slow_path(reg_t addr)
tlb_data[idx] = mem + paddr - vaddr;
}
-reg_t mmu_t::walk(reg_t addr, bool supervisor, access_type type)
+reg_t mmu_t::walk(reg_t addr, access_type type, bool supervisor, bool pum)
{
int levels, ptidxbits, ptesize;
switch (get_field(proc->get_state()->mstatus, MSTATUS_VM))
if (PTE_TABLE(pte)) { // next level of page table
base = ppn << PGSHIFT;
+ } else if (pum && PTE_CHECK_PERM(pte, 0, type == STORE, type == FETCH)) {
+ break;
} else if (!PTE_CHECK_PERM(pte, supervisor, type == STORE, type == FETCH)) {
break;
} else {
void refill_tlb(reg_t vaddr, reg_t paddr, access_type type);
// perform a page table walk for a given VA; set referenced/dirty bits
- reg_t walk(reg_t addr, bool supervisor, access_type type);
+ reg_t walk(reg_t addr, access_type type, bool supervisor, bool pum);
// handle uncommon cases: TLB misses, page faults, MMIO
const uint16_t* fetch_slow_path(reg_t addr);
state.suinstret_delta = (val << 32) | (uint32_t)state.suinstret_delta;
break;
case CSR_MSTATUS: {
- if ((val ^ state.mstatus) & (MSTATUS_VM | MSTATUS_MPP | MSTATUS_MPRV))
+ if ((val ^ state.mstatus) &
+ (MSTATUS_VM | MSTATUS_MPP | MSTATUS_MPRV | MSTATUS_PUM))
mmu->flush_tlb();
reg_t mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE
- | MSTATUS_SPP | MSTATUS_MPRV | MSTATUS_FS
+ | MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_PUM
| (ext ? MSTATUS_XS : 0);
if (validate_vm(max_xlen, get_field(val, MSTATUS_VM)))
}
case CSR_SSTATUS: {
reg_t mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP | SSTATUS_FS
- | SSTATUS_XS;
+ | SSTATUS_XS | SSTATUS_PUM;
set_csr(CSR_MSTATUS, (state.mstatus & ~mask) | (val & mask));
break;
}
break;
return (state.minstret + state.suinstret_delta) >> 32;
case CSR_SSTATUS: {
- reg_t sstatus = state.mstatus &
- (SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS);
+ reg_t mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP | SSTATUS_FS
+ | SSTATUS_XS | SSTATUS_PUM;
+ reg_t sstatus = state.mstatus & mask;
if ((sstatus & SSTATUS_FS) == SSTATUS_FS ||
(sstatus & SSTATUS_XS) == SSTATUS_XS)
sstatus |= (xlen == 32 ? SSTATUS32_SD : SSTATUS64_SD);