Skip to content

Add DCSR.MPRVEN support #1882

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

fk-sc
Copy link

@fk-sc fk-sc commented Dec 20, 2024

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.
  • DCSR.MPRVEN decreases the number of required abstract commands to read virtual memory.

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 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

@fk-sc
Copy link
Author

fk-sc commented Dec 20, 2024

I've also added tests targeting this feature: riscv-software-src/riscv-tests#599

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 <f.khaydari@syntacore.com>
@fk-sc fk-sc force-pushed the fk-sc/mprven-support branch from 372448d to 95af514 Compare December 20, 2024 12:52
@fk-sc
Copy link
Author

fk-sc commented Dec 20, 2024

@aswaterman, @rtwfroody, would you kindly take a look?

Copy link
Collaborator

@aswaterman aswaterman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had thought that not using dscratch1 was a goal of this sample debug ROM, but I'll defer to @rtwfroody

@rtwfroody
Copy link
Contributor

@aswaterman Can you approve the workflows for this change?

@aswaterman
Copy link
Collaborator

Yep.

Comment on lines +30 to +31
csrw CSR_DSCRATCH1, s1 // Save s1
csrrci s1, CSR_DCSR, DCSR_MPRVEN // Save DCSR and clear MPRVEN
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This clobbers s1. Now the debugger can't access it anymore.

Also you're going through a bunch of effort here to clear dcsr.mprven while in debug mode, but if you're clearing it then when does the bit actually have an effect?

Copy link
Author

@fk-sc fk-sc Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the use of register s1:
The register s1 is used within the debug ROM to save and restore the DCSR register, specifically to manage the MPRVEN bit. After the debug ROM execution, s1 is restored to its original value, ensuring that the debugger can access it as before. This approach maintains the integrity of s1 for debugger operations.

Clarification on MPRVEN bit management:
The MPRVEN bit is cleared within the debug ROM to prevent unwanted virtual address translations during ROM execution. However, it is crucial that this bit is set when the debugger initiates memory accesses. The debug ROM's role is to ensure a controlled environment, and the MPRVEN bit will have its intended effect when the debugger performs memory operations post-ROM execution.

@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can the debugger set bits in dcsr if here you overwrite it with a previously saved value? The debugger has to be able to set bits like ebreakm and step.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your feedback! I understand your concern about the debugger's ability to set bits like ebreakm and step in the DCSR register.

As I understand, the debugger modifies the DCSR only in whereto section (section for progbuf and abstract commands code). And we clear MPRVEN only inside of debug ROM which is not intersect with whereto. This means that restoring the entire DCSR register (including MPRVEN) should not interfere with the debugger's ability to set other bits like ebreakm and step during normal operation.

Copy link

@wissygh wissygh Mar 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But additional dscratch2 may be needed to support this when base address of debug is not ZERO. @fk-sc @rtwfroody

In Rocket-chip: https://github.com/chipsalliance/rocket-chip/blob/f517abbf41abb65cea37421d3559f9739efd00a9/scripts/debug_rom/debug_rom_nonzero.S#L51C7-L51C29

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wissygh this is not the case for spike

Copy link
Contributor

@aap-sc aap-sc Mar 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wissygh just to elaborate. This patch does not mean that dscratch2 becomes unusable in any way. Whether or not dscratch register is used is an implementation detail specific to the design/implementation.

This change allows us to implement support for hw address translation in spike (do note that this not only updates the ROM image - it has some changes in the codebase of the simulator). This change is required to test relevant support in riscv-openocd. It has nothing to do with rocket-chip or other designs.

@fk-sc fk-sc requested a review from rtwfroody January 28, 2025 08:55
@fk-sc
Copy link
Author

fk-sc commented Jan 29, 2025

@rtwfroody would you kindly take a look again?

@aap-sc
Copy link
Contributor

aap-sc commented Feb 26, 2025

@rtwfroody ping)

Copy link
Contributor

@rtwfroody rtwfroody left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. I've read over this again and now it makes sense to me. Sorry for not reading more closely the first time around. Thanks for your explanations.

@fk-sc
Copy link
Author

fk-sc commented Mar 11, 2025

@aswaterman could you please consider merging this? I already have tests for OpenOCD in riscv_tests repository that depend on this patch: pr599

