Browse Source

Implement SPMP extension

* Add 'spmp' in isa string parsing for SPMP extension
* Add PMP_Entry CSRs of spmp
* Implement SPMP matching logic
* Update implementation to spec rc5 version
pull/2299/head
Binno 10 months ago
committed by Andrew Waterman
parent
commit
4850489df5
Failed to extract signature
  1. 5
      disasm/isa_parser.cc
  2. 30
      riscv/csr_init.cc
  3. 240
      riscv/csrs.cc
  4. 64
      riscv/csrs.h
  5. 5
      riscv/isa_parser.h
  6. 59
      riscv/mmu.cc
  7. 5
      riscv/mmu.h
  8. 5
      riscv/processor.h

5
disasm/isa_parser.cc

@ -150,6 +150,8 @@ static const extension_info_t extension_infos[] = {
{"zkr", {EXT_ZKR}},
{"zkt"},
{"smepmp", {EXT_SMEPMP}},
{"sspmp", {EXT_SSPMP, EXT_SMPMPDELEG, EXT_SMCSRIND, EXT_SSCSRIND}},
{"sspmpen", {EXT_SSPMPEN}},
{"smstateen", {EXT_SMSTATEEN}},
{"smpmpmt", {EXT_SMPMPMT}},
{"smrnmi", {EXT_SMRNMI}},
@ -452,4 +454,7 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
if (extension_table[ch])
max_isa |= 1UL << (ch - 'A');
}
if (extension_table[EXT_SSPMP] && !supervisor)
bad_isa_string(str, "'SPMP' extension requires S mode");
}

30
riscv/csr_init.cc

@ -330,7 +330,7 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa)
}
for (int i = 0; i < max_pmp; ++i) {
add_csr(CSR_PMPADDR0 + i, pmpaddr[i] = std::make_shared<pmpaddr_csr_t>(proc, CSR_PMPADDR0 + i));
add_csr(CSR_PMPADDR0 + i, mpmpaddr[i] = std::make_shared<pmpaddr_csr_t>(proc, CSR_PMPADDR0 + i));
}
for (int i = 0; i < max_pmp; i += xlen / 8) {
reg_t addr = CSR_PMPCFG0 + i / 4;
@ -572,4 +572,32 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa)
add_hypervisor_csr(CSR_HVICTL, hvictl);
add_hypervisor_csr(CSR_VSTOPI, vstopi);
}
if (proc->extension_enabled_const(EXT_SMPMPDELEG)) {
add_csr(CSR_MPMPDELEG, mpmpdeleg = std::make_shared<mpmpdeleg_csr_t>(proc, CSR_MPMPDELEG, MPMPDELEG_PMPNUM, proc->n_pmp));
}
if (proc->extension_enabled_const(EXT_SSPMP)) {
const reg_t spmp_cfg_mask = (SPMP_SHARED | SPMP_U | PMP_L | PMP_A | PMP_X | PMP_W | PMP_R);
// add entry registers (index: 0x0..0x3F)
for (size_t i = 0; i < max_pmp; ++i) {
spmpaddr[i] = std::make_shared<spmpaddr_csr_t>(proc, i);
dynamic_cast<sscsrind_reg_csr_t*>(csrmap[CSR_MIREG].get())->add_ireg_proxy(i, spmpaddr[i]);
dynamic_cast<sscsrind_reg_csr_t*>(csrmap[CSR_SIREG].get())->add_ireg_proxy(i, spmpaddr[i]);
csr_t_p cfg = std::make_shared<spmpcfg_csr_t>(proc, i, spmp_cfg_mask, 0);
dynamic_cast<sscsrind_reg_csr_t*>(csrmap[CSR_MIREG2].get())->add_ireg_proxy(i, cfg);
dynamic_cast<sscsrind_reg_csr_t*>(csrmap[CSR_SIREG2].get())->add_ireg_proxy(i, cfg);
}
if (proc->extension_enabled_const(EXT_SSPMPEN)) {
sspmpswitch = std::make_shared<spmpen_csr_t>(proc, CSR_SPMPEN, 0);
if (xlen == 32) {
add_supervisor_csr(CSR_SPMPEN, std::make_shared<rv32_low_csr_t>(proc, CSR_SPMPEN, sspmpswitch));
add_supervisor_csr(CSR_SPMPENH, std::make_shared<rv32_high_csr_t>(proc, CSR_SPMPENH, sspmpswitch));
} else {
add_supervisor_csr(CSR_SPMPEN, sspmpswitch);
}
}
}
}

