Strip down privileged modes. Only machine mode is supported
This commit is contained in:
parent
969b408288
commit
6f3963a473
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue