Merge pull request #177 from riscv/debug_auth
authorTim Newsome <tim@sifive.com>
Thu, 8 Mar 2018 01:17:39 +0000 (17:17 -0800)
committerGitHub <noreply@github.com>
Thu, 8 Mar 2018 01:17:39 +0000 (17:17 -0800)
Add debug module authentication.

1  2 
riscv/debug_module.cc
riscv/debug_module.h
riscv/sim.cc
riscv/sim.h

diff --combined riscv/debug_module.cc
index de54a8377256346b8223c5a5fe6b4025b8400bfc,f10c866ed26e21cec0f949b82712929bce898eef..74c302300c8c14c3df029899d5122184f190aea7
@@@ -6,7 -6,7 +6,7 @@@
  #include "mmu.h"
  
  #include "debug_rom/debug_rom.h"
 -#include "debug_rom/debug_rom_defines.h"
 +#include "debug_rom_defines.h"
  
  #if 0
  #  define D(x) x
  
  ///////////////////////// debug_module_t
  
- debug_module_t::debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits) :
+ 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)
  {
 +  D(fprintf(stderr, "debug_data_start=0x%x\n", debug_data_start));
 +  D(fprintf(stderr, "debug_progbuf_start=0x%x\n", debug_progbuf_start));
 +  D(fprintf(stderr, "debug_abstract_start=0x%x\n", debug_abstract_start));
 +
    program_buffer = new uint8_t[program_buffer_bytes];
  
    memset(halted, 0, sizeof(halted));
@@@ -65,7 -63,7 +67,7 @@@ void debug_module_t::reset(
  
    dmstatus = {0};
    dmstatus.impebreak = true;
-   dmstatus.authenticated = 1;
+   dmstatus.authenticated = !require_authentication;
    dmstatus.version = 2;
  
    abstractcs = {0};
@@@ -87,6 -85,8 +89,8 @@@
      sbcs.access16 = true;
    if (max_bus_master_bits >= 8)
      sbcs.access8 = true;
+   challenge = random();
  }
  
  void debug_module_t::add_device(bus_t *bus) {
@@@ -462,6 -462,9 +466,9 @@@ bool debug_module_t::dmi_read(unsigned 
        case DMI_SBDATA3:
          result = sbdata[3];
          break;
+       case DMI_AUTHDATA:
+         result = challenge;
+         break;
        default:
          result = 0;
          D(fprintf(stderr, "Unexpected. Returning Error."));
@@@ -493,110 -496,51 +500,110 @@@ bool debug_module_t::perform_abstract_c
        return true;
      }
  
 +    unsigned i = 0;
      if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
  
 -      if (regno < 0x1000 || regno >= 0x1020) {
 -        abstractcs.cmderr = CMDERR_NOTSUP;
 -        return true;
 -      }
 +      if (regno < 0x1000 && progbufsize < 2) {
 +        // Make the debugger use the program buffer if it's available, so it
 +        // can test both use cases.
 +        write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH));
 +
 +        if (write) {
 +          switch (size) {
 +            case 2:
 +              write32(debug_abstract, i++, lw(S0, ZERO, debug_data_start));
 +              break;
 +            case 3:
 +              write32(debug_abstract, i++, ld(S0, ZERO, debug_data_start));
 +              break;
 +            default:
 +              abstractcs.cmderr = CMDERR_NOTSUP;
 +              return true;
 +          }
 +          write32(debug_abstract, i++, csrw(S0, regno));
 +
 +        } else {
 +          write32(debug_abstract, i++, csrr(S0, regno));
 +          switch (size) {
 +            case 2:
 +              write32(debug_abstract, i++, sw(S0, ZERO, debug_data_start));
 +              break;
 +            case 3:
 +              write32(debug_abstract, i++, sd(S0, ZERO, debug_data_start));
 +              break;
 +            default:
 +              abstractcs.cmderr = CMDERR_NOTSUP;
 +              return true;
 +          }
 +        }
 +        write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH));
 +
 +      } else if (regno >= 0x1000 && regno < 0x1020) {
 +        unsigned regnum = regno - 0x1000;
 +
 +        switch (size) {
 +          case 2:
 +            if (write)
 +              write32(debug_abstract, i++, lw(regnum, ZERO, debug_data_start));
 +            else
 +              write32(debug_abstract, i++, sw(regnum, ZERO, debug_data_start));
 +            break;
 +          case 3:
 +            if (write)
 +              write32(debug_abstract, i++, ld(regnum, ZERO, debug_data_start));
 +            else
 +              write32(debug_abstract, i++, sd(regnum, ZERO, debug_data_start));
 +            break;
 +          default:
 +            abstractcs.cmderr = CMDERR_NOTSUP;
 +            return true;
 +        }
  
 -      unsigned regnum = regno - 0x1000;
 +      } else if (regno >= 0x1020 && regno < 0x1040) {
 +        // Don't force the debugger to use progbuf if it exists, so the
 +        // debugger has to make the decision not to use abstract commands to
 +        // access 64-bit FPRs on 32-bit targets.
 +        unsigned fprnum = regno - 0x1020;
 +
 +        if (write) {
 +          switch (size) {
 +            case 2:
 +              write32(debug_abstract, i++, flw(fprnum, ZERO, debug_data_start));
 +              break;
 +            case 3:
 +              write32(debug_abstract, i++, fld(fprnum, ZERO, debug_data_start));
 +              break;
 +            default:
 +              abstractcs.cmderr = CMDERR_NOTSUP;
 +              return true;
 +          }
  
 -      switch (size) {
 -      case 2:
 -        if (write)
 -          write32(debug_abstract, 0, lw(regnum, ZERO, debug_data_start));
 -        else
 -          write32(debug_abstract, 0, sw(regnum, ZERO, debug_data_start));
 -        break;
 -      case 3:
 -        if (write)
 -          write32(debug_abstract, 0, ld(regnum, ZERO, debug_data_start));
 -        else
 -          write32(debug_abstract, 0, sd(regnum, ZERO, debug_data_start));
 -        break;
 -        /*
 -          case 4:
 -          if (write)
 -          write32(debug_rom_code, 0, lq(regnum, ZERO, debug_data_start));
 -          else
 -          write32(debug_rom_code, 0, sq(regnum, ZERO, debug_data_start));
 -          break;
 -        */
 -      default:
 +        } else {
 +          switch (size) {
 +            case 2:
 +              write32(debug_abstract, i++, fsw(fprnum, ZERO, debug_data_start));
 +              break;
 +            case 3:
 +              write32(debug_abstract, i++, fsd(fprnum, ZERO, debug_data_start));
 +              break;
 +            default:
 +              abstractcs.cmderr = CMDERR_NOTSUP;
 +              return true;
 +          }
 +        }
 +
 +      } else {
          abstractcs.cmderr = CMDERR_NOTSUP;
          return true;
        }
 -    } else {
 -      //NOP
 -      write32(debug_abstract, 0, addi(ZERO, ZERO, 0));
      }
  
      if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {
 -      // Since the next instruction is what we will use, just use nother NOP
 -      // to get there.
 -      write32(debug_abstract, 1, addi(ZERO, ZERO, 0));
 +      write32(debug_abstract, i,
 +          jal(ZERO, debug_progbuf_start - debug_abstract_start - 4 * i));
 +      i++;
      } else {
 -      write32(debug_abstract, 1, ebreak());
 +      write32(debug_abstract, i++, ebreak());
      }
  
      debug_rom_flags[dmcontrol.hartsel] |= 1 << DEBUG_ROM_FLAG_GO;
  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)
            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);
        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;
