From 372448d9e7d680f46bae748a713ace116cc55db9 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 while executing ROM To avoid unwanted address translation in while debug_rom.S executed DCSR.MPRVEN bit has to be cleared on entry and restored on exit. Updated version of debug_rom.S does the following: * On _entry: clears DCSR.MPRVEN bit, stores previous DCSR value to S1 and stores previous S1 value to DSCRATCH01 * On _exception: restores S1 value from DSCRATCH01 * On _resume/going: restores S1 and DCSR values Signed-off-by: Farid Khaydari --- debug_rom/debug_rom.S | 12 +++++++++++- debug_rom/debug_rom.h | 22 ++++++++++++---------- riscv/csrs.cc | 3 +++ riscv/csrs.h | 1 + riscv/mmu.h | 2 +- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/debug_rom/debug_rom.S b/debug_rom/debug_rom.S index 2d361397e3..6ed1d21433 100755 --- a/debug_rom/debug_rom.S +++ b/debug_rom/debug_rom.S @@ -23,7 +23,12 @@ _entry: // This fence is required because the execution may have written something // into the Abstract Data or Program Buffer registers. fence - csrw CSR_DSCRATCH0, s0 // Save s0 to allow signaling MHARTID + csrw CSR_DSCRATCH0, s0 // Save s0 to allow signaling MHARTID + + // We need to disable privilege modification to avoid + // address translation in debug_rom memory accesses + csrw CSR_DSCRATCH1, s1 // Save s1 + csrrci s1, CSR_DCSR, DCSR_MPRVEN // Save DCSR and clear MPRVEN // We continue to let the hart know that we are halted in order that // a DM which was reset is still made aware that a hart is halted. @@ -47,6 +52,7 @@ _exception: // We need this in case the user tried an abstract write to a // non-existent CSR. csrr s0, CSR_DSCRATCH0 + csrr s1, CSR_DSCRATCH1 // Restore s1 sw zero, DEBUG_ROM_EXCEPTION(zero) // Let debug module know you got an exception. ebreak @@ -54,6 +60,8 @@ going: csrr s0, CSR_MHARTID sw s0, DEBUG_ROM_GOING(zero) // When debug module sees this write, the GO flag is reset. csrr s0, CSR_DSCRATCH0 // Restore s0 here + csrw CSR_DCSR, s1 // Restore DSCR + csrr s1, CSR_DSCRATCH1 // Restore s1 fence fence.i jalr zero, zero, %lo(whereto) // Debug module will put different instructions and data in the RAM, @@ -64,6 +72,8 @@ _resume: csrr s0, CSR_MHARTID sw s0, DEBUG_ROM_RESUMING(zero) // When Debug Module sees this write, the RESUME flag is reset. csrr s0, CSR_DSCRATCH0 // Restore s0 + csrw CSR_DCSR, s1 // Restore DSCR + csrr s1, CSR_DSCRATCH1 // Restore s1 dret // END OF ACTUAL "ROM" CONTENTS. BELOW IS JUST FOR LINKER SCRIPT. diff --git a/debug_rom/debug_rom.h b/debug_rom/debug_rom.h index 7edd5f68f9..92fa505f82 100644 --- a/debug_rom/debug_rom.h +++ b/debug_rom/debug_rom.h @@ -1,13 +1,15 @@ 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, + 0x6f, 0x00, 0xc0, 0x00, 0x6f, 0x00, 0x40, 0x07, 0x6f, 0x00, 0x00, 0x04, + 0x0f, 0x00, 0xf0, 0x0f, 0x73, 0x10, 0x24, 0x7b, 0x73, 0x90, 0x34, 0x7b, + 0xf3, 0x74, 0x08, 0x7b, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x20, 0x80, 0x10, + 0x03, 0x44, 0x04, 0x40, 0x13, 0x74, 0x14, 0x00, 0x63, 0x16, 0x04, 0x02, + 0x73, 0x24, 0x40, 0xf1, 0x03, 0x44, 0x04, 0x40, 0x13, 0x74, 0x24, 0x00, + 0x63, 0x1e, 0x04, 0x02, 0x73, 0x00, 0x50, 0x10, 0x6f, 0xf0, 0x9f, 0xfd, + 0x73, 0x24, 0x20, 0x7b, 0xf3, 0x24, 0x30, 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, - 0x73, 0x24, 0x20, 0x7b, 0x73, 0x00, 0x20, 0x7b + 0x73, 0x24, 0x20, 0x7b, 0x73, 0x90, 0x04, 0x7b, 0xf3, 0x24, 0x30, 0x7b, + 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x10, 0x00, 0x00, 0x67, 0x00, 0x00, 0x30, + 0x73, 0x24, 0x40, 0xf1, 0x23, 0x24, 0x80, 0x10, 0x73, 0x24, 0x20, 0x7b, + 0x73, 0x90, 0x04, 0x7b, 0xf3, 0x24, 0x30, 0x7b, 0x73, 0x00, 0x20, 0x7b }; -static const unsigned int debug_rom_raw_len = 116; +static const unsigned int debug_rom_raw_len = 144; diff --git a/riscv/csrs.cc b/riscv/csrs.cc index ea535f6fe3..a1142d9510 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -1345,6 +1345,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), @@ -1374,6 +1375,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; } @@ -1388,6 +1390,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 278bdb3713..cd4f36937d 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -697,6 +697,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 224b8f5954..0eb899419e 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -486,7 +486,7 @@ class mmu_t { 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); }