fix MPP reset value, PMP inactive in U-mode handling and MRET in U-mode
This commit is contained in:
parent
65b4db5eca
commit
ba9339a50d
@ -145,7 +145,7 @@ public:
|
||||
|
||||
mstatus_t mstatus;
|
||||
|
||||
static const reg_t mstatus_reset_val = 0;
|
||||
static const reg_t mstatus_reset_val = 0x1800;
|
||||
|
||||
void write_mstatus(T val, unsigned priv_lvl) {
|
||||
auto mask = get_mask(priv_lvl);
|
||||
@ -398,7 +398,7 @@ private:
|
||||
iss::status read_ip(unsigned addr, reg_t &val);
|
||||
iss::status write_ip(unsigned addr, reg_t val);
|
||||
iss::status read_hartid(unsigned addr, reg_t &val);
|
||||
iss::status write_mepc(unsigned addr, reg_t val);
|
||||
iss::status write_epc(unsigned addr, reg_t val);
|
||||
iss::status read_satp(unsigned addr, reg_t &val);
|
||||
iss::status write_satp(unsigned addr, reg_t val);
|
||||
iss::status read_fcsr(unsigned addr, reg_t &val);
|
||||
@ -954,8 +954,8 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_ip(unsigned
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_epc(unsigned addr, reg_t val) {
|
||||
csr[addr] = val & get_pc_mask();
|
||||
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_epc(unsigned addr, reg_t val) {
|
||||
csr[addr] = val & get_pc_mask();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ public:
|
||||
|
||||
mstatus_t mstatus;
|
||||
|
||||
static const reg_t mstatus_reset_val = 0;
|
||||
static const reg_t mstatus_reset_val = 0x1800; // MPP set to 1
|
||||
|
||||
void write_mstatus(T val, unsigned priv_lvl) {
|
||||
auto mask = get_mask(priv_lvl);
|
||||
@ -543,25 +543,27 @@ template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_
|
||||
constexpr auto PMP_NA4 =0x2U;
|
||||
constexpr auto PMP_NAPOT =0x3U;
|
||||
reg_t base = 0;
|
||||
auto any_active = false;
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
reg_t tor = csr[pmpaddr0+i] << PMP_SHIFT;
|
||||
uint8_t cfg = csr[pmpcfg0+(i/4)]>>(i%4);
|
||||
if (cfg & PMP_A) {
|
||||
any_active=true;
|
||||
auto pmp_a = (cfg & PMP_A) >> 3;
|
||||
bool is_tor = pmp_a == PMP_TOR;
|
||||
bool is_na4 = pmp_a == PMP_NA4;
|
||||
auto is_tor = pmp_a == PMP_TOR;
|
||||
auto is_na4 = pmp_a == PMP_NA4;
|
||||
|
||||
reg_t mask = (csr[pmpaddr0+i] << 1) | (!is_na4);
|
||||
mask = ~(mask & ~(mask + 1)) << PMP_SHIFT;
|
||||
|
||||
// Check each 4-byte sector of the access
|
||||
bool any_match = false;
|
||||
bool all_match = true;
|
||||
auto any_match = false;
|
||||
auto all_match = true;
|
||||
for (reg_t offset = 0; offset < len; offset += 1 << PMP_SHIFT) {
|
||||
reg_t cur_addr = addr + offset;
|
||||
bool napot_match = ((cur_addr ^ tor) & mask) == 0;
|
||||
bool tor_match = base <= cur_addr && cur_addr < tor;
|
||||
bool match = is_tor ? tor_match : napot_match;
|
||||
auto napot_match = ((cur_addr ^ tor) & mask) == 0;
|
||||
auto tor_match = base <= cur_addr && cur_addr < tor;
|
||||
auto match = is_tor ? tor_match : napot_match;
|
||||
any_match |= match;
|
||||
all_match &= match;
|
||||
}
|
||||
@ -577,7 +579,7 @@ template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_
|
||||
}
|
||||
base = tor;
|
||||
}
|
||||
return this->reg.PRIV == PRIV_M;
|
||||
return !any_active || this->reg.PRIV == PRIV_M;
|
||||
}
|
||||
|
||||
|
||||
@ -926,8 +928,6 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_ie(unsigned addr, reg_t val) {
|
||||
auto mask = get_irq_wrmask((addr >> 8) & 0x3);
|
||||
if(this->reg.PRIV==0)
|
||||
mask&= ~(0xff<<4); // STIE and UTIE are read only in user and supervisor mode
|
||||
csr[mie] = (csr[mie] & ~mask) | (val & mask);
|
||||
check_interrupt();
|
||||
return iss::Ok;
|
||||
@ -1256,27 +1256,33 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
||||
template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::leave_trap(uint64_t flags) {
|
||||
auto cur_priv = this->reg.PRIV;
|
||||
auto inst_priv = (flags & 0x3)? 3:0;
|
||||
auto status = state.mstatus;
|
||||
// pop the relevant lower-privilege interrupt enable and privilege mode stack
|
||||
// clear respective yIE
|
||||
switch (inst_priv) {
|
||||
case PRIV_M:
|
||||
this->reg.PRIV = state.mstatus.MPP;
|
||||
state.mstatus.MPP = 0; // clear mpp to U mode
|
||||
state.mstatus.MIE = state.mstatus.MPIE;
|
||||
state.mstatus.MPIE = 1;
|
||||
break;
|
||||
case PRIV_U:
|
||||
this->reg.PRIV = 0;
|
||||
state.mstatus.UIE = state.mstatus.UPIE;
|
||||
state.mstatus.UPIE = 1;
|
||||
break;
|
||||
if(inst_priv>cur_priv){
|
||||
auto trap_val = 0x80ULL << 24 | (2 << 16); // illegal instruction
|
||||
this->reg.trap_state = trap_val;
|
||||
this->reg.NEXT_PC = std::numeric_limits<uint32_t>::max();
|
||||
} else {
|
||||
auto status = state.mstatus;
|
||||
// pop the relevant lower-privilege interrupt enable and privilege mode stack
|
||||
// clear respective yIE
|
||||
switch (inst_priv) {
|
||||
case PRIV_M:
|
||||
this->reg.PRIV = state.mstatus.MPP;
|
||||
state.mstatus.MPP = 0; // clear mpp to U mode
|
||||
state.mstatus.MIE = state.mstatus.MPIE;
|
||||
state.mstatus.MPIE = 1;
|
||||
break;
|
||||
case PRIV_U:
|
||||
this->reg.PRIV = 0;
|
||||
state.mstatus.UIE = state.mstatus.UPIE;
|
||||
state.mstatus.UPIE = 1;
|
||||
break;
|
||||
}
|
||||
// sets the pc to the value stored in the x epc register.
|
||||
this->reg.NEXT_PC = csr[uepc | inst_priv << 8];
|
||||
CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to "
|
||||
<< lvl[this->reg.PRIV];
|
||||
check_interrupt();
|
||||
}
|
||||
// sets the pc to the value stored in the x epc register.
|
||||
this->reg.NEXT_PC = csr[uepc | inst_priv << 8];
|
||||
CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to "
|
||||
<< lvl[this->reg.PRIV];
|
||||
check_interrupt();
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user