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); require(STATE.debug_mode);
set_pc_and_serialize(STATE.dpc->read()); set_pc_and_serialize(STATE.dpc->read());
p->set_privilege(STATE.dcsr->prv); p->set_privilege(STATE.dcsr->prv, STATE.dcsr->v);
p->set_virt(STATE.dcsr->v);
if (STATE.prv < PRV_M) if (STATE.prv < PRV_M)
STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_MPRV); 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); s = set_field(s, MNSTATUS_NMIE, 1);
STATE.mnstatus->write(s); STATE.mnstatus->write(s);
p->set_privilege(prev_prv); p->set_privilege(prev_prv, prev_virt);
p->set_virt(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_MPP, p->extension_enabled('U') ? PRV_U : PRV_M);
s = set_field(s, MSTATUS_MPV, 0); s = set_field(s, MSTATUS_MPV, 0);
p->put_csr(CSR_MSTATUS, s); p->put_csr(CSR_MSTATUS, s);
p->set_privilege(prev_prv); p->set_privilege(prev_prv, prev_virt);
p->set_virt(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)); STATE.mstatus->write(set_field(STATE.mstatus->read(), MSTATUS_MPRV, 0));
} }
p->set_privilege(prev_prv); p->set_privilege(prev_prv, prev_virt);
p->set_virt(prev_virt);

35
riscv/processor.cc

@ -714,11 +714,13 @@ reg_t processor_t::legalize_privilege(reg_t prv)
return prv; return prv;
} }
void processor_t::set_privilege(reg_t prv) void processor_t::set_privilege(reg_t prv, bool virt)
{ {
mmu->flush_tlb(); mmu->flush_tlb();
state.prev_prv = state.prv; state.prev_prv = state.prv;
state.prev_v = state.v;
state.prv = legalize_privilege(prv); state.prv = legalize_privilege(prv);
state.v = virt && state.prv != PRV_M;
} }
const char* processor_t::get_privilege_string() const char* processor_t::get_privilege_string()
@ -741,31 +743,11 @@ const char* processor_t::get_privilege_string()
abort(); 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) void processor_t::enter_debug_mode(uint8_t cause)
{ {
state.debug_mode = true; state.debug_mode = true;
state.dcsr->write_cause_and_prv(cause, state.prv, state.v); state.dcsr->write_cause_and_prv(cause, state.prv, state.v);
set_virt(false); set_privilege(PRV_M, false);
set_privilege(PRV_M);
state.dpc->write(state.pc); state.dpc->write(state.pc);
state.pc = DEBUG_ROM_ENTRY; state.pc = DEBUG_ROM_ENTRY;
in_wfi = false; 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_SPP, state.prv);
s = set_field(s, MSTATUS_SIE, 0); s = set_field(s, MSTATUS_SIE, 0);
state.sstatus->write(s); state.sstatus->write(s);
set_virt(true); set_privilege(PRV_S, true);
set_privilege(PRV_S);
} else if (state.prv <= PRV_S && bit < max_xlen && ((hsdeleg >> bit) & 1)) { } else if (state.prv <= PRV_S && bit < max_xlen && ((hsdeleg >> bit) & 1)) {
// Handle the trap in HS-mode // Handle the trap in HS-mode
reg_t vector = (state.nonvirtual_stvec->read() & 1) && interrupt ? 4 * bit : 0; 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()); s = set_field(s, HSTATUS_GVA, t.has_gva());
state.hstatus->write(s); state.hstatus->write(s);
} }
set_virt(false); set_privilege(PRV_S, false);
set_privilege(PRV_S);
} else { } else {
// Handle the trap in M-mode // Handle the trap in M-mode
const reg_t vector = (state.mtvec->read() & 1) && interrupt ? 4 * bit : 0; 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()); s = set_field(s, MSTATUS_GVA, t.has_gva());
state.mstatus->write(s); state.mstatus->write(s);
if (state.mstatush) state.mstatush->write(s >> 32); // log mstatush change if (state.mstatush) state.mstatush->write(s >> 32); // log mstatush change
set_virt(false); set_privilege(PRV_M, false);
set_privilege(PRV_M);
} }
} }

3
riscv/processor.h

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

Loading…
Cancel
Save