There are some concerns from @wissygh that indicate that this may break compatibility (I'm not sure that there was one, to be fair) with rocket-chip project for some configurations of their designs. This compatibility was never intended to be in the scope of this MR, though. If this is an issue - someone could try to address this in a subsequent commit. I can participate too if there is a request for it.

@fk-sc fk-sc requested a review from aswaterman March 11, 2025 11:19
@wissygh
Copy link

wissygh commented Mar 12, 2025

@aswaterman could you please consider merging this? I already have tests for OpenOCD in riscv_tests repository that depend on this patch: pr599

There are some concerns from @wissygh that indicate that this may break compatibility (I'm not sure that there was one, to be fair) with rocket-chip project for some configurations of their designs. This compatibility was never intended to be in the scope of this MR, though. If this is an issue - someone could try to address this in a subsequent commit. I can participate too if there is a request for it.

What concerns me is whether Spike will continue to increase its use of dscratchX if similar issues arise in the future. Additionally, Spike is considered an important reference when designing the microarchitecture. What I'm trying to say is, is there a better way to solve this problem?

@aap-sc
Copy link
Contributor

aap-sc commented Mar 12, 2025

@wissygh

Additionally, Spike is considered an important reference when designing the microarchitecture.

The thing is that this patch extends existing functionality. The fact that the new ROM becomes incompatible with some older rocket-chip design is a direct consequence of that (we introduce a new micro architectural feature that should be taken into account).

What concerns me is whether Spike will continue to increase its use of dscratchX if similar issues arise in the future

I don't think that we require to increase the number of dsccrach registers in future. It could be possible to avoid it. However, I don't think that we can reduce the number of used scratch registers in this specific case.

  1. It is possible to allocate an extra per-hart storage and store whatever information we need there. However, this will require us to modify the code of the simulator and re-design the way storage space for debug mode is allocated. I'm not sure if this can be classified as "better way", though.
  2. Even if the above change is made we still need 2 things in order to operate: mhartid (to uniquely identify hart and it's associated storage) and the current state of of DCSR (to disable mprven). The latter allows for ROM code to perform access to physical addresses allowing to use per-hart storage as usual.

What I'm trying to say is, is there a better way to solve this problem?

Given the summary above I don't think there is. However, if in future we need to take into account some new issue - it should be possible to implement a solution that won't require more scratch registers.

@aswaterman
Copy link
Collaborator

aswaterman commented Mar 15, 2025

I share @wissygh's concern but don't have a great solution. But one improvement I'd recommend is to use #ifdef USE_MPRVEN guards (or pick a better name if you have one) so that dscratch1 is only needed if the code is assembled with -DUSE_MPRVEN. I'm willing to merge it after we make that improvement.

@rtwfroody
Copy link
Contributor

I think you can avoid using dscratch1 by duplicating some code. You'd write something like:

if (dcsr.mprven) {
   clear_mprven();
   // do all the usual things, but make sure to set_mprven() in a few places where necessary
} else {
  // do all the usual things, don't touch mprven
}

Thinking of this more, the comment says we disable mprven to avoid address translation when fetching code from the debug_rom. What about fetching code while mprven is set? E.g. the few instructions before you disable mprven, and the fetching of instructions orchestrated pointed at by whereto?

@aswaterman
Copy link
Collaborator

Avoiding use of dscratch1 by restructuring the code would be an improvement, IMO.

@wissygh
Copy link

wissygh commented Mar 18, 2025

I noticed that when virt2phys_mode is set to hw, OpenOCD assert dcsr.mprven before memory access and deassert dcsr.mprven after memory access through the progbuffer, respectively. Given that this method is already supported, is it still necessary to separately write to dcsr.mprven? @aap-sc @fk-sc @rtwfroody @aswaterman

image

riscv-collab/riscv-openocd#386

@fk-sc
Copy link
Author

fk-sc commented Mar 18, 2025

I noticed that when virt2phys_mode is set to hw, OpenOCD assert dcsr.mprven before memory access and deassert dcsr.mprven after memory access through the progbuffer, respectively. Given that this method is already supported, is it still necessary to separately write to dcsr.mprven?

When running OpenOCD with Spike, the simulator ignores writes to dcsr.mprven (it behaves like it hardwired to zero). Consequently, hardware-assisted virtual-to-physical address translation doesn't work properly, and "virtual" address accesses directly map to physical memory. OpenOCD’s automated mprven toggling thus has no effect in this environment. The patch corrects this behavior by allowing Spike to honor dcsr.mprven writes, enabling proper translation. This is the reason this MR exists. @wissygh

@wissygh
Copy link

wissygh commented Mar 18, 2025

I noticed that when virt2phys_mode is set to hw, OpenOCD assert dcsr.mprven before memory access and deassert dcsr.mprven after memory access through the progbuffer, respectively. Given that this method is already supported, is it still necessary to separately write to dcsr.mprven?

When running OpenOCD with Spike, the simulator ignores writes to dcsr.mprven (it behaves like it hardwired to zero). Consequently, hardware-assisted virtual-to-physical address translation doesn't work properly, and "virtual" address accesses directly map to physical memory. OpenOCD’s automated mprven toggling thus has no effect in this environment. The patch corrects this behavior by allowing Spike to honor dcsr.mprven writes, enabling proper translation. This is the reason this MR exists. @wissygh

Yes, therefore I believe that Spike only needs to add support for the implementation of mprven and does not require modifications to the debug_rom.

@aap-sc
Copy link
Contributor

aap-sc commented Mar 18, 2025

Yes, therefore I believe that Spike only needs to add support for the implementation of mprven and does not require modifications to the debug_rom.

@wissygh

As soon as we add support for mprven we have to update debug rom because the debug rom itself performs memory accesses and expects these memory accesses to avoid memory translation

@fk-sc
Copy link
Author

fk-sc commented Mar 18, 2025

@rtwfroody, I will try to implement your idea. If successful, I’ll create a separate PR. For now, I’ll use the temporary #ifdef solution suggested by @aswaterman.

Regarding your concerns about instruction fetch: the RISC-V Privileged Specification (section 3.1.6.3, Memory Privilege in mstatus Register) states that MPRV should not affect instruction address translation. I’ve double-checked Spike’s implementation, and it behaves correctly.

@fk-sc
Copy link
Author

fk-sc commented Mar 18, 2025

@wissygh, are you okay with the approach suggested by @aswaterman?

@aswaterman
Copy link
Collaborator

I would strongly prefer to wait until you've gotten @rtwfroody's scheme working, rather than using the #ifdef scheme as a temporary solution.

@wissygh
Copy link

wissygh commented Mar 19, 2025

I noticed that when virt2phys_mode is set to hw, OpenOCD assert dcsr.mprven before memory access and deassert dcsr.mprven after memory access through the progbuffer, respectively. Given that this method is already supported, is it still necessary to separately write to dcsr.mprven?

When running OpenOCD with Spike, the simulator ignores writes to dcsr.mprven (it behaves like it hardwired to zero). Consequently, hardware-assisted virtual-to-physical address translation doesn't work properly, and "virtual" address accesses directly map to physical memory. OpenOCD’s automated mprven toggling thus has no effect in this environment. The patch corrects this behavior by allowing Spike to honor dcsr.mprven writes, enabling proper translation. This is the reason this MR exists. @wissygh

Given that this method is already supported, is it still necessary to separately write to dcsr.mprven?

What I want to express here is that if the debugger is only capable of debugging hardware address translation by setting virt2phys_mode to hw, perhaps there's no need to modify the debug_rom. However, I realized that I might have overlooked an issue: the progbuffer's memory access instructions can also cause exceptions, which means the instruction to clear mprven might not be executed, and this could still affect the execution of memory access instructions in the debug_rom.

@wissygh
Copy link

wissygh commented Mar 19, 2025

@wissygh, are you okay with the approach suggested by @aswaterman?

OK!

@aap-sc
Copy link
Contributor

aap-sc commented Mar 19, 2025

@wissygh

the progbuffer's memory access instructions can also cause exceptions, which means the instruction to clear mprven might not be executed, and this could still affect the execution of memory access instructions in the debug_rom.

Aside from that there is also "abstract memory access" command mechanism that does not use progbuf at all (just FYI).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants