From cb73c085a22b225576b5d5c22f74490f9e30a5a8 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Sun, 1 May 2016 09:53:23 -0700 Subject: [PATCH] Properly save/restore dpc, mcause, mbadaddr. Also clear dcsr.cause when leaving Debug Mode so future traps go where they should. --- riscv/gdbserver.cc | 115 +++++++++++++++++++++++++++++++++++++++------ riscv/gdbserver.h | 6 +++ riscv/insns/sret.h | 3 ++ 3 files changed, 110 insertions(+), 14 deletions(-) diff --git a/riscv/gdbserver.cc b/riscv/gdbserver.cc index f2dd6af..e7aa99c 100644 --- a/riscv/gdbserver.cc +++ b/riscv/gdbserver.cc @@ -82,6 +82,10 @@ static uint32_t csrr(unsigned int rd, unsigned int csr) { return (csr << 20) | (rd << 7) | MATCH_CSRRS; } +static uint32_t csrw(unsigned int source, unsigned int csr) { + return (csr << 20) | (source << 15) | MATCH_CSRRW; +} + static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) { return (bits(offset, 11, 5) << 25) | @@ -100,6 +104,15 @@ static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) MATCH_SD; } +static uint32_t ld(unsigned int src, unsigned int base, uint16_t offset) +{ + return (bits(offset, 11, 5) << 25) | + (bits(src, 4, 0) << 20) | + (base << 15) | + (bits(offset, 4, 0) << 7) | + MATCH_LD; +} + static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) { return (bits(offset, 11, 5) << 25) | @@ -201,17 +214,87 @@ class halt_op_t : public operation_t gs.write_debug_ram(0, csrsi(DCSR_ADDRESS, DCSR_HALT_MASK)); gs.write_debug_ram(1, csrr(S0, DPC_ADDRESS)); gs.write_debug_ram(2, sd(S0, 0, (uint16_t) DEBUG_RAM_START)); - gs.write_debug_ram(3, csrr(S0, DCSR_ADDRESS)); + gs.write_debug_ram(3, csrr(S0, CSR_MBADADDR)); gs.write_debug_ram(4, sd(S0, 0, (uint16_t) DEBUG_RAM_START + 8)); gs.write_debug_ram(5, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*5)))); gs.set_interrupt(0); + // We could read mcause here as well, but only on 64-bit targets. I'm + // trying to keep The patterns here usable for 32-bit ISAs as well. (On a + // 32-bit ISA 8 words are required, while the minimum Debug RAM size is 7 + // words.) + state = READ_DPC; return false; } bool step() { - return true; + if (state == READ_DPC) { + gs.saved_dpc = ((uint64_t) gs.read_debug_ram(1) << 32) | gs.read_debug_ram(0); + gs.saved_mbadaddr = ((uint64_t) gs.read_debug_ram(3) << 32) | gs.read_debug_ram(2); + gs.write_debug_ram(0, csrr(S0, CSR_MCAUSE)); + gs.write_debug_ram(1, sd(S0, 0, (uint16_t) DEBUG_RAM_START + 16)); + gs.write_debug_ram(2, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*2)))); + gs.set_interrupt(0); + state = READ_CAUSE; + return false; + } else { + gs.saved_mcause = ((uint64_t) gs.read_debug_ram(1) << 32) | gs.read_debug_ram(0); + return true; + } } + + private: + enum { + READ_DPC, + READ_CAUSE + } state; +}; + +class continue_op_t : public operation_t +{ + public: + continue_op_t(gdbserver_t& gdbserver) : operation_t(gdbserver) {}; + + bool start() + { + gs.write_debug_ram(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START+16)); + gs.write_debug_ram(1, csrw(S0, DPC_ADDRESS)); + gs.write_debug_ram(2, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*2)))); + gs.write_debug_ram(4, gs.saved_dpc); + gs.write_debug_ram(5, gs.saved_dpc >> 32); + gs.set_interrupt(0); + state = WRITE_DPC; + return false; + } + + bool step() + { + if (state == WRITE_DPC) { + gs.write_debug_ram(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START+16)); + gs.write_debug_ram(1, csrw(S0, CSR_MBADADDR)); + gs.write_debug_ram(2, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*2)))); + gs.write_debug_ram(4, gs.saved_mbadaddr); + gs.write_debug_ram(5, gs.saved_mbadaddr >> 32); + gs.set_interrupt(0); + state = WRITE_MBADADDR; + return false; + } else { + gs.write_debug_ram(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START+16)); + gs.write_debug_ram(1, csrw(S0, CSR_MCAUSE)); + gs.write_debug_ram(2, csrci(DCSR_ADDRESS, DCSR_HALT_MASK)); + gs.write_debug_ram(3, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*3)))); + gs.write_debug_ram(4, gs.saved_mcause); + gs.write_debug_ram(5, gs.saved_mcause >> 32); + gs.set_interrupt(0); + return true; + } + } + + private: + enum { + WRITE_DPC, + WRITE_MBADADDR + } state; }; class general_registers_read_op_t : public operation_t @@ -284,13 +367,24 @@ class register_read_op_t : public operation_t die("handle_register_read"); // send(p->state.XPR[reg - REG_XPR0]); } else if (reg == REG_PC) { - gs.write_debug_ram(0, csrr(S0, DPC_ADDRESS)); - gs.write_debug_ram(1, sd(S0, 0, (uint16_t) DEBUG_RAM_START + 16)); - gs.write_debug_ram(2, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*2)))); + gs.start_packet(); + gs.send(gs.saved_dpc); + gs.end_packet(); + return true; } else if (reg >= REG_FPR0 && reg <= REG_FPR31) { // send(p->state.FPR[reg - REG_FPR0]); gs.write_debug_ram(0, fsd(reg - REG_FPR0, 0, (uint16_t) DEBUG_RAM_START + 16)); gs.write_debug_ram(1, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*1)))); + } else if (reg == REG_CSR0 + CSR_MBADADDR) { + gs.start_packet(); + gs.send(gs.saved_mbadaddr); + gs.end_packet(); + return true; + } else if (reg == REG_CSR0 + CSR_MCAUSE) { + gs.start_packet(); + gs.send(gs.saved_mcause); + gs.end_packet(); + return true; } else if (reg >= REG_CSR0 && reg <= REG_CSR4095) { gs.write_debug_ram(0, csrr(S0, reg - REG_CSR0)); gs.write_debug_ram(1, sd(S0, 0, (uint16_t) DEBUG_RAM_START + 16)); @@ -716,24 +810,17 @@ void gdbserver_t::handle_continue(const std::vector &packet) processor_t *p = sim->get_core(0); if (packet[2] != '#') { std::vector::const_iterator iter = packet.begin() + 2; - die("handle_continue"); - // p->state.pc = consume_hex_number(iter, packet.end()); + saved_dpc = consume_hex_number(iter, packet.end()); if (*iter != '#') return send_packet("E30"); } - write_debug_ram(0, csrci(DCSR_ADDRESS, DCSR_HALT_MASK)); - write_debug_ram(1, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 1*5)))); - set_interrupt(0); - - // TODO p->set_halted(false, HR_NONE); - // TODO running = true; + set_operation(new continue_op_t(*this)); } void gdbserver_t::handle_step(const std::vector &packet) { // s [addr] - processor_t *p = sim->get_core(0); if (packet[2] != '#') { std::vector::const_iterator iter = packet.begin() + 2; die("handle_step"); diff --git a/riscv/gdbserver.h b/riscv/gdbserver.h index 35e12b8..acd68b3 100644 --- a/riscv/gdbserver.h +++ b/riscv/gdbserver.h @@ -132,6 +132,12 @@ public: void set_interrupt(uint32_t hartid); + // Members that ought to be privated, but that we'd really like to access + // from operation classes. + reg_t saved_dpc; + reg_t saved_mbadaddr; + reg_t saved_mcause; + private: sim_t *sim; int socket_fd; diff --git a/riscv/insns/sret.h b/riscv/insns/sret.h index f5e89e4..dc2fee0 100644 --- a/riscv/insns/sret.h +++ b/riscv/insns/sret.h @@ -7,3 +7,6 @@ s = set_field(s, MSTATUS_SPIE, 0); s = set_field(s, MSTATUS_SPP, PRV_U); p->set_privilege(prev_prv); p->set_csr(CSR_MSTATUS, s); + +/* We're not in Debug Mode anymore. */ +STATE.dcsr.cause = 0; -- 2.30.2