diff --combined riscv/debug_module.h
index 82c449ef6a70a699af5438db8a9adc83e353a356,e554ffc8f3623863851a1a4f5fbf4192402fae69..813c6472189b00e16da5aae099bceed692ba8bf1
@@@ -74,7 -74,14 +74,14 @@@ typedef struct 
  class debug_module_t : public abstract_device_t
  {
    public:
-     debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits);
+     /*
+      * If require_authentication is true, then a debugger must authenticate as
+      * follows:
+      * 1. Read a 32-bit value from authdata:
+      * 2. Write the value that was read back, plus one, to authdata.
+      */
+     debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits,
+         bool require_authentication);
      ~debug_module_t();
  
      void add_device(bus_t *bus);
      // Actual size of the program buffer, which is 1 word bigger than we let on
      // to implement the implicit ebreak at the end.
      unsigned program_buffer_bytes;
-     unsigned max_bus_master_bits ;
+     unsigned max_bus_master_bits;
+     bool require_authentication;
      static const unsigned debug_data_start = 0x380;
      unsigned debug_progbuf_start;
  
 -    static const unsigned debug_abstract_size = 2;
 +    static const unsigned debug_abstract_size = 5;
      unsigned debug_abstract_start;
  
      static const unsigned hartsellen = 10;
      uint32_t sbaddress[4];
      uint32_t sbdata[4];
  
