Browse Source

Refactor set_privilege to subsume set_virt

This cleans up the code and avoids bugs like #1365.
pull/1366/head
Andrew Waterman 3 years ago
parent
commit
2c6b94e853
  1. 3
      riscv/insns/dret.h
  2. 3
      riscv/insns/mnret.h
  3. 3
      riscv/insns/mret.h
  4. 3
      riscv/insns/sret.h
  5. 35
      riscv/processor.cc
  6. 3
      riscv/processor.h

3
riscv/insns/dret.h

@ -1,7 +1,6 @@
require(STATE.debug_mode);
set_pc_and_serialize(STATE.dpc->read());
p->set_privilege(STATE.dcsr->prv);
p->set_virt(STATE.dcsr->v);
p->set_privilege(STATE.dcsr->prv, STATE.dcsr->v);
if (STATE.prv < PRV_M)
STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_MPRV);

3
riscv/insns/mnret.h

@ -11,5 +11,4 @@ if (prev_prv != PRV_M) {
}
s = set_field(s, MNSTATUS_NMIE, 1);
STATE.mnstatus->write(s);
p->set_privilege(prev_prv);
p->set_virt(prev_virt);
p->set_privilege(prev_prv, prev_virt);

3
riscv/insns/mret.h

@ -10,5 +10,4 @@ s = set_field(s, MSTATUS_MPIE, 1);
s = set_field(s, MSTATUS_MPP, p->extension_enabled('U') ? PRV_U : PRV_M);
s = set_field(s, MSTATUS_MPV, 0);
p->put_csr(CSR_MSTATUS, s);
p->set_privilege(prev_prv);
p->set_virt(prev_virt);
p->set_privilege(prev_prv, prev_virt);

3
riscv/insns/sret.h

@ -24,5 +24,4 @@ if (!STATE.v) {
STATE.mstatus->write(set_field(STATE.mstatus->read(), MSTATUS_MPRV, 0));
}
p->set_privilege(prev_prv);
p->set_virt(prev_virt);
p->set_privilege(prev_prv, prev_virt);

35
riscv/processor.cc

@ -714,11 +714,13 @@ reg_t processor_t::legalize_privilege(reg_t prv)
return prv;
}
void processor_t::set_privilege(reg_t prv)
void processor_t::set_privilege(reg_t prv, bool virt)
{
mmu->flush_tlb();
state.prev_prv = state.prv;
state.prev_v = state.v;
state.prv = legalize_privilege(prv);
state.v = virt && state.prv != PRV_M;
}
const char* processor_t::get_privilege_string()
@ -741,31 +743,11 @@ const char* processor_t::get_privilege_string()
abort();
}
void processor_t::set_virt(bool virt)
{
reg_t tmp, mask;
if (state.prv == PRV_M)
return;
/*
* Ideally, we should flush TLB here but we don't need it because
* set_virt() is always used in conjucter with set_privilege() and
* set_privilege() will flush TLB unconditionally.
*
* The virtualized sstatus register also relies on this TLB flush,
* since changing V might change sstatus.MXR and sstatus.SUM.
*/
state.prev_v = state.v;
state.v = virt;
}
void processor_t::enter_debug_mode(uint8_t cause)
{
state.debug_mode = true;
state.dcsr->write_cause_and_prv(cause, state.prv, state.v);
set_virt(false);
set_privilege(PRV_M);
set_privilege(PRV_M, false);
state.dpc->write(state.pc);
state.pc = DEBUG_ROM_ENTRY;
in_wfi = false;
@ -832,8 +814,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
s = set_field(s, MSTATUS_SPP, state.prv);
s = set_field(s, MSTATUS_SIE, 0);
state.sstatus->write(s);
set_virt(true);
set_privilege(PRV_S);
set_privilege(PRV_S, true);
} else if (state.prv <= PRV_S && bit < max_xlen && ((hsdeleg >> bit) & 1)) {
// Handle the trap in HS-mode
reg_t vector = (state.nonvirtual_stvec->read() & 1) && interrupt ? 4 * bit : 0;
@ -857,8 +838,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
s = set_field(s, HSTATUS_GVA, t.has_gva());
state.hstatus->write(s);
}
set_virt(false);
set_privilege(PRV_S);
set_privilege(PRV_S, false);
} else {
// Handle the trap in M-mode
const reg_t vector = (state.mtvec->read() & 1) && interrupt ? 4 * bit : 0;
@ -882,8 +862,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
s = set_field(s, MSTATUS_GVA, t.has_gva());
state.mstatus->write(s);
if (state.mstatush) state.mstatush->write(s >> 32); // log mstatush change
set_virt(false);
set_privilege(PRV_M);
set_privilege(PRV_M, false);
}
}

3
riscv/processor.h

@ -269,8 +269,7 @@ public:
throw trap_instruction_address_misaligned(state.v, pc, 0, 0);
}
reg_t legalize_privilege(reg_t);
void set_privilege(reg_t);
void set_virt(bool);
void set_privilege(reg_t, bool);
const char* get_privilege_string();
void update_histogram(reg_t pc);
const disassembler_t* get_disassembler() { return disassembler; }

Loading…
Cancel
Save