Skip to content
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

etrigger priority #1084

Open
jiahzhang opened this issue Nov 18, 2024 · 10 comments · May be fixed by #1085
Open

etrigger priority #1084

jiahzhang opened this issue Nov 18, 2024 · 10 comments · May be fixed by #1085

Comments

@jiahzhang
Copy link

Must all etrigger-firing exceptions have the highest priority, or can a subset have lower priorities? For example, a load page fault etrigger having lower priority than an instruction address mcontrol6 trigger.

@pdonahue-ventana
Copy link
Collaborator

"etrigger" is defined to be higher priority than "mcontrol6 execute address before" on the first instruction of the handler. To do it the other way would lose the etrigger.

As specified:

  • page fault
  • etrigger fires before fetching the first instruction of the page fault handler
  • debugger eventually resumes to the first instruction of the page fault handler
  • mcontrol6 fires on the first instruction of the page fault handler
  • debugger eventually resumes and executes the page fault handler

The alternative is worse because the etrigger doesn't ever happen:

  • page fault
  • mcontrol6 fires on the first instruction of the page fault handler
  • debugger eventually resumes and executes the page fault handler

Depending on how the debugger is written, this might matter. (It also would matter if you're simultaneously running an external debugger and a native debugger and the two triggers belong to the two different debuggers. We don't always guarantee that two concurrent debuggers will work, but they would in this case.)

@jiahzhang
Copy link
Author

jiahzhang commented Nov 18, 2024

I meant more in the scenario if the mcontrol6 address was the address of the exception-causing instruction.

@pdonahue-ventana
Copy link
Collaborator

This scenario?

  • mcontrol6 has load=0, execute=1, tdata2=X
  • page tables for address Y will get a page fault
  • address X is a load instruction from address Y
  • etrigger has tdata2[13]=1 (fire on load page fault)
  • PC becomes X and then what happens next?

@jiahzhang
Copy link
Author

Yep. I'm wondering if the etrigger still has to fire before the mcontrol6.

@pdonahue-ventana
Copy link
Collaborator

The etrigger won't fire at all. Table 13 in the debug spec says that "mcontrol6 execute address before" is higher priority than load page fault (cause 13). The etrigger will fire only if we take a load page fault. The mcontrol6 trigger fired which prevents the page fault from happening which prevents the etrigger from happening.

@jiahzhang
Copy link
Author

jiahzhang commented Nov 18, 2024

Good to know. This doesn't seem very clear in the spec. "etrigger" is a generic term for an exception-related trigger. Perhaps it would be clearer to indicate the etrigger priority corresponds to its programmed exception(s).

The way I read it, the "etrigger" priority superseded the original exception. In which case, the fact that the load page fault could only occur if there was no mcontrol6 address trigger didn't matter (therefore, we have to evaluate for all possible exceptions).

@pdonahue-ventana
Copy link
Collaborator

The way I read it, the "etrigger" priority superseded the original exception.

What is the original exception? In the scenario above there is no exception at all.

  • mcontrol6 has load=0, execute=1, tdata2=X
  • page tables for address Y will get a page fault
  • address X is a load instruction from address Y
  • etrigger has tdata2[13]=1 (fire on load page fault)
  • PC becomes X
  • mcontrol6 fires with higher priority than any fault on address X or address Y
  • halt (which is not an exception) or take a breakpoint exception (which etrigger is not programmed to look at in this scenario)

We never access address Y. We actually never even access address X because mcontrol6 fires before we fetch the instruction. If the mcontrol6 didn't exist then I agree that we would have taken the page fault and then the etrigger.

Looking at the priv spec's synchronous exception priority, the RISC-V execution model is basically:

  • fetch
  • decode
  • execute

Any exceptions are dealt with in the appropriate phase:

  • fetch. Deal with any instruction page faults or access faults etc.
  • decode. Deal with any illegal instructions, virtual instructions, ecalls, ebreaks, etc.
  • execute. Deal with any load/store page faults or access faults, etc.

Debug adds triggers to each phase and it adds a phase before fetch:

  • Deal with anything leftover from the previous instruction/trap: etrigger, itrigger, timing=after triggers, etc.
  • fetch. Deal with any instruction page faults or access faults, execute triggers, etc.
  • decode. Deal with any illegal instructions, virtual instructions, ecalls, ebreaks, etc.
  • execute. Deal with any load/store page faults or access faults, load/store triggers, etc.

If you get an execute trigger firing in the fetch phase then you don't successfully fetch an instruction. Therefore, there's no instruction to decode and there's no load to execute and you won't know that it got a page fault. Of course, implementations can possibly run ahead but they need to preserve the illusion that everything happens sequentially like this.

@jiahzhang
Copy link
Author

By "original exception" I mean the exception corresponding to the etrigger.

I agree that is the presumed execution model, but it's not like this is something stated either. The confusion I had with the debug spec's priority table is it does seem to require "runahead" behavior to determine possible exceptions.

For instance, there is no text that the etrigger priority called out in the table deals with

etrigger and itrigger triggers will always be taken from a trap handler before the first
instruction of the handler

Instead, it is a blanket statement that says etrigger is higher priority than an instruction address breakpoint. If you feel the text is clear enough about this I'll close the issue.

@pdonahue-ventana
Copy link
Collaborator

I don't exactly understand the scenario you're worried about but I do agree that etrigger isn't defined very well. For example, itrigger clearly says "This trigger can fire when an interrupt trap is taken." On the other hand, etrigger doesn't really say when it matches. It says that it fires on codes in mcause rather than firing on exceptions.

Would it be clearer if etrigger said this?

This trigger can match when a trap is taken due to an exception. The trigger may be configured to match on up to XLEN of the Exception Codes defined in mcause (described in the Privileged Spec, with Interrupt=0). Those causes are configured by writing the corresponding bit in tdata2. (e.g. to have etrigger match on an illegal instruction trap, the debugger sets bit 2 in tdata2.)

Then it already explains what happens next:

When the trigger matches, it fires after the trap occurs, just before the first instruction of the trap handler is executed.

That clearly separates matching from firing. Matching happens on the trap itself (subject to per-trap filtering) and firing happens immediately before fetching the first instruction of the handler.

@jiahzhang
Copy link
Author

Yes, that is much clearer. I just realized I was looking at an older version that did not even have this statement

When the trigger matches, it fires after the trap occurs, just before the first instruction of the trap handler is executed.

@pdonahue-ventana pdonahue-ventana linked a pull request Nov 20, 2024 that will close this issue
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 a pull request may close this issue.

2 participants