aboutsummaryrefslogtreecommitdiff
path: root/riscv
diff options
context:
space:
mode:
Diffstat (limited to 'riscv')
-rw-r--r--riscv/encoding.h15
-rw-r--r--riscv/mmu.cc15
-rw-r--r--riscv/mmu.h2
-rw-r--r--riscv/processor.cc12
4 files changed, 26 insertions, 18 deletions
diff --git a/riscv/encoding.h b/riscv/encoding.h
index a88205f..b2ef0bf 100644
--- a/riscv/encoding.h
+++ b/riscv/encoding.h
@@ -17,7 +17,8 @@
#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
@@ -28,7 +29,7 @@
#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
@@ -669,10 +670,10 @@
#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
@@ -682,7 +683,7 @@
#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
diff --git a/riscv/mmu.cc b/riscv/mmu.cc
index b8fb028..45457d9 100644
--- a/riscv/mmu.cc
+++ b/riscv/mmu.cc
@@ -35,9 +35,12 @@ reg_t mmu_t::translate(reg_t addr, access_type type)
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;
@@ -45,7 +48,7 @@ reg_t mmu_t::translate(reg_t addr, access_type type)
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)
@@ -102,7 +105,7 @@ void mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, access_type type)
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))
@@ -136,6 +139,8 @@ reg_t mmu_t::walk(reg_t addr, bool supervisor, access_type type)
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 {
diff --git a/riscv/mmu.h b/riscv/mmu.h
index b6697cd..b9948c5 100644
--- a/riscv/mmu.h
+++ b/riscv/mmu.h
@@ -161,7 +161,7 @@ private:
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);
diff --git a/riscv/processor.cc b/riscv/processor.cc
index e948a47..0673787 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -306,11 +306,12 @@ void processor_t::set_csr(int which, reg_t val)
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)))
@@ -356,7 +357,7 @@ void processor_t::set_csr(int which, reg_t val)
}
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;
}
@@ -443,8 +444,9 @@ reg_t processor_t::get_csr(int which)
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);