Add debug module authentication.
[riscv-isa-sim.git] / riscv / debug_module.cc
index 1d184781495c3a94db14546d3a9f3c6f9ee8e775..f10c866ed26e21cec0f949b82712929bce898eef 100644 (file)
 
 ///////////////////////// debug_module_t
 
-debug_module_t::debug_module_t(sim_t *sim, unsigned progbufsize) :
+debug_module_t::debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits,
+    bool require_authentication) :
   progbufsize(progbufsize),
   program_buffer_bytes(4 + 4*progbufsize),
+  max_bus_master_bits(max_bus_master_bits),
+  require_authentication(require_authentication),
   debug_progbuf_start(debug_data_start - program_buffer_bytes),
   debug_abstract_start(debug_progbuf_start - debug_abstract_size*4),
   sim(sim)
@@ -60,7 +63,7 @@ void debug_module_t::reset()
 
   dmstatus = {0};
   dmstatus.impebreak = true;
-  dmstatus.authenticated = 1;
+  dmstatus.authenticated = !require_authentication;
   dmstatus.version = 2;
 
   abstractcs = {0};
@@ -70,12 +73,20 @@ void debug_module_t::reset()
   abstractauto = {0};
 
   sbcs = {0};
-  sbcs.version = 1;
-  sbcs.access64 = true;
-  sbcs.access32 = true;
-  sbcs.access16 = true;
-  sbcs.access8 = true;
-  sbcs.asize = sizeof(reg_t) * 8;
+  if (max_bus_master_bits > 0) {
+    sbcs.version = 1;
+    sbcs.asize = sizeof(reg_t) * 8;
+  }
+  if (max_bus_master_bits >= 64)
+    sbcs.access64 = true;
+  if (max_bus_master_bits >= 32)
+    sbcs.access32 = true;
+  if (max_bus_master_bits >= 16)
+    sbcs.access16 = true;
+  if (max_bus_master_bits >= 8)
+    sbcs.access8 = true;
+
+  challenge = random();
 }
 
 void debug_module_t::add_device(bus_t *bus) {
@@ -233,7 +244,7 @@ unsigned debug_module_t::sb_access_bits()
 
 void debug_module_t::sb_autoincrement()
 {
-  if (!sbcs.autoincrement)
+  if (!sbcs.autoincrement || !max_bus_master_bits)
     return;
 
   uint64_t value = sbaddress[0] + sb_access_bits() / 8;
@@ -254,29 +265,19 @@ void debug_module_t::sb_autoincrement()
 void debug_module_t::sb_read()
 {
   reg_t address = ((uint64_t) sbaddress[1] << 32) | sbaddress[0];
-  D(fprintf(stderr, "sb_read() @ 0x%lx\n", address));
   try {
-    switch (sbcs.sbaccess) {
-      case 0:
-        sbdata[0] = sim->debug_mmu->load_uint8(address);
-        break;
-      case 1:
-        sbdata[0] = sim->debug_mmu->load_uint16(address);
-        break;
-      case 2:
-        sbdata[0] = sim->debug_mmu->load_uint32(address);
-        D(fprintf(stderr, "   -> 0x%x\n", sbdata[0]));
-        break;
-      case 3:
-        {
-          uint64_t value = sim->debug_mmu->load_uint32(address);
-          sbdata[0] = value;
-          sbdata[1] = value >> 32;
-          break;
-        }
-      default:
-        sbcs.error = 3;
-        break;
+    if (sbcs.sbaccess == 0 && max_bus_master_bits >= 8) {
+      sbdata[0] = sim->debug_mmu->load_uint8(address);
+    } else if (sbcs.sbaccess == 1 && max_bus_master_bits >= 16) {
+      sbdata[0] = sim->debug_mmu->load_uint16(address);
+    } else if (sbcs.sbaccess == 2 && max_bus_master_bits >= 32) {
+      sbdata[0] = sim->debug_mmu->load_uint32(address);
+    } else if (sbcs.sbaccess == 3 && max_bus_master_bits >= 64) {
+      uint64_t value = sim->debug_mmu->load_uint32(address);
+      sbdata[0] = value;
+      sbdata[1] = value >> 32;
+    } else {
+      sbcs.error = 3;
     }
   } catch (trap_load_access_fault& t) {
     sbcs.error = 2;
@@ -287,23 +288,17 @@ void debug_module_t::sb_write()
 {
   reg_t address = ((uint64_t) sbaddress[1] << 32) | sbaddress[0];
   D(fprintf(stderr, "sb_write() 0x%x @ 0x%lx\n", sbdata[0], address));
-  switch (sbcs.sbaccess) {
-    case 0:
-      sim->debug_mmu->store_uint8(address, sbdata[0]);
-      break;
-    case 1:
-      sim->debug_mmu->store_uint16(address, sbdata[0]);
-      break;
-    case 2:
-      sim->debug_mmu->store_uint32(address, sbdata[0]);
-      break;
-    case 3:
-      sim->debug_mmu->store_uint64(address,
-          (((uint64_t) sbdata[1]) << 32) | sbdata[0]);
-      break;
-    default:
-      sbcs.error = 3;
-      break;
+  if (sbcs.sbaccess == 0 && max_bus_master_bits >= 8) {
+    sim->debug_mmu->store_uint8(address, sbdata[0]);
+  } else if (sbcs.sbaccess == 1 && max_bus_master_bits >= 16) {
+    sim->debug_mmu->store_uint16(address, sbdata[0]);
+  } else if (sbcs.sbaccess == 2 && max_bus_master_bits >= 32) {
+    sim->debug_mmu->store_uint32(address, sbdata[0]);
+  } else if (sbcs.sbaccess == 3 && max_bus_master_bits >= 64) {
+    sim->debug_mmu->store_uint64(address,
+        (((uint64_t) sbdata[1]) << 32) | sbdata[0]);
+  } else {
+    sbcs.error = 3;
   }
 }
 
@@ -467,6 +462,9 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
       case DMI_SBDATA3:
         result = sbdata[3];
         break;
+      case DMI_AUTHDATA:
+        result = challenge;
+        break;
       default:
         result = 0;
         D(fprintf(stderr, "Unexpected. Returning Error."));
@@ -557,6 +555,11 @@ bool debug_module_t::perform_abstract_command()
 bool debug_module_t::dmi_write(unsigned address, uint32_t value)
 {
   D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value));
+
+  if (!dmstatus.authenticated && address != DMI_AUTHDATA &&
+      address != DMI_DMCONTROL)
+    return false;
+
   if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
     unsigned i = address - DMI_DATA0;
     if (!abstractcs.busy)
@@ -589,6 +592,8 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
           if (!dmcontrol.dmactive && get_field(value, DMI_DMCONTROL_DMACTIVE))
             reset();
           dmcontrol.dmactive = get_field(value, DMI_DMCONTROL_DMACTIVE);
+          if (!dmstatus.authenticated)
+            return true;
           if (dmcontrol.dmactive) {
             dmcontrol.haltreq = get_field(value, DMI_DMCONTROL_HALTREQ);
             dmcontrol.resumereq = get_field(value, DMI_DMCONTROL_RESUMEREQ);
@@ -671,6 +676,18 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
       case DMI_SBDATA3:
         sbdata[3] = value;
         return true;
+      case DMI_AUTHDATA:
+        D(fprintf(stderr, "debug authentication: got 0x%x; 0x%x unlocks\n", value,
+            challenge + secret));
+        if (require_authentication) {
+          if (value == challenge + secret) {
+            dmstatus.authenticated = true;
+          } else {
+            dmstatus.authenticated = false;
+            challenge = random();
+          }
+        }
+        return true;
     }
   }
   return false;