Strip down privileged modes. Only machine mode is supported

This commit is contained in:
Stanislaw Kaushanski 2020-09-07 11:54:45 +02:00
parent 969b408288
commit 6f3963a473
1 changed files with 40 additions and 213 deletions

View File

@ -174,8 +174,6 @@ enum riscv_csr {
namespace { namespace {
std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
std::array<const char *, 16> trap_str = {{"" std::array<const char *, 16> trap_str = {{""
"Instruction address misaligned", // 0 "Instruction address misaligned", // 0
"Instruction access fault", // 1 "Instruction access fault", // 1
@ -326,8 +324,8 @@ public:
static const reg_t mstatus_reset_val = 0; static const reg_t mstatus_reset_val = 0;
void write_mstatus(T val, unsigned priv_lvl) { void write_mstatus(T val) {
auto mask = get_mask(priv_lvl); auto mask = get_mask();
auto new_val = (mstatus.st.value & ~mask) | (val & mask); auto new_val = (mstatus.st.value & ~mask) | (val & mask);
mstatus = new_val; mstatus = new_val;
} }
@ -336,41 +334,19 @@ public:
static constexpr T get_misa() { return (1UL << 30) | ISA_I | ISA_M | ISA_A | ISA_U | ISA_S | ISA_M; } static constexpr T get_misa() { return (1UL << 30) | ISA_I | ISA_M | ISA_A | ISA_U | ISA_S | ISA_M; }
static constexpr uint32_t get_mask(unsigned priv_lvl) { static constexpr uint32_t get_mask() {
#if __cplusplus < 201402L return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011 // only machine mode is supported
return priv_lvl == PRIV_U ? 0x80000011UL : priv_lvl == PRIV_S ? 0x800de133UL : 0x807ff9ddUL;
#else
switch (priv_lvl) {
case PRIV_U: return 0x80000011UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001
case PRIV_S: return 0x800de133UL; // 0b1000 0000 0000 1101 1110 0001 0011 0011
default: return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011
}
#endif
} }
static inline vm_info decode_vm_info(uint32_t state, T sptbr) { static inline vm_info decode_vm_info() {
if (state == PRIV_M) return {0, 0, 0, 0}; return {0, 0, 0, 0};
if (state <= PRIV_S)
switch (bit_sub<31, 1>(sptbr)) {
case 0: return {0, 0, 0, 0}; // off
case 1: return {2, 10, 4, bit_sub<0, 22>(sptbr) << PGSHIFT}; // SV32
default: abort();
}
abort();
return {0, 0, 0, 0}; // dummy
} }
}; };
const typename super::reg_t PGSIZE = 1 << PGSHIFT; const typename super::reg_t PGSIZE = 1 << PGSHIFT;
const typename super::reg_t PGMASK = PGSIZE - 1; const typename super::reg_t PGMASK = PGSIZE - 1;
constexpr reg_t get_irq_mask(size_t mode) { constexpr reg_t get_irq_mask() {
std::array<const reg_t, 4> m = {{ return 0b101110111011; // only machine mode is supported
0b000100010001, // U mode
0b001100110011, // S mode
0,
0b101110111011 // M mode
}};
return m[mode];
} }
riscv_hart_m_p(); riscv_hart_m_p();
@ -396,8 +372,8 @@ public:
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; }; void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
void disass_output(uint64_t pc, const std::string instr) override { void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]",
pc, instr, lvl[this->reg.machine_state], (reg_t)state.mstatus, this->reg.icount); pc, instr, (reg_t)state.mstatus, this->reg.icount);
}; };
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; } iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
@ -497,22 +473,10 @@ riscv_hart_m_p<BASE>::riscv_hart_m_p()
csr_rd_cb[minstreth] = &riscv_hart_m_p<BASE>::read_cycle; csr_rd_cb[minstreth] = &riscv_hart_m_p<BASE>::read_cycle;
csr_rd_cb[mstatus] = &riscv_hart_m_p<BASE>::read_status; csr_rd_cb[mstatus] = &riscv_hart_m_p<BASE>::read_status;
csr_wr_cb[mstatus] = &riscv_hart_m_p<BASE>::write_status; csr_wr_cb[mstatus] = &riscv_hart_m_p<BASE>::write_status;
csr_rd_cb[sstatus] = &riscv_hart_m_p<BASE>::read_status;
csr_wr_cb[sstatus] = &riscv_hart_m_p<BASE>::write_status;
csr_rd_cb[ustatus] = &riscv_hart_m_p<BASE>::read_status;
csr_wr_cb[ustatus] = &riscv_hart_m_p<BASE>::write_status;
csr_rd_cb[mip] = &riscv_hart_m_p<BASE>::read_ip; csr_rd_cb[mip] = &riscv_hart_m_p<BASE>::read_ip;
csr_wr_cb[mip] = &riscv_hart_m_p<BASE>::write_ip; csr_wr_cb[mip] = &riscv_hart_m_p<BASE>::write_ip;
csr_rd_cb[sip] = &riscv_hart_m_p<BASE>::read_ip;
csr_wr_cb[sip] = &riscv_hart_m_p<BASE>::write_ip;
csr_rd_cb[uip] = &riscv_hart_m_p<BASE>::read_ip;
csr_wr_cb[uip] = &riscv_hart_m_p<BASE>::write_ip;
csr_rd_cb[mie] = &riscv_hart_m_p<BASE>::read_ie; csr_rd_cb[mie] = &riscv_hart_m_p<BASE>::read_ie;
csr_wr_cb[mie] = &riscv_hart_m_p<BASE>::write_ie; csr_wr_cb[mie] = &riscv_hart_m_p<BASE>::write_ie;
csr_rd_cb[sie] = &riscv_hart_m_p<BASE>::read_ie;
csr_wr_cb[sie] = &riscv_hart_m_p<BASE>::write_ie;
csr_rd_cb[uie] = &riscv_hart_m_p<BASE>::read_ie;
csr_wr_cb[uie] = &riscv_hart_m_p<BASE>::write_ie;
csr_rd_cb[mhartid] = &riscv_hart_m_p<BASE>::read_hartid; csr_rd_cb[mhartid] = &riscv_hart_m_p<BASE>::read_hartid;
} }
@ -583,7 +547,7 @@ iss::status riscv_hart_m_p<BASE>::read(const address_type type, const access_typ
} }
try { try {
if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary
vm_info vm = hart_state<reg_t>::decode_vm_info(this->reg.machine_state, state.satp); vm_info vm = hart_state<reg_t>::decode_vm_info();
if (vm.levels != 0) { // VM is active if (vm.levels != 0) { // VM is active
auto split_addr = (addr + length) & ~PGMASK; auto split_addr = (addr + length) & ~PGMASK;
auto len1 = split_addr - addr; auto len1 = split_addr - addr;
@ -609,18 +573,7 @@ iss::status riscv_hart_m_p<BASE>::read(const address_type type, const access_typ
} break; } break;
case traits<BASE>::FENCE: { case traits<BASE>::FENCE: {
if ((addr + length) > mem.size()) return iss::Err; if ((addr + length) > mem.size()) return iss::Err;
switch (addr) { return iss::Ok;
case 2: // SFENCE:VMA lower
case 3: { // SFENCE:VMA upper
auto tvm = state.mstatus.TVM;
if (this->reg.machine_state == PRIV_S & tvm != 0) {
this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC;
return iss::Err;
}
return iss::Ok;
}
}
} break; } break;
case traits<BASE>::RES: { case traits<BASE>::RES: {
auto it = atomic_reservation.find(addr); auto it = atomic_reservation.find(addr);
@ -677,7 +630,7 @@ iss::status riscv_hart_m_p<BASE>::write(const address_type type, const access_ty
} }
try { try {
if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary
vm_info vm = hart_state<reg_t>::decode_vm_info(this->reg.machine_state, state.satp); vm_info vm = hart_state<reg_t>::decode_vm_info();
if (vm.levels != 0) { // VM is active if (vm.levels != 0) { // VM is active
auto split_addr = (addr + length) & ~PGMASK; auto split_addr = (addr + length) & ~PGMASK;
auto len1 = split_addr - addr; auto len1 = split_addr - addr;
@ -741,11 +694,6 @@ iss::status riscv_hart_m_p<BASE>::write(const address_type type, const access_ty
case 3: { case 3: {
ptw.clear(); ptw.clear();
auto tvm = state.mstatus.TVM; auto tvm = state.mstatus.TVM;
if (this->reg.machine_state == PRIV_S & tvm != 0) {
this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC;
return iss::Err;
}
return iss::Ok; return iss::Ok;
} }
} }
@ -817,14 +765,12 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned ad
} }
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_status(unsigned addr, reg_t &val) { template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_status(unsigned addr, reg_t &val) {
auto req_priv_lvl = (addr >> 8) & 0x3; val = state.mstatus & hart_state<reg_t>::get_mask();
val = state.mstatus & hart_state<reg_t>::get_mask(req_priv_lvl);
return iss::Ok; return iss::Ok;
} }
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_status(unsigned addr, reg_t val) { template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_status(unsigned addr, reg_t val) {
auto req_priv_lvl = (addr >> 8) & 0x3; state.write_mstatus(val);
state.write_mstatus(val, req_priv_lvl);
check_interrupt(); check_interrupt();
update_vm_info(); update_vm_info();
return iss::Ok; return iss::Ok;
@ -832,8 +778,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_status(unsigned
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ie(unsigned addr, reg_t &val) { template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ie(unsigned addr, reg_t &val) {
val = csr[mie]; val = csr[mie];
if (addr < mie) val &= csr[mideleg]; val &= csr[mideleg];
if (addr < sie) val &= csr[sideleg];
return iss::Ok; return iss::Ok;
} }
@ -843,8 +788,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_hartid(unsigned
} }
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ie(unsigned addr, reg_t val) { template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ie(unsigned addr, reg_t val) {
auto req_priv_lvl = (addr >> 8) & 0x3; auto mask = get_irq_mask();
auto mask = get_irq_mask(req_priv_lvl);
csr[mie] = (csr[mie] & ~mask) | (val & mask); csr[mie] = (csr[mie] & ~mask) | (val & mask);
check_interrupt(); check_interrupt();
return iss::Ok; return iss::Ok;
@ -852,76 +796,18 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ie(unsigned add
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ip(unsigned addr, reg_t &val) { template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ip(unsigned addr, reg_t &val) {
val = csr[mip]; val = csr[mip];
if (addr < mip) val &= csr[mideleg]; val &= csr[mideleg];
if (addr < sip) val &= csr[sideleg];
return iss::Ok; return iss::Ok;
} }
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ip(unsigned addr, reg_t val) { template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ip(unsigned addr, reg_t val) {
auto req_priv_lvl = (addr >> 8) & 0x3; auto mask = get_irq_mask();
auto mask = get_irq_mask(req_priv_lvl);
mask &= ~(1 << 7); // MTIP is read only mask &= ~(1 << 7); // MTIP is read only
csr[mip] = (csr[mip] & ~mask) | (val & mask); csr[mip] = (csr[mip] & ~mask) | (val & mask);
check_interrupt(); check_interrupt();
return iss::Ok; return iss::Ok;
} }
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_satp(unsigned addr, reg_t &val) {
reg_t tvm = state.mstatus.TVM;
if (this->reg.machine_state == PRIV_S & tvm != 0) {
this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC;
return iss::Err;
}
val = state.satp;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_satp(unsigned addr, reg_t val) {
reg_t tvm = state.mstatus.TVM;
if (this->reg.machine_state == PRIV_S & tvm != 0) {
this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC;
return iss::Err;
}
state.satp = val;
update_vm_info();
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_fcsr(unsigned addr, reg_t &val) {
switch (addr) {
case 1: // fflags, 4:0
val = bit_sub<0, 5>(this->get_fcsr());
break;
case 2: // frm, 7:5
val = bit_sub<5, 3>(this->get_fcsr());
break;
case 3: // fcsr
val = this->get_fcsr();
break;
default:
return iss::Err;
}
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_fcsr(unsigned addr, reg_t val) {
switch (addr) {
case 1: // fflags, 4:0
this->set_fcsr((this->get_fcsr() & 0xffffffe0) | (val & 0x1f));
break;
case 2: // frm, 7:5
this->set_fcsr((this->get_fcsr() & 0xffffff1f) | ((val & 0x7) << 5));
break;
case 3: // fcsr
this->set_fcsr(val & 0xff);
break;
default:
return iss::Err;
}
return iss::Ok;
}
template <typename BASE> template <typename BASE>
iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
if ((paddr.val + length) > mem.size()) return iss::Err; if ((paddr.val + length) > mem.size()) return iss::Err;
@ -1032,10 +918,10 @@ template <typename BASE> inline void riscv_hart_m_p<BASE>::reset(uint64_t addres
} }
template <typename BASE> inline void riscv_hart_m_p<BASE>::update_vm_info() { template <typename BASE> inline void riscv_hart_m_p<BASE>::update_vm_info() {
vm[1] = hart_state<reg_t>::decode_vm_info(this->reg.machine_state, state.satp); vm[1] = hart_state<reg_t>::decode_vm_info();
BASE::addr_mode[3]=BASE::addr_mode[2] = vm[1].is_active()? iss::address_type::VIRTUAL : iss::address_type::PHYSICAL; BASE::addr_mode[3]=BASE::addr_mode[2] = vm[1].is_active()? iss::address_type::VIRTUAL : iss::address_type::PHYSICAL;
if (state.mstatus.MPRV) if (state.mstatus.MPRV)
vm[0] = hart_state<reg_t>::decode_vm_info(state.mstatus.MPP, state.satp); vm[0] = hart_state<reg_t>::decode_vm_info();
else else
vm[0] = vm[1]; vm[0] = vm[1];
BASE::addr_mode[1] = BASE::addr_mode[0]=vm[0].is_active() ? iss::address_type::VIRTUAL : iss::address_type::PHYSICAL; BASE::addr_mode[1] = BASE::addr_mode[0]=vm[0].is_active() ? iss::address_type::VIRTUAL : iss::address_type::PHYSICAL;
@ -1057,11 +943,6 @@ template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() {
auto m_enabled = this->reg.machine_state < PRIV_M || (this->reg.machine_state == PRIV_M && mie); auto m_enabled = this->reg.machine_state < PRIV_M || (this->reg.machine_state == PRIV_M && mie);
auto enabled_interrupts = m_enabled ? ena_irq & ~ideleg : 0; auto enabled_interrupts = m_enabled ? ena_irq & ~ideleg : 0;
if (enabled_interrupts == 0) {
auto sie = state.mstatus.SIE;
auto s_enabled = this->reg.machine_state < PRIV_S || (this->reg.machine_state == PRIV_S && sie);
enabled_interrupts = s_enabled ? ena_irq & ideleg : 0;
}
if (enabled_interrupts != 0) { if (enabled_interrupts != 0) {
int res = 0; int res = 0;
while ((enabled_interrupts & 1) == 0) enabled_interrupts >>= 1, res++; while ((enabled_interrupts & 1) == 0) enabled_interrupts >>= 1, res++;
@ -1094,7 +975,6 @@ typename riscv_hart_m_p<BASE>::phys_addr_t riscv_hart_m_p<BASE>::virt2phys(const
const vm_info &vm = this->vm[static_cast<uint16_t>(type) / 2]; const vm_info &vm = this->vm[static_cast<uint16_t>(type) / 2];
const bool s_mode = mode == PRIV_S;
const bool sum = state.mstatus.SUM; const bool sum = state.mstatus.SUM;
const bool mxr = state.mstatus.MXR; const bool mxr = state.mstatus.MXR;
@ -1118,7 +998,7 @@ typename riscv_hart_m_p<BASE>::phys_addr_t riscv_hart_m_p<BASE>::virt2phys(const
if (PTE_TABLE(pte)) { // next level of page table if (PTE_TABLE(pte)) { // next level of page table
base = ppn << PGSHIFT; base = ppn << PGSHIFT;
} else if ((pte & PTE_U) ? s_mode && (type == iss::access_type::FETCH || !sum) : !s_mode) { } else if (!(pte & PTE_U)) {
break; break;
} else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { } else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) {
break; break;
@ -1163,36 +1043,22 @@ typename riscv_hart_m_p<BASE>::phys_addr_t riscv_hart_m_p<BASE>::virt2phys(const
} }
template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flags, uint64_t addr) { template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flags, uint64_t addr) {
auto cur_priv = this->reg.machine_state;
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0] // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
// calculate and write mcause val // calculate and write mcause val
auto trap_id = bit_sub<0, 16>(flags); auto trap_id = bit_sub<0, 16>(flags);
auto cause = bit_sub<16, 15>(flags); auto cause = bit_sub<16, 15>(flags);
if (trap_id == 0 && cause == 11) cause = 0x8 + cur_priv; // adjust environment call cause if (trap_id == 0 && cause == 11) cause = 0x8 + PRIV_M; // adjust environment call cause
// calculate effective privilege level // calculate effective privilege level
auto new_priv = PRIV_M;
if (trap_id == 0) { // exception if (trap_id == 0) { // exception
if (cur_priv != PRIV_M && ((csr[medeleg] >> cause) & 0x1) != 0)
new_priv = (csr[sedeleg] >> cause) & 0x1 ? PRIV_U : PRIV_S;
// store ret addr in xepc register // store ret addr in xepc register
csr[uepc | (new_priv << 8)] = static_cast<reg_t>(addr); // store actual address instruction of exception csr[mepc] = static_cast<reg_t>(addr); // store actual address instruction of exception
/* csr[mtval] = fault_data;
* write mtval if new_priv=M_MODE, spec says:
* When a hardware breakpoint is triggered, or an instruction-fetch, load,
* or store address-misaligned,
* access, or page-fault exception occurs, mtval is written with the
* faulting effective address.
*/
csr[utval | (new_priv << 8)] = fault_data;
fault_data = 0; fault_data = 0;
} else { } else {
if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0) csr[mepc] = this->reg.NEXT_PC; // store next address if interrupt
new_priv = (csr[sideleg] >> cause) & 0x1 ? PRIV_U : PRIV_S;
csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt
this->reg.pending_trap = 0; this->reg.pending_trap = 0;
} }
size_t adr = ucause | (new_priv << 8); csr[mcause] = (trap_id << 31) + cause;
csr[adr] = (trap_id << 31) + cause;
// update mstatus // update mstatus
// xPP field of mstatus is written with the active privilege mode at the time // xPP field of mstatus is written with the active privilege mode at the time
// of the trap; the x PIE field of mstatus // of the trap; the x PIE field of mstatus
@ -1200,41 +1066,25 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flag
// the trap; and the x IE field of mstatus // the trap; and the x IE field of mstatus
// is cleared // is cleared
// store the actual privilege level in yPP and store interrupt enable flags // store the actual privilege level in yPP and store interrupt enable flags
switch (new_priv) { state.mstatus.MPP = PRIV_M;
case PRIV_M: state.mstatus.MPIE = state.mstatus.MIE;
state.mstatus.MPP = cur_priv; state.mstatus.MIE = false;
state.mstatus.MPIE = state.mstatus.MIE;
state.mstatus.MIE = false;
break;
case PRIV_S:
state.mstatus.SPP = cur_priv;
state.mstatus.SPIE = state.mstatus.SIE;
state.mstatus.SIE = false;
break;
case PRIV_U:
state.mstatus.UPIE = state.mstatus.UIE;
state.mstatus.UIE = false;
break;
default:
break;
}
// get trap vector // get trap vector
auto ivec = csr[utvec | (new_priv << 8)]; auto ivec = csr[mtvec];
// calculate addr// set NEXT_PC to trap addressess to jump to based on MODE // calculate addr// set NEXT_PC to trap addressess to jump to based on MODE
// bits in mtvec // bits in mtvec
this->reg.NEXT_PC = ivec & ~0x1UL; this->reg.NEXT_PC = ivec & ~0x1UL;
if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause; if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
// reset trap state // reset trap state
this->reg.machine_state = new_priv; this->reg.machine_state = PRIV_M;
this->reg.trap_state = 0; this->reg.trap_state = 0;
std::array<char, 32> buffer; std::array<char, 32> buffer;
sprintf(buffer.data(), "0x%016lx", addr); sprintf(buffer.data(), "0x%016lx", addr);
if((flags&0xffffffff) != 0xffffffff) if((flags&0xffffffff) != 0xffffffff)
CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '"
<< (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" << cause << ")" << (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" << cause << ")"
<< " at address " << buffer.data() << " occurred, changing privilege level from " << " at address " << buffer.data() << " occurred";
<< lvl[cur_priv] << " to " << lvl[new_priv];
update_vm_info(); update_vm_info();
return this->reg.NEXT_PC; return this->reg.NEXT_PC;
} }
@ -1244,47 +1094,24 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::leave_trap(uint64_t flag
auto inst_priv = flags & 0x3; auto inst_priv = flags & 0x3;
auto status = state.mstatus; auto status = state.mstatus;
auto tsr = state.mstatus.TSR;
if (cur_priv == PRIV_S && inst_priv == PRIV_S && tsr != 0) {
this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC;
return this->reg.PC;
}
// pop the relevant lower-privilege interrupt enable and privilege mode stack // pop the relevant lower-privilege interrupt enable and privilege mode stack
// clear respective yIE // clear respective yIE
switch (inst_priv) { if (inst_priv == PRIV_M) {
case PRIV_M:
this->reg.machine_state = state.mstatus.MPP; this->reg.machine_state = state.mstatus.MPP;
state.mstatus.MPP = 0; // clear mpp to U mode state.mstatus.MPP = 0; // clear mpp to U mode
state.mstatus.MIE = state.mstatus.MPIE; state.mstatus.MIE = state.mstatus.MPIE;
break; } else {
case PRIV_S: CLOG(ERROR, disass) << "Unsupported mode:" << inst_priv;
this->reg.machine_state = state.mstatus.SPP;
state.mstatus.SPP = 0; // clear spp to U mode
state.mstatus.SIE = state.mstatus.SPIE;
break;
case PRIV_U:
this->reg.machine_state = 0;
state.mstatus.UIE = state.mstatus.UPIE;
break;
} }
// sets the pc to the value stored in the x epc register. // sets the pc to the value stored in the x epc register.
this->reg.NEXT_PC = csr[uepc | inst_priv << 8]; this->reg.NEXT_PC = csr[mepc];
CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to " CLOG(INFO, disass) << "Executing xRET";
<< lvl[this->reg.machine_state];
update_vm_info(); update_vm_info();
return this->reg.NEXT_PC; return this->reg.NEXT_PC;
} }
template <typename BASE> void riscv_hart_m_p<BASE>::wait_until(uint64_t flags) { template <typename BASE> void riscv_hart_m_p<BASE>::wait_until(uint64_t flags) {}
auto status = state.mstatus;
auto tw = status.TW;
if (this->reg.machine_state == PRIV_S && tw != 0) {
this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC;
}
}
} // namespace arch } // namespace arch
} // namespace iss } // namespace iss