From a30f1583002563aaae6a0e83c43300eaf81e646e Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 8 Feb 2017 14:16:08 -0800 Subject: [PATCH] Encode VM type in sptbr, not mstatus https://github.com/riscv/riscv-isa-manual/issues/4 Also, refactor gdbserver code to not duplicate VM decoding logic. --- riscv/encoding.h | 120 ++++++++++++++++++++++++++++++++++++++++++++- riscv/gdbserver.cc | 107 +++++++--------------------------------- riscv/gdbserver.h | 3 -- riscv/mmu.cc | 47 +++++++----------- riscv/mmu.h | 31 ++++++++++++ riscv/processor.cc | 21 +++----- 6 files changed, 192 insertions(+), 137 deletions(-) diff --git a/riscv/encoding.h b/riscv/encoding.h index 35e0f9f..3ab9c6b 100644 --- a/riscv/encoding.h +++ b/riscv/encoding.h @@ -114,6 +114,20 @@ #define VM_SV39 9 #define VM_SV48 10 +#define SPTBR32_MODE 0x80000000 +#define SPTBR32_ASID 0x7FC00000 +#define SPTBR32_PPN 0x003FFFFF +#define SPTBR64_MODE 0xE000000000000000 +#define SPTBR64_ASID 0x1FFFE00000000000 +#define SPTBR64_PPN 0x0000003FFFFFFFFF + +#define SPTBR_MODE_OFF 0 +#define SPTBR_MODE_SV32 1 +#define SPTBR_MODE_SV39 4 +#define SPTBR_MODE_SV48 5 +#define SPTBR_MODE_SV57 6 +#define SPTBR_MODE_SV64 7 + #define IRQ_S_SOFT 1 #define IRQ_H_SOFT 2 #define IRQ_M_SOFT 3 @@ -150,7 +164,7 @@ #ifdef __riscv -#ifdef __riscv64 +#if __riscv_xlen == 64 # define MSTATUS_SD MSTATUS64_SD # define SSTATUS_SD SSTATUS64_SD # define RISCV_PGLEVEL_BITS 9 @@ -208,7 +222,7 @@ #endif #endif -/* Automatically generated by parse-opcodes */ +/* Automatically generated by parse-opcodes. */ #ifndef RISCV_ENCODING_H #define RISCV_ENCODING_H #define MATCH_BEQ 0x63 @@ -457,6 +471,34 @@ #define MASK_FCVT_D_S 0xfff0007f #define MATCH_FSQRT_D 0x5a000053 #define MASK_FSQRT_D 0xfff0007f +#define MATCH_FADD_Q 0x6000053 +#define MASK_FADD_Q 0xfe00007f +#define MATCH_FSUB_Q 0xe000053 +#define MASK_FSUB_Q 0xfe00007f +#define MATCH_FMUL_Q 0x16000053 +#define MASK_FMUL_Q 0xfe00007f +#define MATCH_FDIV_Q 0x1e000053 +#define MASK_FDIV_Q 0xfe00007f +#define MATCH_FSGNJ_Q 0x26000053 +#define MASK_FSGNJ_Q 0xfe00707f +#define MATCH_FSGNJN_Q 0x26001053 +#define MASK_FSGNJN_Q 0xfe00707f +#define MATCH_FSGNJX_Q 0x26002053 +#define MASK_FSGNJX_Q 0xfe00707f +#define MATCH_FMIN_Q 0x2e000053 +#define MASK_FMIN_Q 0xfe00707f +#define MATCH_FMAX_Q 0x2e001053 +#define MASK_FMAX_Q 0xfe00707f +#define MATCH_FCVT_S_Q 0x40300053 +#define MASK_FCVT_S_Q 0xfff0007f +#define MATCH_FCVT_Q_S 0x46000053 +#define MASK_FCVT_Q_S 0xfff0007f +#define MATCH_FCVT_D_Q 0x42300053 +#define MASK_FCVT_D_Q 0xfff0007f +#define MATCH_FCVT_Q_D 0x46100053 +#define MASK_FCVT_Q_D 0xfff0007f +#define MATCH_FSQRT_Q 0x5e000053 +#define MASK_FSQRT_Q 0xfff0007f #define MATCH_FLE_S 0xa0000053 #define MASK_FLE_S 0xfe00707f #define MATCH_FLT_S 0xa0001053 @@ -469,6 +511,12 @@ #define MASK_FLT_D 0xfe00707f #define MATCH_FEQ_D 0xa2002053 #define MASK_FEQ_D 0xfe00707f +#define MATCH_FLE_Q 0xa6000053 +#define MASK_FLE_Q 0xfe00707f +#define MATCH_FLT_Q 0xa6001053 +#define MASK_FLT_Q 0xfe00707f +#define MATCH_FEQ_Q 0xa6002053 +#define MASK_FEQ_Q 0xfe00707f #define MATCH_FCVT_W_S 0xc0000053 #define MASK_FCVT_W_S 0xfff0007f #define MATCH_FCVT_WU_S 0xc0100053 @@ -493,6 +541,18 @@ #define MASK_FMV_X_D 0xfff0707f #define MATCH_FCLASS_D 0xe2001053 #define MASK_FCLASS_D 0xfff0707f +#define MATCH_FCVT_W_Q 0xc6000053 +#define MASK_FCVT_W_Q 0xfff0007f +#define MATCH_FCVT_WU_Q 0xc6100053 +#define MASK_FCVT_WU_Q 0xfff0007f +#define MATCH_FCVT_L_Q 0xc6200053 +#define MASK_FCVT_L_Q 0xfff0007f +#define MATCH_FCVT_LU_Q 0xc6300053 +#define MASK_FCVT_LU_Q 0xfff0007f +#define MATCH_FMV_X_Q 0xe6000053 +#define MASK_FMV_X_Q 0xfff0707f +#define MATCH_FCLASS_Q 0xe6001053 +#define MASK_FCLASS_Q 0xfff0707f #define MATCH_FCVT_S_W 0xd0000053 #define MASK_FCVT_S_W 0xfff0007f #define MATCH_FCVT_S_WU 0xd0100053 @@ -513,14 +573,28 @@ #define MASK_FCVT_D_LU 0xfff0007f #define MATCH_FMV_D_X 0xf2000053 #define MASK_FMV_D_X 0xfff0707f +#define MATCH_FCVT_Q_W 0xd6000053 +#define MASK_FCVT_Q_W 0xfff0007f +#define MATCH_FCVT_Q_WU 0xd6100053 +#define MASK_FCVT_Q_WU 0xfff0007f +#define MATCH_FCVT_Q_L 0xd6200053 +#define MASK_FCVT_Q_L 0xfff0007f +#define MATCH_FCVT_Q_LU 0xd6300053 +#define MASK_FCVT_Q_LU 0xfff0007f +#define MATCH_FMV_Q_X 0xf6000053 +#define MASK_FMV_Q_X 0xfff0707f #define MATCH_FLW 0x2007 #define MASK_FLW 0x707f #define MATCH_FLD 0x3007 #define MASK_FLD 0x707f +#define MATCH_FLQ 0x4007 +#define MASK_FLQ 0x707f #define MATCH_FSW 0x2027 #define MASK_FSW 0x707f #define MATCH_FSD 0x3027 #define MASK_FSD 0x707f +#define MATCH_FSQ 0x4027 +#define MASK_FSQ 0x707f #define MATCH_FMADD_S 0x43 #define MASK_FMADD_S 0x600007f #define MATCH_FMSUB_S 0x47 @@ -537,6 +611,14 @@ #define MASK_FNMSUB_D 0x600007f #define MATCH_FNMADD_D 0x200004f #define MASK_FNMADD_D 0x600007f +#define MATCH_FMADD_Q 0x6000043 +#define MASK_FMADD_Q 0x600007f +#define MATCH_FMSUB_Q 0x6000047 +#define MASK_FMSUB_Q 0x600007f +#define MATCH_FNMSUB_Q 0x600004b +#define MASK_FNMSUB_Q 0x600007f +#define MATCH_FNMADD_Q 0x600004f +#define MASK_FNMADD_Q 0x600007f #define MATCH_C_NOP 0x1 #define MASK_C_NOP 0xffff #define MATCH_C_ADDI16SP 0x6101 @@ -997,12 +1079,29 @@ DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fadd_q, MATCH_FADD_Q, MASK_FADD_Q) +DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q) +DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q) +DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q) +DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q) +DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q) +DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q) +DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q) +DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q) +DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q) +DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S) +DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q) +DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D) +DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q) DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q) +DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q) +DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q) DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) @@ -1015,6 +1114,12 @@ DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q) +DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q) +DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q) +DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q) +DECLARE_INSN(fmv_x_q, MATCH_FMV_X_Q, MASK_FMV_X_Q) +DECLARE_INSN(fclass_q, MATCH_FCLASS_Q, MASK_FCLASS_Q) DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) @@ -1025,10 +1130,17 @@ DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W) +DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU) +DECLARE_INSN(fcvt_q_l, MATCH_FCVT_Q_L, MASK_FCVT_Q_L) +DECLARE_INSN(fcvt_q_lu, MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU) +DECLARE_INSN(fmv_q_x, MATCH_FMV_Q_X, MASK_FMV_Q_X) DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(flq, MATCH_FLQ, MASK_FLQ) DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ) DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) @@ -1037,6 +1149,10 @@ DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q) +DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q) +DECLARE_INSN(fnmsub_q, MATCH_FNMSUB_Q, MASK_FNMSUB_Q) +DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q) DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) diff --git a/riscv/gdbserver.cc b/riscv/gdbserver.cc index 79284eb..01defda 100644 --- a/riscv/gdbserver.cc +++ b/riscv/gdbserver.cc @@ -987,40 +987,6 @@ class collect_translation_info_op_t : public operation_t bool perform_step(unsigned int step) { - unsigned int vm = gs.virtual_memory(); - - if (step == 0) { - switch (vm) { - case VM_MBARE: - // Nothing to be done. - return true; - - case VM_SV32: - levels = 2; - ptidxbits = 10; - ptesize = 4; - break; - case VM_SV39: - levels = 3; - ptidxbits = 9; - ptesize = 8; - break; - case VM_SV48: - levels = 4; - ptidxbits = 9; - ptesize = 8; - break; - - default: - { - char buf[100]; - sprintf(buf, "VM mode %d is not supported by gdbserver.cc.", vm); - die(buf); - return true; // die doesn't return, but gcc doesn't know that. - } - } - } - // Perform any reads from the just-completed action. switch (state) { case STATE_START: @@ -1028,9 +994,12 @@ class collect_translation_info_op_t : public operation_t case STATE_READ_SPTBR: gs.sptbr = gs.dr_read(SLOT_DATA0); gs.sptbr_valid = true; + vm = decode_vm_info(gs.xlen, gs.privilege_mode(), gs.sptbr); + if (vm.levels == 0) + return true; break; case STATE_READ_PTE: - if (ptesize == 4) { + if (vm.ptesize == 4) { gs.pte_cache[pte_addr] = gs.dr_read32(4); } else { gs.pte_cache[pte_addr] = ((uint64_t) gs.dr_read32(5) << 32) | @@ -1053,16 +1022,16 @@ class collect_translation_info_op_t : public operation_t return false; } - reg_t base = gs.sptbr << PGSHIFT; - int ptshift = (levels - 1) * ptidxbits; - for (unsigned int i = 0; i < levels; i++, ptshift -= ptidxbits) { - reg_t idx = (vaddr >> (PGSHIFT + ptshift)) & ((1 << ptidxbits) - 1); + reg_t base = vm.ptbase; + for (int i = vm.levels - 1; i >= 0; i--) { + int ptshift = i * vm.idxbits; + reg_t idx = (vaddr >> (PGSHIFT + ptshift)) & ((1 << vm.idxbits) - 1); - pte_addr = base + idx * ptesize; + pte_addr = base + idx * vm.ptesize; auto it = gs.pte_cache.find(pte_addr); if (it == gs.pte_cache.end()) { state = STATE_READ_PTE; - if (ptesize == 4) { + if (vm.ptesize == 4) { gs.dr_write32(0, lw(S0, 0, (uint16_t) DEBUG_RAM_START + 16)); gs.dr_write32(1, lw(S1, S0, 0)); gs.dr_write32(2, sw(S1, 0, (uint16_t) DEBUG_RAM_START + 16)); @@ -1103,9 +1072,7 @@ class collect_translation_info_op_t : public operation_t } state; reg_t vaddr; size_t length; - unsigned int levels; - unsigned int ptidxbits; - unsigned int ptesize; + vm_info vm; reg_t pte_addr; }; @@ -1351,46 +1318,18 @@ unsigned int gdbserver_t::find_access_size(reg_t address, int length) reg_t gdbserver_t::translate(reg_t vaddr) { - unsigned int vm = virtual_memory(); - unsigned int levels, ptidxbits, ptesize; - - switch (vm) { - case VM_MBARE: - return vaddr; - - case VM_SV32: - levels = 2; - ptidxbits = 10; - ptesize = 4; - break; - case VM_SV39: - levels = 3; - ptidxbits = 9; - ptesize = 8; - break; - case VM_SV48: - levels = 4; - ptidxbits = 9; - ptesize = 8; - break; - - default: - { - char buf[100]; - sprintf(buf, "VM mode %d is not supported by gdbserver.cc.", vm); - die(buf); - return true; // die doesn't return, but gcc doesn't know that. - } - } + vm_info vm = decode_vm_info(xlen, privilege_mode(), sptbr); + if (vm.levels == 0) + return vaddr; // Handle page tables here. There's a bunch of duplicated code with // collect_translation_info_op_t. :-( - reg_t base = sptbr << PGSHIFT; - int ptshift = (levels - 1) * ptidxbits; - for (unsigned int i = 0; i < levels; i++, ptshift -= ptidxbits) { - reg_t idx = (vaddr >> (PGSHIFT + ptshift)) & ((1 << ptidxbits) - 1); + reg_t base = vm.ptbase; + for (int i = vm.levels - 1; i >= 0; i--) { + int ptshift = i * vm.idxbits; + reg_t idx = (vaddr >> (PGSHIFT + ptshift)) & ((1 << vm.idxbits) - 1); - reg_t pte_addr = base + idx * ptesize; + reg_t pte_addr = base + idx * vm.ptesize; auto it = pte_cache.find(pte_addr); if (it == pte_cache.end()) { fprintf(stderr, "ERROR: gdbserver tried to translate 0x%016" PRIx64 @@ -1427,14 +1366,6 @@ unsigned int gdbserver_t::privilege_mode() return mode; } -unsigned int gdbserver_t::virtual_memory() -{ - unsigned int mode = privilege_mode(); - if (mode == PRV_M) - return VM_MBARE; - return get_field(mstatus, MSTATUS_VM); -} - void gdbserver_t::dr_write32(unsigned int index, uint32_t value) { sim->debug_module.ram_write32(index, value); diff --git a/riscv/gdbserver.h b/riscv/gdbserver.h index 79748b1..8584215 100644 --- a/riscv/gdbserver.h +++ b/riscv/gdbserver.h @@ -230,9 +230,6 @@ public: // Return the PRV_x that is used when the code under debug performs a memory // access. unsigned int privilege_mode(); - // Return the VM_x that is used when the code under debug performs a memory - // access. - unsigned int virtual_memory(); unsigned int xlen; diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 878d849..6162fd0 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -43,13 +43,7 @@ reg_t mmu_t::translate(reg_t addr, access_type type) if (!proc->state.dcsr.cause && get_field(proc->state.mstatus, MSTATUS_MPRV)) mode = get_field(proc->state.mstatus, MSTATUS_MPP); } - if (get_field(proc->state.mstatus, MSTATUS_VM) == VM_MBARE) - mode = PRV_M; - if (mode == PRV_M) { - reg_t msb_mask = (reg_t(2) << (proc->xlen-1))-1; // zero-extend from xlen - return addr & msb_mask; - } return walk(addr, type, mode) | (addr & (PGSIZE-1)); } @@ -57,12 +51,6 @@ const uint16_t* mmu_t::fetch_slow_path(reg_t vaddr) { reg_t paddr = translate(vaddr, FETCH); - // mmu_t::walk() returns -1 if it can't find a match. Of course -1 could also - // be a valid address. - if (paddr == ~(reg_t) 0 && vaddr != ~(reg_t) 0) { - throw trap_instruction_access_fault(vaddr); - } - if (sim->addr_is_mem(paddr)) { refill_tlb(vaddr, paddr, FETCH); return (const uint16_t*)sim->addr_to_mem(paddr); @@ -169,38 +157,33 @@ void mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, access_type type) reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode) { - int levels, ptidxbits, ptesize; - switch (get_field(proc->get_state()->mstatus, MSTATUS_VM)) - { - case VM_SV32: levels = 2; ptidxbits = 10; ptesize = 4; break; - case VM_SV39: levels = 3; ptidxbits = 9; ptesize = 8; break; - case VM_SV48: levels = 4; ptidxbits = 9; ptesize = 8; break; - default: abort(); - } + vm_info vm = decode_vm_info(proc->max_xlen, mode, proc->get_state()->sptbr); + if (vm.levels == 0) + return addr & ((reg_t(2) << (proc->xlen-1))-1); // zero-extend from xlen bool supervisor = mode == PRV_S; bool pum = get_field(proc->state.mstatus, MSTATUS_PUM); bool mxr = get_field(proc->state.mstatus, MSTATUS_MXR); // verify bits xlen-1:va_bits-1 are all equal - int va_bits = PGSHIFT + levels * ptidxbits; + int va_bits = PGSHIFT + vm.levels * vm.idxbits; reg_t mask = (reg_t(1) << (proc->xlen - (va_bits-1))) - 1; reg_t masked_msbs = (addr >> (va_bits-1)) & mask; if (masked_msbs != 0 && masked_msbs != mask) - return -1; + vm.levels = 0; - reg_t base = proc->get_state()->sptbr << PGSHIFT; - int ptshift = (levels - 1) * ptidxbits; - for (int i = 0; i < levels; i++, ptshift -= ptidxbits) { - reg_t idx = (addr >> (PGSHIFT + ptshift)) & ((1 << ptidxbits) - 1); + reg_t base = vm.ptbase; + for (int i = vm.levels - 1; i >= 0; i--) { + int ptshift = i * vm.idxbits; + reg_t idx = (addr >> (PGSHIFT + ptshift)) & ((1 << vm.idxbits) - 1); // check that physical address of PTE is legal - reg_t pte_addr = base + idx * ptesize; + reg_t pte_addr = base + idx * vm.ptesize; if (!sim->addr_is_mem(pte_addr)) break; void* ppte = sim->addr_to_mem(pte_addr); - reg_t pte = ptesize == 4 ? *(uint32_t*)ppte : *(uint64_t*)ppte; + reg_t pte = vm.ptesize == 4 ? *(uint32_t*)ppte : *(uint64_t*)ppte; reg_t ppn = pte >> PTE_PPN_SHIFT; if (PTE_TABLE(pte)) { // next level of page table @@ -223,7 +206,13 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode) } } - return -1; +fail: + switch (type) { + case FETCH: throw trap_instruction_access_fault(addr); + case LOAD: throw trap_load_access_fault(addr); + case STORE: throw trap_store_access_fault(addr); + default: abort(); + } } void mmu_t::register_memtracer(memtracer_t* t) diff --git a/riscv/mmu.h b/riscv/mmu.h index 34bcf99..9365457 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -260,4 +260,35 @@ private: friend class processor_t; }; +struct vm_info { + int levels; + int idxbits; + int ptesize; + reg_t ptbase; +}; + +inline vm_info decode_vm_info(int xlen, reg_t prv, reg_t sptbr) +{ + if (prv == PRV_M) { + return {0, 0, 0, 0}; + } else if (prv <= PRV_S && xlen == 32) { + switch (get_field(sptbr, SPTBR32_MODE)) { + case SPTBR_MODE_OFF: return {0, 0, 0, 0}; + case SPTBR_MODE_SV32: return {2, 10, 4, (sptbr & SPTBR32_PPN) << PGSHIFT}; + default: abort(); + } + } else if (prv <= PRV_S && xlen == 64) { + switch (get_field(sptbr, SPTBR64_MODE)) { + case SPTBR_MODE_OFF: return {0, 0, 0, 0}; + case SPTBR_MODE_SV39: return {3, 9, 8, (sptbr & SPTBR64_PPN) << PGSHIFT}; + case SPTBR_MODE_SV48: return {4, 9, 8, (sptbr & SPTBR64_PPN) << PGSHIFT}; + case SPTBR_MODE_SV57: return {5, 9, 8, (sptbr & SPTBR64_PPN) << PGSHIFT}; + case SPTBR_MODE_SV64: return {6, 9, 8, (sptbr & SPTBR64_PPN) << PGSHIFT}; + default: abort(); + } + } else { + abort(); + } +} + #endif diff --git a/riscv/processor.cc b/riscv/processor.cc index 9a6a4e2..1883757 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -264,15 +264,6 @@ void processor_t::disasm(insn_t insn) id, state.pc, bits, disassembler->disassemble(insn).c_str()); } -static bool validate_vm(int max_xlen, reg_t vm) -{ - if (max_xlen == 64 && (vm == VM_SV39 || vm == VM_SV48)) - return true; - if (max_xlen == 32 && vm == VM_SV32) - return true; - return vm == VM_MBARE; -} - int processor_t::paddr_bits() { assert(xlen == max_xlen); @@ -301,16 +292,13 @@ void processor_t::set_csr(int which, reg_t val) break; case CSR_MSTATUS: { if ((val ^ state.mstatus) & - (MSTATUS_VM | MSTATUS_MPP | MSTATUS_MPRV | MSTATUS_PUM | MSTATUS_MXR)) + (MSTATUS_MPP | MSTATUS_MPRV | MSTATUS_PUM | MSTATUS_MXR)) mmu->flush_tlb(); reg_t mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE | MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_PUM | MSTATUS_MPP | MSTATUS_MXR | (ext ? MSTATUS_XS : 0); - if (validate_vm(max_xlen, get_field(val, MSTATUS_VM))) - mask |= MSTATUS_VM; - state.mstatus = (state.mstatus & ~mask) | (val & mask); bool dirty = (state.mstatus & MSTATUS_FS) == MSTATUS_FS; @@ -374,8 +362,11 @@ void processor_t::set_csr(int which, reg_t val) return set_csr(CSR_MIE, (state.mie & ~state.mideleg) | (val & state.mideleg)); case CSR_SPTBR: { - // upper bits of sptbr are the ASID; we only support ASID = 0 - state.sptbr = val & (((reg_t)1 << (paddr_bits() - PGSHIFT)) - 1); + if (max_xlen == 32) + state.sptbr = val & (SPTBR32_PPN | SPTBR32_MODE); + if (max_xlen == 64 && (get_field(val, SPTBR64_MODE) == SPTBR_MODE_OFF || + get_field(val, SPTBR64_MODE) >= SPTBR_MODE_SV39)) + state.sptbr = val & (SPTBR64_PPN | SPTBR64_MODE); break; } case CSR_SEPC: state.sepc = val; break; -- 2.30.2