Encode VM type in sptbr, not mstatus
authorAndrew Waterman <andrew@sifive.com>
Wed, 8 Feb 2017 22:16:08 +0000 (14:16 -0800)
committerAndrew Waterman <andrew@sifive.com>
Wed, 8 Feb 2017 22:16:08 +0000 (14:16 -0800)
https://github.com/riscv/riscv-isa-manual/issues/4

Also, refactor gdbserver code to not duplicate VM decoding logic.

riscv/encoding.h
riscv/gdbserver.cc
riscv/gdbserver.h
riscv/mmu.cc
riscv/mmu.h
riscv/processor.cc

index 35e0f9fe05006a46704e40940cae1265d734913f..3ab9c6b49c3ad7ac8ca6aa9d15c80e17da52da11 100644 (file)
 #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
 
 #ifdef __riscv
 
-#ifdef __riscv64
+#if __riscv_xlen == 64
 # define MSTATUS_SD MSTATUS64_SD
 # define SSTATUS_SD SSTATUS64_SD
 # define RISCV_PGLEVEL_BITS 9
 #endif
 
 #endif
-/* Automatically generated by parse-opcodes */
+/* Automatically generated by parse-opcodes */
 #ifndef RISCV_ENCODING_H
 #define RISCV_ENCODING_H
 #define MATCH_BEQ 0x63
 #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
 #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
 #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
 #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
 #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)
index 79284ebf3fb5c2fbac3dd588e82d45df43cc5bc1..01defdaa43247210ba7949f9c914007374365800 100644 (file)
@@ -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);
index 79748b10adde35e8161093bfa5deabad579916d1..85842155ac3519f9d62c81bfb2ddb3d81fe41257 100644 (file)
@@ -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;
 
index 878d849d7ecaed30521bb8053a23389500743a2b..6162fd0db82c7d0ef318ee519611dec0d5ca835b 100644 (file)
@@ -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)
index 34bcf99be27b187946774ac5dd41aeb66b2bd21c..936545735ebe6cc83dd899d5c7735b89b0b69879 100644 (file)
@@ -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
index 9a6a4e27648232c37fd1309cfb6464ea406c8cc1..1883757cca09fc1c9453fbf6202f09b81070d9ef 100644 (file)
@@ -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;