Browse Source

Add Svukte extension support

This adds support for the Svukte extension, which adds support for
address-independent latency of user-mode faults to supervisor addresses.
pull/2121/head
Andrew Young 10 months ago
committed by Binno
parent
commit
a2dc352286
  1. 4
      disasm/isa_parser.cc
  2. 1
      riscv/csr_init.cc
  3. 3
      riscv/csrs.cc
  4. 1
      riscv/isa_parser.h
  5. 43
      riscv/mmu.cc
  6. 2
      riscv/mmu.h

4
disasm/isa_parser.cc

@ -265,6 +265,10 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
extension_table[EXT_SVPBMT] = true;
} else if (ext_str == "svinval") {
extension_table[EXT_SVINVAL] = true;
} else if (ext_str == "svukte") {
if (max_xlen != 64)
bad_isa_string(str, "'svukte' requires RV64");
extension_table[EXT_SVUKTE] = true;
} else if (ext_str == "zfa") {
extension_table[EXT_ZFA] = true;
} else if (ext_str == "zicbom") {

1
riscv/csr_init.cc

@ -329,6 +329,7 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa)
}
const reg_t senvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? SENVCFG_CBCFE | SENVCFG_CBIE : 0) |
(proc->extension_enabled(EXT_ZICBOZ) ? SENVCFG_CBZE : 0) |
(proc->extension_enabled(EXT_SVUKTE) ? SENVCFG_UKTE : 0) |
(proc->extension_enabled(EXT_SSNPM) ? SENVCFG_PMM : 0) |
(proc->extension_enabled(EXT_ZICFILP) ? SENVCFG_LPE : 0) |
(proc->extension_enabled(EXT_ZICFISS) ? SENVCFG_SSE : 0);

3
riscv/csrs.cc

@ -2020,7 +2020,8 @@ hstatus_csr_t::hstatus_csr_t(processor_t* const proc, const reg_t addr):
}
bool hstatus_csr_t::unlogged_write(const reg_t val) noexcept {
const reg_t mask = HSTATUS_VTSR | HSTATUS_VTW
const reg_t mask = (proc->extension_enabled(EXT_SVUKTE) ? HSTATUS_HUKTE : 0)
| HSTATUS_VTSR | HSTATUS_VTW
| (proc->supports_impl(IMPL_MMU) ? HSTATUS_VTVM : 0)
| (proc->extension_enabled(EXT_SSNPM) ? HSTATUS_HUPMM : 0)
| HSTATUS_HU | HSTATUS_SPVP | HSTATUS_SPV | HSTATUS_GVA;

1
riscv/isa_parser.h

@ -47,6 +47,7 @@ typedef enum {
EXT_SVNAPOT,
EXT_SVPBMT,
EXT_SVINVAL,
EXT_SVUKTE,
EXT_ZDINX,
EXT_ZFA,
EXT_ZFBFMIN,

43
riscv/mmu.cc

@ -53,6 +53,16 @@ void throw_access_exception(bool virt, reg_t addr, access_type type)
}
}
[[noreturn]] void throw_page_fault_exception(bool virt, reg_t addr, access_type type)
{
switch (type) {
case FETCH: throw trap_instruction_page_fault(virt, addr, 0, 0);
case LOAD: throw trap_load_page_fault(virt, addr, 0, 0);
case STORE: throw trap_store_page_fault(virt, addr, 0, 0);
default: abort();
}
}
reg_t mmu_t::translate(mem_access_info_t access_info, reg_t len)
{
reg_t addr = access_info.transformed_vaddr;
@ -560,6 +570,28 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty
}
}
bool mmu_t::check_svukte_qualified(reg_t addr, reg_t mode, bool forced_virt)
{
state_t* state = proc->get_state();
if (mode != PRV_U)
return true;
if (proc->extension_enabled('S') && get_field(state->senvcfg->read(), SENVCFG_UKTE)) {
if (forced_virt && state->prv == PRV_U) {
bool hstatus_hukte = proc->extension_enabled('H') && (get_field(state->hstatus->read(), HSTATUS_HUKTE) == 1);
return !hstatus_hukte;
}
assert(proc->get_xlen() == 64);
if ((addr >> 63) & 1) {
return (state->v || forced_virt) && ((state->vsatp->read() & SATP64_MODE) == 0);
}
}
return true;
}
reg_t mmu_t::walk(mem_access_info_t access_info)
{
access_type type = access_info.type;
@ -582,6 +614,10 @@ reg_t mmu_t::walk(mem_access_info_t access_info)
if (vm.levels == 0)
return s2xlate(addr, addr & ((reg_t(2) << (proc->xlen-1))-1), type, type, virt, hlvx, false) & ~page_mask; // zero-extend from xlen
if (proc->extension_enabled(EXT_SVUKTE) && !check_svukte_qualified(addr, mode, access_info.flags.forced_virt)) {
throw_page_fault_exception(virt, addr, type);
}
bool s_mode = mode == PRV_S;
bool sum = proc->state.sstatus->readvirt(virt) & MSTATUS_SUM;
bool mxr = (proc->state.sstatus->readvirt(false) | proc->state.sstatus->readvirt(virt)) & MSTATUS_MXR;
@ -672,12 +708,7 @@ reg_t mmu_t::walk(mem_access_info_t access_info)
}
}
switch (type) {
case FETCH: throw trap_instruction_page_fault(virt, addr, 0, 0);
case LOAD: throw trap_load_page_fault(virt, addr, 0, 0);
case STORE: throw trap_store_page_fault(virt, addr, 0, 0);
default: abort();
}
throw_page_fault_exception(virt, addr, type);
}
void mmu_t::register_memtracer(memtracer_t* t)

2
riscv/mmu.h

@ -78,6 +78,7 @@ struct mem_access_info_t {
};
void throw_access_exception(bool virt, reg_t addr, access_type type);
[[noreturn]] void throw_page_fault_exception(bool virt, reg_t addr, access_type type);
// this class implements a processor's port into the virtual memory system.
// an MMU and instruction cache are maintained for simulator performance.
@ -447,6 +448,7 @@ private:
check_triggers(operation, address, virt, address, data);
}
void check_triggers(triggers::operation_t operation, reg_t address, bool virt, reg_t tval, std::optional<reg_t> data);
bool check_svukte_qualified(reg_t addr, reg_t mode, bool forced_virt);
reg_t translate(mem_access_info_t access_info, reg_t len);
reg_t pte_load(reg_t pte_paddr, reg_t addr, bool virt, access_type trap_type, size_t ptesize) {

Loading…
Cancel
Save