240
riscv/csrs.cc

@ -84,75 +84,45 @@ bool basic_csr_t::unlogged_write(const reg_t val) noexcept {
return true;
}
// implement class pmpaddr_csr_t
pmpaddr_csr_t::pmpaddr_csr_t(processor_t* const proc, const reg_t addr):
// implement class base_pmpaddr_csr_t
base_pmpaddr_csr_t::base_pmpaddr_csr_t(processor_t* const proc, const reg_t addr, const size_t idx, bool is_spmp):
csr_t(proc, addr),
val(0),
cfg(0),
pmpidx(address - CSR_PMPADDR0) {
}
void pmpaddr_csr_t::verify_permissions(insn_t insn, bool write) const {
csr_t::verify_permissions(insn, write);
// If n_pmp is zero, that means pmp is not implemented hence raise
// trap if it tries to access the csr. I would prefer to implement
// this by not instantiating any pmpaddr_csr_t for these regs, but
// n_pmp can change after reset() is run.
if (proc->n_pmp == 0)
throw trap_illegal_instruction(insn.bits());
}
reg_t pmpaddr_csr_t::read() const noexcept {
if ((cfg & PMP_A) >= PMP_NAPOT)
return val | (~proc->pmp_tor_mask() >> 1);
return val & proc->pmp_tor_mask();
}
bool pmpaddr_csr_t::unlogged_write(const reg_t val) noexcept {
// If no PMPs are configured, disallow access to all. Otherwise,
// allow access to all, but unimplemented ones are hardwired to
// zero. Note that n_pmp can change after reset(); otherwise I would
// implement this in state_t::reset() by instantiating the correct
// number of pmpaddr_csr_t.
if (proc->n_pmp == 0)
return false;
const bool lock_bypass = state->mseccfg->get_rlb();
const bool locked = !lock_bypass && (cfg & PMP_L);
if (pmpidx < proc->n_pmp && !locked && !next_locked_and_tor()) {
this->val = val & ((reg_t(1) << (proc->paddr_bits() - PMP_SHIFT)) - 1);
}
else
return false;
proc->get_mmu()->flush_tlb();
return true;
pmpidx(idx),
pmpaddr(is_spmp? state->spmpaddr : state->mpmpaddr),
is_spmp(is_spmp) {
}
bool pmpaddr_csr_t::next_locked_and_tor() const noexcept {
bool base_pmpaddr_csr_t::next_locked_and_tor() const noexcept {
if (pmpidx+1 >= state->max_pmp) return false; // this is the last entry
const bool lock_bypass = state->mseccfg->get_rlb();
const bool next_locked = !lock_bypass && (state->pmpaddr[pmpidx+1]->cfg & PMP_L);
const bool next_tor = (state->pmpaddr[pmpidx+1]->cfg & PMP_A) == PMP_TOR;
const bool next_locked = !lock_bypass && (pmpaddr[pmpidx+1]->cfg & PMP_L);
const bool next_tor = (pmpaddr[pmpidx+1]->cfg & PMP_A) == PMP_TOR;
return next_locked && next_tor;
}
reg_t pmpaddr_csr_t::tor_paddr() const noexcept {
reg_t base_pmpaddr_csr_t::tor_paddr() const noexcept {
return (val & proc->pmp_tor_mask()) << PMP_SHIFT;
}
reg_t pmpaddr_csr_t::tor_base_paddr() const noexcept {
reg_t base_pmpaddr_csr_t::tor_base_paddr() const noexcept {
if (pmpidx == 0) return 0; // entry 0 always uses 0 as base
return state->pmpaddr[pmpidx-1]->tor_paddr();
return pmpaddr[pmpidx-1]->tor_paddr();
}
reg_t pmpaddr_csr_t::napot_mask() const noexcept {
reg_t base_pmpaddr_csr_t::napot_mask() const noexcept {
bool is_na4 = (cfg & PMP_A) == PMP_NA4;
reg_t mask = (val << 1) | (!is_na4) | ~proc->pmp_tor_mask();
return ~(mask & ~(mask + 1)) << PMP_SHIFT;
}
bool pmpaddr_csr_t::match4(reg_t addr) const noexcept {
bool base_pmpaddr_csr_t::match4(reg_t addr) const noexcept {
if (proc->extension_enabled_const(EXT_SSPMPEN) && is_spmp) {
if (!((state->sspmpswitch->read() >> pmpidx) & 1))
return false;
}
if ((cfg & PMP_A) == 0) return false;
bool is_tor = (cfg & PMP_A) == PMP_TOR;
if (is_tor) return tor_base_paddr() <= addr && addr < tor_paddr();
@ -160,7 +130,12 @@ bool pmpaddr_csr_t::match4(reg_t addr) const noexcept {
return ((addr ^ tor_paddr()) & napot_mask()) == 0;
}
bool pmpaddr_csr_t::subset_match(reg_t addr, reg_t len) const noexcept {
bool base_pmpaddr_csr_t::subset_match(reg_t addr, reg_t len) const noexcept {
if (proc->extension_enabled_const(EXT_SSPMPEN) && is_spmp) {
if (!((state->sspmpswitch->read() >> pmpidx) & 1))
return false;
}
if ((addr | len) & (len - 1))
abort();
reg_t base = tor_base_paddr();
@ -182,6 +157,52 @@ bool pmpaddr_csr_t::subset_match(reg_t addr, reg_t len) const noexcept {
return !(is_tor ? tor_homogeneous : napot_homogeneous);
}
pmpaddr_csr_t::pmpaddr_csr_t(processor_t* const proc, const reg_t addr):
base_pmpaddr_csr_t(proc, addr, addr - CSR_PMPADDR0, false) {
}
void pmpaddr_csr_t::verify_permissions(insn_t insn, bool write) const {
csr_t::verify_permissions(insn, write);
// If n_pmp is zero, that means pmp is not implemented hence raise
// trap if it tries to access the csr. I would prefer to implement
// this by not instantiating any base_pmpaddr_csr_t for these regs, but
// n_pmp can change after reset() is run.
if (proc->n_pmp == 0)
throw trap_illegal_instruction(insn.bits());
}
reg_t pmpaddr_csr_t::read() const noexcept {
if (pmpidx >= proc->n_pmp)
return 0;
if ((cfg & PMP_A) >= PMP_NAPOT)
return val | (~proc->pmp_tor_mask() >> 1);
return val & proc->pmp_tor_mask();
}
bool pmpaddr_csr_t::unlogged_write(const reg_t val) noexcept {
// If no PMPs are configured, disallow access to all. Otherwise,
// allow access to all, but unimplemented ones are hardwired to
// zero. Note that n_pmp can change after reset(); otherwise I would
// implement this in state_t::reset() by instantiating the correct
// number of base_pmpaddr_csr_t.
if (proc->n_pmp == 0)
return false;
if (pmpidx >= proc->n_pmp)
return true;
const bool lock_bypass = state->mseccfg->get_rlb();
const bool locked = !lock_bypass && (cfg & PMP_L);
if (pmpidx >= proc->n_pmp || locked || next_locked_and_tor())
return false;
this->val = val & ((reg_t(1) << (proc->paddr_bits() - PMP_SHIFT)) - 1);
proc->get_mmu()->flush_tlb();
return true;
}
bool pmpaddr_csr_t::access_ok(access_type type, reg_t mode, bool hlvx) const noexcept {
const bool cfgx = cfg & PMP_X;
const bool cfgw = cfg & PMP_W;
@ -234,7 +255,7 @@ void pmpcfg_csr_t::verify_permissions(insn_t insn, bool write) const {
reg_t pmpcfg_csr_t::read() const noexcept {
reg_t cfg_res = 0;
for (size_t i0 = (address - CSR_PMPCFG0) * 4, i = i0; i < i0 + proc->get_xlen() / 8 && i < state->max_pmp; i++)
cfg_res |= reg_t(state->pmpaddr[i]->cfg) << (8 * (i - i0));
cfg_res |= reg_t(state->mpmpaddr[i]->cfg) << (8 * (i - i0));
return cfg_res;
}
@ -247,7 +268,7 @@ bool pmpcfg_csr_t::unlogged_write(const reg_t val) noexcept {
const bool mml = state->mseccfg->get_mml();
for (size_t i0 = (address - CSR_PMPCFG0) * 4, i = i0; i < i0 + proc->get_xlen() / 8; i++) {
if (i < proc->n_pmp) {
const bool locked = (state->pmpaddr[i]->cfg & PMP_L);
const bool locked = (state->mpmpaddr[i]->cfg & PMP_L);
if (rlb || !locked) {
uint8_t all_cfg_fields = (PMP_R | PMP_W | PMP_X | PMP_A |
(proc->extension_enabled(EXT_SMPMPMT) ? PMP_MT : 0) |
@ -276,7 +297,7 @@ bool pmpcfg_csr_t::unlogged_write(const reg_t val) noexcept {
&& !(cfgx && cfgw && cfgr) // RWX = 111 is allowed
&& (cfgx || (cfgw && !cfgr)) // X=1 or RW=01 is not allowed
))) {
state->pmpaddr[i]->cfg = cfg;
state->mpmpaddr[i]->cfg = cfg;
}
}
write_success = true;
@ -286,6 +307,117 @@ bool pmpcfg_csr_t::unlogged_write(const reg_t val) noexcept {
return write_success;
}
mpmpdeleg_csr_t::mpmpdeleg_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init):
masked_csr_t(proc, addr, mask, init) {
}
bool mpmpdeleg_csr_t::unlogged_write(const reg_t val) noexcept {
int max_locked_pmp_index = -1;
for(reg_t i = 0; i < proc->n_pmp; ++i) {
if (state->mpmpaddr[i]->is_locked())
max_locked_pmp_index = i;
}
reg_t new_val = val & MPMPDELEG_PMPNUM;
if (new_val > state->max_pmp)
new_val = state->max_pmp;
bool write_success = false;
if (max_locked_pmp_index < (int)new_val) {
proc->n_pmp = new_val;
write_success = masked_csr_t::unlogged_write(new_val);
}
return write_success;
}
spmpaddr_csr_t::spmpaddr_csr_t(processor_t* const proc, const reg_t addr):
base_pmpaddr_csr_t(proc, addr, addr & 0x3F, true) {
}
reg_t spmpaddr_csr_t::read() const noexcept {
if ((cfg & PMP_A) >= PMP_NAPOT)
return val | (~proc->pmp_tor_mask() >> 1);
return val & proc->pmp_tor_mask();
}
bool spmpaddr_csr_t::unlogged_write(const reg_t val) noexcept {
if ((state->prv != PRV_M && (cfg & PMP_L)) || next_locked_and_tor())
return false;
this->val = val & ((reg_t(1) << (proc->paddr_bits() - PMP_SHIFT)) - 1);
proc->get_mmu()->flush_tlb();
return true;
}
bool spmpaddr_csr_t::access_ok(access_type type, reg_t mode, bool) const noexcept {
const bool cfgx = cfg & PMP_X;
const bool cfgw = cfg & PMP_W;
const bool cfgr = cfg & PMP_R;
const bool cfgu = cfg & SPMP_U;
const bool cfgs = cfg & SPMP_SHARED;
const bool prvs = mode == PRV_S;
const bool prvu = mode == PRV_U;
const bool typer = type == LOAD;
const bool typex = type == FETCH;
const bool typew = type == STORE;
const bool sum = STATE.sstatus->read() & SSTATUS_SUM;
const bool reserved = !cfgr && cfgw;
const bool deny = !cfgs && ((cfgu && prvs && !sum) || (!cfgu && prvu));
bool enforce_no_x(false), share_read_only(false), share_exec_only(false);
if (cfgu) {
if (!cfgs) {
if (prvs && sum) enforce_no_x = true;
} else if (cfgr && cfgw) {
if (cfgx) share_exec_only = true;
else share_read_only = true;
}
}
const bool normal_rwx = (typer && cfgr && !share_exec_only) ||
(typew && cfgw && !share_read_only && !share_exec_only) ||
(typex && cfgx && !share_read_only && !enforce_no_x);
return !reserved && !deny && normal_rwx;
}
spmpcfg_csr_t::spmpcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init):
masked_csr_t(proc, addr, mask, init) {
}
bool spmpcfg_csr_t::unlogged_write(const reg_t val) noexcept {
const size_t idx = address & 0x3F;
const bool locked = (state->spmpaddr[idx]->cfg & PMP_L);
bool write_success = false;
if (!locked) {
state->spmpaddr[idx]->cfg = val;
write_success = masked_csr_t::unlogged_write(val);
}
proc->get_mmu()->flush_tlb();
return write_success;
}
spmpen_csr_t::spmpen_csr_t(processor_t* const proc, const reg_t addr, const reg_t init):
basic_csr_t(proc, addr, init) {
}
bool spmpen_csr_t::unlogged_write(const reg_t val) noexcept {
reg_t write_val = 0;
for (reg_t i = 0; i < (state->max_pmp - proc->n_pmp); ++i) {
if (!state->spmpaddr[i]->is_locked() && ((val >> i) & 1))
write_val |= reg_t(1) << i;
}
return basic_csr_t::unlogged_write(write_val);
}
// implement class mseccfg_csr_t
mseccfg_csr_t::mseccfg_csr_t(processor_t* const proc, const reg_t addr):
basic_csr_t(proc, addr, 0) {
@ -325,8 +457,8 @@ bool mseccfg_csr_t::unlogged_write(const reg_t val) noexcept {
if (proc->n_pmp != 0) {
// pmpcfg.L is 1 in any rule or entry (including disabled entries)
const bool pmplock_recorded = std::any_of(state->pmpaddr, state->pmpaddr + proc->n_pmp,
[](const pmpaddr_csr_t_p & c) { return c->is_locked(); } );
const bool pmplock_recorded = std::any_of(state->mpmpaddr, state->mpmpaddr + proc->n_pmp,
[](const base_pmpaddr_csr_t_p & c) { return c->is_locked(); } );
// When RLB is 0 and pmplock_recorded, RLB is locked to 0.
// Otherwise set the RLB bit according val

64
riscv/csrs.h

@ -89,11 +89,9 @@ class basic_csr_t: public csr_t {
reg_t val;
};
class pmpaddr_csr_t: public csr_t {
class base_pmpaddr_csr_t: public csr_t {
public:
pmpaddr_csr_t(processor_t* const proc, const reg_t addr);
virtual void verify_permissions(insn_t insn, bool write) const override;
virtual reg_t read() const noexcept override;
base_pmpaddr_csr_t(processor_t* const proc, const reg_t addr, const size_t idx, bool is_spmp);
// Does a 4-byte access at the specified address match this PMP entry?
bool match4(reg_t addr) const noexcept;
@ -102,15 +100,13 @@ class pmpaddr_csr_t: public csr_t {
bool subset_match(reg_t addr, reg_t len) const noexcept;
// Is the specified access allowed given the pmpcfg privileges?
bool access_ok(access_type type, reg_t mode, bool hlvx) const noexcept;
virtual bool access_ok(access_type type, reg_t mode, bool hlvx) const noexcept = 0;
// To check lock bit status from outside like mseccfg
bool is_locked() const noexcept {
return cfg & PMP_L;
}
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
private:
// Assuming this is configured as TOR, return address for top of
// range. Also forms bottom-of-range for next-highest pmpaddr
@ -126,13 +122,29 @@ class pmpaddr_csr_t: public csr_t {
reg_t napot_mask() const noexcept;
bool next_locked_and_tor() const noexcept;
reg_t val;
friend class pmpcfg_csr_t; // so he can access cfg
uint8_t cfg;
friend class spmpcfg_csr_t;
friend class pmpaddr_csr_t;
friend class spmpaddr_csr_t;
reg_t val;
uint16_t cfg;
const size_t pmpidx;
std::shared_ptr<base_pmpaddr_csr_t>* pmpaddr;
bool is_spmp;
};
typedef std::shared_ptr<pmpaddr_csr_t> pmpaddr_csr_t_p;
typedef std::shared_ptr<base_pmpaddr_csr_t> base_pmpaddr_csr_t_p;
class pmpaddr_csr_t: public base_pmpaddr_csr_t {
public:
pmpaddr_csr_t(processor_t* const proc, const reg_t addr);
virtual void verify_permissions(insn_t insn, bool write) const override;
virtual reg_t read() const noexcept override;
virtual bool access_ok(access_type type, reg_t mode, bool hlvx) const noexcept override;
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
};
class pmpcfg_csr_t: public csr_t {
public:
@ -996,4 +1008,36 @@ class aia_csr_t: public masked_csr_t {
aia_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init);
virtual void verify_permissions(insn_t insn, bool write) const override;
};
class mpmpdeleg_csr_t: public masked_csr_t {
public:
mpmpdeleg_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init);
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
};
class spmpaddr_csr_t: public base_pmpaddr_csr_t {
public:
spmpaddr_csr_t(processor_t* const proc, const reg_t addr);
virtual void verify_permissions(insn_t, bool) const override {}
virtual reg_t read() const noexcept override;
virtual bool access_ok(access_type type, reg_t mode, bool) const noexcept override;
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
};
class spmpcfg_csr_t: public masked_csr_t {
public:
spmpcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init);
virtual void verify_permissions(insn_t, bool) const override {}
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
};
class spmpen_csr_t: public basic_csr_t {
public:
spmpen_csr_t(processor_t* const proc, const reg_t addr, const reg_t init);
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
};
#endif

5
riscv/isa_parser.h

@ -40,9 +40,12 @@ typedef enum {
EXT_ZVFOFP4MIN,
EXT_ZVFOFP8MIN,
EXT_SMEPMP,
EXT_SMSTATEEN,
EXT_SMPMPMT,
EXT_SMRNMI,
EXT_SMSTATEEN,
EXT_SSPMP,
EXT_SMPMPDELEG,
EXT_SSPMPEN,
EXT_SSCOFPMF,
EXT_SVADU,
EXT_SVADE,

59
riscv/mmu.cc

@ -48,7 +48,7 @@ void mmu_t::flush_tlb()
flush_icache();
}
void throw_access_exception(bool virt, reg_t addr, access_type type)
[[noreturn]] void throw_access_exception(bool virt, reg_t addr, access_type type)
{
switch (type) {
case FETCH: throw trap_instruction_access_fault(virt, addr, 0, 0);
@ -79,6 +79,12 @@ reg_t mmu_t::translate(mem_access_info_t access_info, reg_t len)
reg_t mode = (reg_t) access_info.effective_priv;
reg_t paddr = walk(access_info) | (addr & (PGSIZE-1));
reg_t satp = proc->get_state()->satp->readvirt(virt);
if (proc->extension_enabled_const(EXT_SSPMP)) {
if ((satp == SATP_MODE_OFF) && (mode < PRV_M) && !spmp_ok(paddr, len, type, mode))
throw_page_fault_exception(virt, addr, type);
}
if (!pmp_ok(paddr, len, access_info.flags.ss_access ? STORE : type, mode, access_info.flags.hlvx))
throw_access_exception(virt, addr, access_info.flags.ss_access ? STORE : type);
return paddr;
@ -491,21 +497,19 @@ tlb_entry_t mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, char* host_addr, access_
return entry;
}
bool mmu_t::pmp_ok(reg_t addr, reg_t len, access_type type, reg_t mode, bool hlvx)
bool mmu_t::pmp_search(reg_t addr, reg_t len, base_pmpaddr_csr_t_p* pmpaddr, size_t pmp_num, int &index)
{
if (!proc || proc->n_pmp == 0)
return true;
index = NO_IDX;
reg_t gran = reg_t(1) << proc->lg_pmp_granularity;
reg_t addr_aligned = addr & -gran;
reg_t len_aligned = ((addr + len + gran - 1) & -gran) - addr_aligned;
for (size_t i = 0; i < proc->n_pmp; i++) {
// Check each PMP-granularity sector of the access
for (size_t i = 0; i < pmp_num; i++) {
// Check each 4-byte sector of the access
bool any_match = false;
bool all_match = true;
for (reg_t offset = 0; offset < len_aligned; offset += gran) {
bool match = proc->state.pmpaddr[i]->match4(addr_aligned + offset);
bool match = pmpaddr[i]->match4(addr_aligned + offset);
any_match |= match;
all_match &= match;
}
@ -515,15 +519,48 @@ bool mmu_t::pmp_ok(reg_t addr, reg_t len, access_type type, reg_t mode, bool hlv
if (!all_match)
return false;
return proc->state.pmpaddr[i]->access_ok(type, mode, hlvx);
index = i;
return true;
}
}
return true;
}
bool mmu_t::pmp_ok(reg_t addr, reg_t len, access_type type, reg_t mode, bool hlvx)
{
if (!proc || proc->n_pmp == 0)
return true;
int pmp_idx = NO_IDX;
if (pmp_search(addr, len, proc->state.mpmpaddr, proc->n_pmp, pmp_idx)) {
if (pmp_idx != NO_IDX)
return proc->state.mpmpaddr[pmp_idx]->access_ok(type, mode, hlvx);
} else {
return false;
}
// in case matching region is not found
const bool mseccfg_mml = proc->state.mseccfg->get_mml();
const bool mseccfg_mmwp = proc->state.mseccfg->get_mmwp();
return ((mode == PRV_M) && !mseccfg_mmwp
&& (!mseccfg_mml || ((type == LOAD) || (type == STORE))));
&& (!mseccfg_mml || ((type == LOAD) || (type == STORE))));
}
bool mmu_t::spmp_ok(reg_t addr, reg_t len, access_type type, reg_t mode)
{
if (!proc)
return true;
int pmp_idx = NO_IDX;
if (pmp_search(addr, len, proc->state.spmpaddr, proc->state.max_pmp - proc->n_pmp, pmp_idx)) {
if (pmp_idx != NO_IDX)
return proc->state.spmpaddr[pmp_idx]->access_ok(type, mode, false);
} else {
return false;
}
return true;
}
reg_t mmu_t::pmp_homogeneous(reg_t addr, reg_t len)
@ -535,7 +572,7 @@ reg_t mmu_t::pmp_homogeneous(reg_t addr, reg_t len)
return true;
for (size_t i = 0; i < proc->n_pmp; i++)
if (proc->state.pmpaddr[i]->subset_match(addr, len))
if (proc->state.mpmpaddr[i]->subset_match(addr, len))
return false;
return true;

5
riscv/mmu.h

@ -86,7 +86,7 @@ struct mem_access_info_t {
const access_type type;
};
void throw_access_exception(bool virt, reg_t addr, access_type type);
[[noreturn]] 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.
@ -538,7 +538,10 @@ private:
}
reg_t pmp_homogeneous(reg_t addr, reg_t len);
static const int NO_IDX = -1;
bool pmp_search(reg_t addr, reg_t len, base_pmpaddr_csr_t_p* pmpaddr, size_t pmp_num, int &index);
bool pmp_ok(reg_t addr, reg_t len, access_type type, reg_t mode, bool hlvx);
bool spmp_ok(reg_t addr, reg_t len, access_type type, reg_t mode);
#ifdef RISCV_ENABLE_DUAL_ENDIAN
bool target_big_endian;

5
riscv/processor.h

@ -164,7 +164,10 @@ struct state_t
csr_t_p mseccfgh;
static const int max_pmp = 64;
pmpaddr_csr_t_p pmpaddr[max_pmp];
csr_t_p mpmpdeleg;
base_pmpaddr_csr_t_p mpmpaddr[max_pmp];
base_pmpaddr_csr_t_p spmpaddr[max_pmp];
csr_t_p sspmpswitch;
float_csr_t_p fflags;
float_csr_t_p frm;

Loading…
Cancel
Save