From 9b2a1d6c81edaff395dc5b75eca41ca88b3e24e3 Mon Sep 17 00:00:00 2001 From: Farid Khaydari Date: Wed, 11 Dec 2024 13:29:26 +0300 Subject: [PATCH] Add DCSR.MPRVEN support Adds DCSR.MPRVEN bit support, as specified in RISC-V External Debug Support Version 1.0.0-rc4 (https://github.com/riscv/riscv-debug-spec/releases/tag/1.0.0-rc4, see 4.9.1 Debug Control and Status). This bit allows to enable hardware virtual address translation when memory access is initiated by the debugger (see 4.1 Debug Mode, clause 2). This change: * Increases debug specification coverage, allows more detailed testing of external debuggers with Spike. * Decreases the number of required abstract commands to read virtual memory thus improving the user experience. Commit's changes: * Added MPRVEN field to DCSR register * Updated debug_rom.S to turn off MPRVEN on memory access To avoid unwanted address translation while debug_rom.S executed DCSR.MPRVEN bit has to be cleared before and restored after access. Signed-off-by: Farid Khaydari --- debug_rom/debug_rom.S | 58 +++++++++++++++++++++++++++++++++++-------- debug_rom/debug_rom.h | 32 ++++++++++++++++-------- riscv/csrs.cc | 3 +++ riscv/csrs.h | 1 + riscv/mmu.h | 2 +- 5 files changed, 74 insertions(+), 22 deletions(-) diff --git a/debug_rom/debug_rom.S b/debug_rom/debug_rom.S index 2d361397..378c5683 100755 --- a/debug_rom/debug_rom.S +++ b/debug_rom/debug_rom.S @@ -7,6 +7,19 @@ .global entry .global exception +// This macro handles mem access with proper management of the MPRVEN +// Usage: MEMORY_ACCESS_WITH_MPRV() +#define MEMORY_ACCESS_WITH_MPRV(...) \ + csrrci s0, CSR_DCSR, DCSR_MPRVEN; \ + andi s0, s0, DCSR_MPRVEN; \ + bnez s0, 1f; \ + __VA_ARGS__; \ + j 2f; \ +1: \ + __VA_ARGS__; \ + csrrsi zero, CSR_DCSR, DCSR_MPRVEN; \ +2: + // Entry location on ebreak, Halt, or Breakpoint // It is the same for all harts. They branch when // their GO or RESUME bit is set. @@ -30,13 +43,22 @@ _entry: // We keep checking both whether there is something the debugger wants // us to do, or whether we should resume. entry_loop: - csrr s0, CSR_MHARTID - sw s0, DEBUG_ROM_HALTED(zero) - lbu s0, DEBUG_ROM_FLAGS(s0) // 1 byte flag per hart. Only one hart advances here. + // 1 byte flag per hart. Only one hart advances here. + MEMORY_ACCESS_WITH_MPRV( + csrr s0, CSR_MHARTID; + sw s0, DEBUG_ROM_HALTED(zero); + lbu s0, DEBUG_ROM_FLAGS(s0); + ) + andi s0, s0, (1 << DEBUG_ROM_FLAG_GO) bnez s0, going - csrr s0, CSR_MHARTID - lbu s0, DEBUG_ROM_FLAGS(s0) // multiple harts can resume here + + // multiple harts can resume here + MEMORY_ACCESS_WITH_MPRV( + csrr s0, CSR_MHARTID; + lbu s0, DEBUG_ROM_FLAGS(s0); + ) + andi s0, s0, (1 << DEBUG_ROM_FLAG_RESUME) bnez s0, _resume wfi @@ -46,13 +68,23 @@ _exception: // Restore S0, which we always save to dscratch. // We need this in case the user tried an abstract write to a // non-existent CSR. - csrr s0, CSR_DSCRATCH0 - sw zero, DEBUG_ROM_EXCEPTION(zero) // Let debug module know you got an exception. + + + // Let debug module know you got an exception. + MEMORY_ACCESS_WITH_MPRV( + csrr s0, CSR_DSCRATCH0; + sw zero, DEBUG_ROM_EXCEPTION(zero); + ) + ebreak going: - csrr s0, CSR_MHARTID - sw s0, DEBUG_ROM_GOING(zero) // When debug module sees this write, the GO flag is reset. + // When debug module sees this write, the GO flag is reset. + MEMORY_ACCESS_WITH_MPRV( + csrr s0, CSR_MHARTID; + sw s0, DEBUG_ROM_GOING(zero); + ) + csrr s0, CSR_DSCRATCH0 // Restore s0 here fence fence.i @@ -61,8 +93,12 @@ going: // because jalr is special there) _resume: - csrr s0, CSR_MHARTID - sw s0, DEBUG_ROM_RESUMING(zero) // When Debug Module sees this write, the RESUME flag is reset. + // When Debug Module sees this write, the RESUME flag is reset. + MEMORY_ACCESS_WITH_MPRV( + csrr s0, CSR_MHARTID; + sw s0, DEBUG_ROM_RESUMING(zero); + ) + csrr s0, CSR_DSCRATCH0 // Restore s0 dret diff --git a/debug_rom/debug_rom.h b/debug_rom/debug_rom.h index 7edd5f68..d3d89a28 100644 --- a/debug_rom/debug_rom.h +++ b/debug_rom/debug_rom.h @@ -1,13 +1,25 @@ static const unsigned char debug_rom_raw[] = { - 0x6f, 0x00, 0xc0, 0x00, 0x6f, 0x00, 0x00, 0x06, 0x6f, 0x00, 0x80, 0x03, - 0x0f, 0x00, 0xf0, 0x0f, 0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x40, 0xf1, - 0x23, 0x20, 0x80, 0x10, 0x03, 0x44, 0x04, 0x40, 0x13, 0x74, 0x14, 0x00, - 0x63, 0x14, 0x04, 0x02, 0x73, 0x24, 0x40, 0xf1, 0x03, 0x44, 0x04, 0x40, - 0x13, 0x74, 0x24, 0x00, 0x63, 0x18, 0x04, 0x02, 0x73, 0x00, 0x50, 0x10, - 0x6f, 0xf0, 0x9f, 0xfd, 0x73, 0x24, 0x20, 0x7b, 0x23, 0x26, 0x00, 0x10, - 0x73, 0x00, 0x10, 0x00, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x22, 0x80, 0x10, - 0x73, 0x24, 0x20, 0x7b, 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x10, 0x00, 0x00, - 0x67, 0x00, 0x00, 0x30, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x24, 0x80, 0x10, + 0x6f, 0x00, 0xc0, 0x00, 0x6f, 0x00, 0x40, 0x0d, 0x6f, 0x00, 0x40, 0x07, + 0x0f, 0x00, 0xf0, 0x0f, 0x73, 0x10, 0x24, 0x7b, 0x73, 0x74, 0x08, 0x7b, + 0x13, 0x74, 0x04, 0x01, 0x63, 0x1a, 0x04, 0x00, 0x73, 0x24, 0x40, 0xf1, + 0x23, 0x20, 0x80, 0x10, 0x03, 0x44, 0x04, 0x40, 0x6f, 0x00, 0x40, 0x01, + 0x73, 0x24, 0x40, 0xf1, 0x23, 0x20, 0x80, 0x10, 0x03, 0x44, 0x04, 0x40, + 0x73, 0x60, 0x08, 0x7b, 0x13, 0x74, 0x14, 0x00, 0x63, 0x10, 0x04, 0x06, + 0x73, 0x74, 0x08, 0x7b, 0x13, 0x74, 0x04, 0x01, 0x63, 0x18, 0x04, 0x00, + 0x73, 0x24, 0x40, 0xf1, 0x03, 0x44, 0x04, 0x40, 0x6f, 0x00, 0x00, 0x01, + 0x73, 0x24, 0x40, 0xf1, 0x03, 0x44, 0x04, 0x40, 0x73, 0x60, 0x08, 0x7b, + 0x13, 0x74, 0x24, 0x00, 0x63, 0x14, 0x04, 0x06, 0x73, 0x00, 0x50, 0x10, + 0x6f, 0xf0, 0xdf, 0xf9, 0x73, 0x74, 0x08, 0x7b, 0x13, 0x74, 0x04, 0x01, + 0x63, 0x18, 0x04, 0x00, 0x73, 0x24, 0x20, 0x7b, 0x23, 0x26, 0x00, 0x10, + 0x6f, 0x00, 0x00, 0x01, 0x73, 0x24, 0x20, 0x7b, 0x23, 0x26, 0x00, 0x10, + 0x73, 0x60, 0x08, 0x7b, 0x73, 0x00, 0x10, 0x00, 0x73, 0x74, 0x08, 0x7b, + 0x13, 0x74, 0x04, 0x01, 0x63, 0x18, 0x04, 0x00, 0x73, 0x24, 0x40, 0xf1, + 0x23, 0x22, 0x80, 0x10, 0x6f, 0x00, 0x00, 0x01, 0x73, 0x24, 0x40, 0xf1, + 0x23, 0x22, 0x80, 0x10, 0x73, 0x60, 0x08, 0x7b, 0x73, 0x24, 0x20, 0x7b, + 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x10, 0x00, 0x00, 0x67, 0x00, 0x00, 0x30, + 0x73, 0x74, 0x08, 0x7b, 0x13, 0x74, 0x04, 0x01, 0x63, 0x18, 0x04, 0x00, + 0x73, 0x24, 0x40, 0xf1, 0x23, 0x24, 0x80, 0x10, 0x6f, 0x00, 0x00, 0x01, + 0x73, 0x24, 0x40, 0xf1, 0x23, 0x24, 0x80, 0x10, 0x73, 0x60, 0x08, 0x7b, 0x73, 0x24, 0x20, 0x7b, 0x73, 0x00, 0x20, 0x7b }; -static const unsigned int debug_rom_raw_len = 116; +static const unsigned int debug_rom_raw_len = 260; diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 49717e55..3a327126 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -1421,6 +1421,7 @@ dcsr_csr_t::dcsr_csr_t(processor_t* const proc, const reg_t addr): ebreakvs(false), ebreakvu(false), v(false), + mprven(false), cause(0), ext_cause(0), cetrig(0), @@ -1450,6 +1451,7 @@ reg_t dcsr_csr_t::read() const noexcept { result = set_field(result, DCSR_STEP, step); result = set_field(result, DCSR_PRV, prv); result = set_field(result, CSR_DCSR_V, v); + result = set_field(result, DCSR_MPRVEN, mprven); result = set_field(result, DCSR_PELP, pelp); return result; } @@ -1464,6 +1466,7 @@ bool dcsr_csr_t::unlogged_write(const reg_t val) noexcept { ebreakvs = proc->extension_enabled('H') ? get_field(val, CSR_DCSR_EBREAKVS) : false; ebreakvu = proc->extension_enabled('H') ? get_field(val, CSR_DCSR_EBREAKVU) : false; v = proc->extension_enabled('H') ? get_field(val, CSR_DCSR_V) : false; + mprven = get_field(val, CSR_DCSR_MPRVEN); pelp = proc->extension_enabled(EXT_ZICFILP) ? static_cast(get_field(val, DCSR_PELP)) : elp_t::NO_LP_EXPECTED; cetrig = proc->extension_enabled(EXT_SMDBLTRP) ? get_field(val, DCSR_CETRIG) : false; diff --git a/riscv/csrs.h b/riscv/csrs.h index 97fd0f18..f076aaab 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -725,6 +725,7 @@ class dcsr_csr_t: public csr_t { bool ebreakvs; bool ebreakvu; bool v; + bool mprven; uint8_t cause; uint8_t ext_cause; bool cetrig; diff --git a/riscv/mmu.h b/riscv/mmu.h index 305d502c..94f3a97f 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -508,7 +508,7 @@ private: { return proc != nullptr && !(proc->state.mnstatus && !get_field(proc->state.mnstatus->read(), MNSTATUS_NMIE)) - && !proc->state.debug_mode + && (!proc->state.debug_mode || get_field(proc->state.dcsr->read(), DCSR_MPRVEN)) && get_field(proc->state.mstatus->read(), MSTATUS_MPRV); }