From: Tim Newsome Date: Thu, 8 Mar 2018 01:17:39 +0000 (-0800) Subject: Merge pull request #177 from riscv/debug_auth X-Git-Url: https://git.libre-soc.org/?p=riscv-isa-sim.git;a=commitdiff_plain;h=9d1e10a36e771bf8cfbf515e07e856e021c1007a;hp=-c Merge pull request #177 from riscv/debug_auth Add debug module authentication. --- 9d1e10a36e771bf8cfbf515e07e856e021c1007a diff --combined riscv/debug_module.cc index de54a83,f10c866..74c3023 --- a/riscv/debug_module.cc +++ b/riscv/debug_module.cc @@@ -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 @@@ -16,18 -16,16 +16,20 @@@ ///////////////////////// 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; @@@ -611,6 -555,11 +618,11 @@@ 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) @@@ -643,6 -592,8 +655,8 @@@ 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); @@@ -725,6 -676,18 +739,18 @@@ 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 82c449e,e554ffc..813c647 --- a/riscv/debug_module.h +++ b/riscv/debug_module.h @@@ -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); @@@ -96,11 -103,12 +103,12 @@@ // 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; @@@ -134,6 -142,9 +142,9 @@@ 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 10c1898,0e38c53..81c5f6f --- a/riscv/sim.cc +++ b/riscv/sim.cc @@@ -27,10 -27,11 +27,11 @@@ sim_t::sim_t(const char* isa, size_t np std::vector> mems, const std::vector& args, std::vector 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 @@@ -277,8 -278,8 +278,8 @@@ " 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 638206e,6c6e435..9a0a10b --- a/riscv/sim.h +++ b/riscv/sim.h @@@ -15,25 -15,14 +15,25 @@@ 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> mems, const std::vector& args, const std::vector 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