+     uint32_t challenge;
+     const uint32_t secret = 1;
      processor_t *current_proc() const;
      void reset();
      bool perform_abstract_command();
diff --combined riscv/sim.cc
index 10c1898d993152b2ac7661f25cd010610ddc9eef,0e38c53fa96444a263f1560cbf631e21edc45497..81c5f6f1c465331a470222237f03f0261d661552
@@@ -27,10 -27,11 +27,11 @@@ sim_t::sim_t(const char* isa, size_t np
               std::vector<std::pair<reg_t, mem_t*>> mems,
               const std::vector<std::string>& args,
               std::vector<int> const hartids, unsigned progsize,
-              unsigned max_bus_master_bits)
+              unsigned max_bus_master_bits, bool require_authentication)
    : htif_t(args), mems(mems), procs(std::max(nprocs, size_t(1))),
      start_pc(start_pc), current_step(0), current_proc(0), debug(false),
-     remote_bitbang(NULL), debug_module(this, progsize, max_bus_master_bits)
+     remote_bitbang(NULL),
+     debug_module(this, progsize, max_bus_master_bits, require_authentication)
  {
    signal(SIGINT, &handle_signal);
  
@@@ -247,7 -248,7 +248,7 @@@ void sim_t::make_dtb(
      0x297,                                      // auipc  t0,0x0
      0x28593 + (reset_vec_size * 4 << 20),       // addi   a1, t0, &dtb
      0xf1402573,                                 // csrr   a0, mhartid
 -    get_core(0)->xlen == 32 ?
 +    get_core(0)->get_xlen() == 32 ?
        0x0182a283u :                             // lw     t0,24(t0)
        0x0182b283u,                              // ld     t0,24(t0)
      0x28067,                                    // jr     t0
           "      reg = <" << i << ">;\n"
           "      status = \"okay\";\n"
           "      compatible = \"riscv\";\n"
 -         "      riscv,isa = \"" << procs[i]->isa_string << "\";\n"
 -         "      mmu-type = \"riscv," << (procs[i]->max_xlen <= 32 ? "sv32" : "sv48") << "\";\n"
 +         "      riscv,isa = \"" << procs[i]->get_isa_string() << "\";\n"
 +         "      mmu-type = \"riscv," << (procs[i]->get_max_xlen() <= 32 ? "sv32" : "sv48") << "\";\n"
           "      clock-frequency = <" << CPU_HZ << ">;\n"
           "      CPU" << i << "_intc: interrupt-controller {\n"
           "        #interrupt-cells = <1>;\n"
diff --combined riscv/sim.h
index 638206e11b329249e04f6b8c37ba0dee1280229b,6c6e4350702d62b240a42730a20f0b3efbd8f901..9a0a10b2569ba4a6aa8190fb5a540108f5a85a72
  class mmu_t;
  class remote_bitbang_t;
  
 +// this is the interface to the simulator used by the processors and memory
 +class simif_t
 +{
 +public:
 +  // should return NULL for MMIO addresses
 +  virtual char* addr_to_mem(reg_t addr) = 0;
 +  // used for MMIO addresses
 +  virtual bool mmio_load(reg_t addr, size_t len, uint8_t* bytes) = 0;
 +  virtual bool mmio_store(reg_t addr, size_t len, const uint8_t* bytes) = 0;
 +};
 +
  // this class encapsulates the processors and memory in a RISC-V machine.
 -class sim_t : public htif_t
 +class sim_t : public htif_t, public simif_t
  {
  public:
    sim_t(const char* isa, size_t _nprocs,  bool halted, reg_t start_pc,
          std::vector<std::pair<reg_t, mem_t*>> mems,
          const std::vector<std::string>& args, const std::vector<int> hartids,
-         unsigned progsize, unsigned max_bus_master_bits);
+         unsigned progsize, unsigned max_bus_master_bits, bool require_authentication);
    ~sim_t();
  
    // run the simulation to completion