Add support for virtual priv register. (#59)
authorTim Newsome <tim@sifive.com>
Thu, 28 Jul 2016 21:51:31 +0000 (14:51 -0700)
committerAndrew Waterman <waterman@eecs.berkeley.edu>
Thu, 28 Jul 2016 21:51:31 +0000 (14:51 -0700)
Users can use this register to inspect and change the privilege level of
the core. It doesn't make any assumptions about the actual underlying
debug mechanism (as opposed to having the user change DCSR directly,
which may not exist in all debug implementations).

riscv/gdbserver.cc
riscv/gdbserver.h
riscv/insns/dret.h
riscv/processor.cc
riscv/processor.h

index 4b8988e3f75df64b5e01cbcf91cccfeba75c835a..c561390b10556a3e0169022bebf337edf4a31de8 100644 (file)
@@ -29,8 +29,6 @@
 #  define D(x)
 #endif // DEBUG
 
-const int debug_gdbserver = 0;
-
 void die(const char* msg)
 {
   fprintf(stderr, "gdbserver code died: %s\n", msg);
@@ -47,7 +45,7 @@ enum {
   REG_FPR31 = 64,
   REG_CSR0 = 65,
   REG_CSR4095 = 4160,
-  REG_END = 4161
+  REG_PRIV = 4161
 };
 
 //////////////////////////////////////// Functions to generate RISC-V opcodes.
@@ -618,6 +616,11 @@ class register_read_op_t : public operation_t
             // If we hit an exception reading the CSR, we'll end up returning ~0 as
             // the register's value, which is what we want. (Right?)
             gs.dr_write(SLOT_DATA0, ~(uint64_t) 0);
+          } else if (reg == REG_PRIV) {
+            gs.start_packet();
+            gs.send((uint8_t) get_field(gs.dcsr, DCSR_PRV));
+            gs.end_packet();
+            return true;
           } else {
             gs.send_packet("E02");
             return true;
@@ -678,6 +681,9 @@ class register_write_op_t : public operation_t
           gs.sptbr = value;
           gs.sptbr_valid = true;
         }
+      } else if (reg == REG_PRIV) {
+        gs.dcsr = set_field(gs.dcsr, DCSR_PRV, value);
+        return true;
       } else {
         gs.send_packet("E02");
         return true;
@@ -746,7 +752,7 @@ class memory_read_op_t : public operation_t
         }
         value >>= 8;
       }
-      if (data && debug_gdbserver) {
+      if (data) {
         D(fprintf(stderr, "\n"));
       }
       length -= access_size;
@@ -1843,6 +1849,13 @@ void gdbserver_t::send(uint32_t value)
   }
 }
 
+void gdbserver_t::send(uint8_t value)
+{
+  char buffer[3];
+  sprintf(buffer, "%02x", (int) value);
+  send(buffer);
+}
+
 void gdbserver_t::send_packet(const char* data)
 {
   start_packet();
index c45f184f6da1253f92a8ee4f27827a59c6bbc371..f0e7fcafc8c338e36c470d166c0821781e1d73ae 100644 (file)
@@ -150,6 +150,8 @@ public:
   // Hex-encode a 32-bit value, and send it to gcc in target byte order (little
   // endian).
   void send(uint32_t value);
+  // Hex-encode an 8-bit value, and send it to gcc.
+  void send(uint8_t value);
   void send_packet(const char* data);
   uint8_t running_checksum;
   // Send "$" and clear running checksum.
index 35c19cb8a29090b774ff8c7a1fa091aa36428e21..bef9ef2e26769c82fd37862cb3023de7e50f1d4b 100644 (file)
@@ -1,6 +1,9 @@
 require_privilege(PRV_M);
 set_pc_and_serialize(STATE.dpc);
-p->set_privilege(STATE.dcsr.prv);
+/* The debug spec says we can't crash when prv is set to an invalid value. */
+if (p->validate_priv(STATE.dcsr.prv)) {
+  p->set_privilege(STATE.dcsr.prv);
+}
 
 /* We're not in Debug Mode anymore. */
 STATE.dcsr.cause = 0;
index 8c267f4964456e64ad5e4a9b944a8f81219e2aa7..3576af3899a6f23cad5c38638228ca4c99d31bac 100644 (file)
@@ -179,7 +179,7 @@ void processor_t::take_interrupt()
     raise_interrupt(ctz(enabled_interrupts));
 }
 
-static bool validate_priv(reg_t priv)
+bool processor_t::validate_priv(reg_t priv)
 {
   return priv == PRV_U || priv == PRV_S || priv == PRV_M;
 }
index 090ebe7a155a9157f2cc6c8e0d112d05f120acfc..4d0d5ab344b40d011ce4b686dc00ea1a36b2e848 100644 (file)
@@ -118,6 +118,7 @@ public:
     if (ext >= 'a' && ext <= 'z') ext += 'A' - 'a';
     return ext >= 'A' && ext <= 'Z' && ((isa >> (ext - 'A')) & 1);
   }
+  bool validate_priv(reg_t priv);
   void set_privilege(reg_t);
   void yield_load_reservation() { state.load_reservation = (reg_t)-1; }
   void update_histogram(reg_t pc);