From 6ef848928a5e2d72d9b0aed66f669b7b9a80b49a Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 4 May 2016 13:14:46 -0700 Subject: [PATCH] Software breakpoints sort of work. --- riscv/debug_module.cc | 4 ++ riscv/debug_module.h | 14 +++++ riscv/decode.h | 6 -- riscv/encoding.h | 8 +++ riscv/gdbserver.cc | 137 ++++++++++++++++++++++-------------------- riscv/gdbserver.h | 5 +- 6 files changed, 100 insertions(+), 74 deletions(-) diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc index e3eb16b..8ad9513 100644 --- a/riscv/debug_module.cc +++ b/riscv/debug_module.cc @@ -41,6 +41,10 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes) clear_interrupt(bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24)); return true; + } else if (len == 4 && addr == DEBUG_SETHALTNOT) { + set_halt_notification(bytes[0] | (bytes[1] << 8) | + (bytes[2] << 16) | (bytes[3] << 24)); + return true; } fprintf(stderr, "ERROR: invalid store to debug module: %ld bytes at 0x%lx\n", diff --git a/riscv/debug_module.h b/riscv/debug_module.h index d7c1a87..7a78ad3 100644 --- a/riscv/debug_module.h +++ b/riscv/debug_module.h @@ -27,9 +27,23 @@ class debug_module_t : public abstract_device_t return interrupt.find(hartid) != interrupt.end(); } + void set_halt_notification(uint32_t hartid) { + fprintf(stderr, "set debug halt_notification 0x%x\n", hartid); + halt_notification.insert(hartid); + } + void clear_halt_notification(uint32_t hartid) { + fprintf(stderr, "clear debug halt_notification 0x%x\n", hartid); + halt_notification.erase(hartid); + } + bool get_halt_notification(uint32_t hartid) const { + return halt_notification.find(hartid) != halt_notification.end(); + } + private: // Track which interrupts from module to debugger are set. std::set interrupt; + // Track which halt notifications from debugger to module are set. + std::set halt_notification; char debug_ram[DEBUG_RAM_SIZE]; }; diff --git a/riscv/decode.h b/riscv/decode.h index 067d426..1625398 100644 --- a/riscv/decode.h +++ b/riscv/decode.h @@ -229,12 +229,6 @@ private: * automatically generated. */ /* TODO */ #include "/media/sf_tnewsome/Synced/SiFive/debug-spec/core_registers.tex.h" -#define DCSR_CAUSE_NONE 0 -#define DCSR_CAUSE_SWBP 1 -#define DCSR_CAUSE_HWBP 2 -#define DCSR_CAUSE_DEBUGINT 3 -#define DCSR_CAUSE_STEPPED 4 -#define DCSR_CAUSE_HALT 5 #define DEBUG_START 0x100 #define DEBUG_ROM_START 0x800 diff --git a/riscv/encoding.h b/riscv/encoding.h index 11aa518..fcc0a8a 100644 --- a/riscv/encoding.h +++ b/riscv/encoding.h @@ -34,6 +34,14 @@ #define SSTATUS64_SD 0x8000000000000000 #define DCSR_PRV (3<<14) +#define DCSR_CAUSE 7 + +#define DCSR_CAUSE_NONE 0 +#define DCSR_CAUSE_SWBP 1 +#define DCSR_CAUSE_HWBP 2 +#define DCSR_CAUSE_DEBUGINT 3 +#define DCSR_CAUSE_STEP 4 +#define DCSR_CAUSE_HALT 5 #define MIP_SSIP (1 << IRQ_S_SOFT) #define MIP_HSIP (1 << IRQ_H_SOFT) diff --git a/riscv/gdbserver.cc b/riscv/gdbserver.cc index d3f2d4d..0cccf3d 100644 --- a/riscv/gdbserver.cc +++ b/riscv/gdbserver.cc @@ -247,7 +247,8 @@ void circular_buffer_t::append(const T *src, unsigned int count) class halt_op_t : public operation_t { public: - halt_op_t(gdbserver_t& gdbserver) : operation_t(gdbserver) {}; + halt_op_t(gdbserver_t& gdbserver, bool send_status=false) : + operation_t(gdbserver), send_status(send_status) {}; bool perform_step(unsigned int step) { switch (step) { @@ -287,10 +288,33 @@ class halt_op_t : public operation_t gs.sptbr_valid = false; gs.pte_cache.clear(); + + if (send_status) { + switch (get_field(gs.dcsr, DCSR_CAUSE)) { + case DCSR_CAUSE_NONE: + fprintf(stderr, "Internal error. Processor halted without reason.\n"); + abort(); + + case DCSR_CAUSE_HWBP: + case DCSR_CAUSE_DEBUGINT: + case DCSR_CAUSE_STEP: + case DCSR_CAUSE_HALT: + // There's no gdb code for this. + gs.send_packet("T05"); + break; + case DCSR_CAUSE_SWBP: + gs.send_packet("T05swbreak:;"); + break; + } + } + return true; } return false; } + + private: + bool send_status; }; class continue_op_t : public operation_t @@ -461,8 +485,11 @@ class register_read_op_t : public operation_t class memory_read_op_t : public operation_t { public: - memory_read_op_t(gdbserver_t& gdbserver, reg_t vaddr, unsigned int length) : - operation_t(gdbserver), vaddr(vaddr), length(length) {}; + // Read length bytes from vaddr, storing the result into data. + // If data is NULL, send the result straight to gdb. + memory_read_op_t(gdbserver_t& gdbserver, reg_t vaddr, unsigned int length, + unsigned char *data=NULL) : + operation_t(gdbserver), vaddr(vaddr), length(length), data(data) {}; bool perform_step(unsigned int step) { @@ -472,6 +499,8 @@ class memory_read_op_t : public operation_t access_size = (paddr % length); if (access_size == 0) access_size = length; + if (access_size > 8) + access_size = 8; gs.write_debug_ram(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START + 16)); switch (access_size) { @@ -487,9 +516,6 @@ class memory_read_op_t : public operation_t case 8: gs.write_debug_ram(1, ld(S1, S0, 0)); break; - default: - gs.send_packet("E12"); - return true; } gs.write_debug_ram(2, sd(S1, 0, (uint16_t) DEBUG_RAM_START + 24)); gs.write_debug_ram(3, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*3)))); @@ -497,22 +523,30 @@ class memory_read_op_t : public operation_t gs.write_debug_ram(5, paddr >> 32); gs.set_interrupt(0); - gs.start_packet(); + if (!data) { + gs.start_packet(); + } return false; } char buffer[3]; reg_t value = ((uint64_t) gs.read_debug_ram(7) << 32) | gs.read_debug_ram(6); for (unsigned int i = 0; i < access_size; i++) { - sprintf(buffer, "%02x", (unsigned int) (value & 0xff)); - gs.send(buffer); + if (data) { + *(data++) = value & 0xff; + } else { + sprintf(buffer, "%02x", (unsigned int) (value & 0xff)); + gs.send(buffer); + } value >>= 8; } length -= access_size; paddr += access_size; if (length == 0) { - gs.end_packet(); + if (!data) { + gs.end_packet(); + } return true; } else { gs.write_debug_ram(4, paddr); @@ -523,8 +557,10 @@ class memory_read_op_t : public operation_t } private: - reg_t vaddr, paddr; + reg_t vaddr; unsigned int length; + unsigned char* data; + reg_t paddr; unsigned int access_size; }; @@ -1265,28 +1301,6 @@ void gdbserver_t::handle_extended(const std::vector &packet) extended_mode = true; } -void software_breakpoint_t::insert(mmu_t* mmu) -{ - if (size == 2) { - instruction = mmu->load_uint16(address); - mmu->store_uint16(address, C_EBREAK); - } else { - instruction = mmu->load_uint32(address); - mmu->store_uint32(address, EBREAK); - } - fprintf(stderr, ">>> Read %x from %lx\n", instruction, address); -} - -void software_breakpoint_t::remove(mmu_t* mmu) -{ - fprintf(stderr, ">>> write %x to %lx\n", instruction, address); - if (size == 2) { - mmu->store_uint16(address, instruction); - } else { - mmu->store_uint32(address, instruction); - } -} - void gdbserver_t::handle_breakpoint(const std::vector &packet) { // insert: Z type,addr,kind @@ -1312,22 +1326,35 @@ void gdbserver_t::handle_breakpoint(const std::vector &packet) return send_packet("E53"); } - processor_t *p = sim->get_core(0); - die("handle_breakpoint"); - /* - mmu_t* mmu = p->mmu; + add_operation(new collect_translation_info_op_t(*this, bp.address, bp.size)); if (insert) { - bp.insert(mmu); + // TODO: this only works on little-endian hosts. + unsigned char* swbp = new unsigned char[4]; + if (bp.size == 2) { + swbp[0] = C_EBREAK & 0xff; + swbp[1] = (C_EBREAK >> 8) & 0xff; + } else { + swbp[0] = EBREAK & 0xff; + swbp[1] = (EBREAK >> 8) & 0xff; + swbp[2] = (EBREAK >> 16) & 0xff; + swbp[3] = (EBREAK >> 24) & 0xff; + } + + add_operation(new memory_read_op_t(*this, bp.address, bp.size, bp.instruction)); + add_operation(new memory_write_op_t(*this, bp.address, bp.size, swbp)); breakpoints[bp.address] = bp; } else { bp = breakpoints[bp.address]; - bp.remove(mmu); + unsigned char* instruction = new unsigned char[4]; + memcpy(instruction, bp.instruction, 4); + add_operation(new memory_write_op_t(*this, bp.address, bp.size, instruction)); breakpoints.erase(bp.address); } - mmu->flush_icache(); - sim->debug_mmu->flush_icache(); - */ + + // TODO mmu->flush_icache(); + // TODO sim->debug_mmu->flush_icache(); + return send_packet("OK"); } @@ -1431,29 +1458,11 @@ void gdbserver_t::handle() } } - /* TODO - if (running && p->halted) { - // The core was running, but now it's halted. Better tell gdb. - switch (p->halt_reason) { - case HR_NONE: - fprintf(stderr, "Internal error. Processor halted without reason.\n"); - abort(); - case HR_STEPPED: - case HR_INTERRUPT: - case HR_CMDLINE: - case HR_ATTACHED: - // There's no gdb code for this. - send_packet("T05"); - break; - case HR_SWBP: - send_packet("T05swbreak:;"); - break; - } - send_packet("T00"); - // TODO: Actually include register values here - running = false; + bool halt_notification = sim->debug_module.get_halt_notification(0); + if (halt_notification) { + sim->debug_module.clear_halt_notification(0); + add_operation(new halt_op_t(*this, true)); } - */ this->read(); this->write(); diff --git a/riscv/gdbserver.h b/riscv/gdbserver.h index 9b39450..f91498a 100644 --- a/riscv/gdbserver.h +++ b/riscv/gdbserver.h @@ -51,10 +51,7 @@ class software_breakpoint_t public: reg_t address; unsigned int size; - uint32_t instruction; - - void insert(mmu_t* mmu); - void remove(mmu_t* mmu); + unsigned char instruction[4]; }; class gdbserver_t; -- 2.30.2