On 8. May 2022, at 14:08, Peter Maydell <[email protected]> wrote: > > On Sat, 7 May 2022 at 14:44, Chris Howard <[email protected]> wrote: >> >> Hi, I’m writing a simple debugger in assembly code for the Raspberry Pi 3B >> (in aarch64). >> >> I’m using QEMU 7.0.0. Everything is running in EL1. (I have MDE and KDE set >> in MDSCR_EL1). >> >> I’m coming across Unexpected Behaviour when playing with single-stepping: >> >> It appears that single-stepping is enabled (ie. an exception is generated >> after every instruction) when the SS bit (bit-0) is set in MDSCR_EL1 and >> debug events are enabled in the CPSR (“D” bit clear) *** irrespective of >> whether the SS bit (bit-21) is set in CPSR or not ***. >> >> I thought the SS bit (bit-21) needs to be set in CPSR for single-stepping to >> occur (and that it gets cleared whenever an exception is taken and needs to >> be reset if one wants to single-step again). >> >> Have I misunderstood / misconfigured something, or is this a bug? > > I think you've misunderstood how the architectural single > step works. This is described in section D2.12 of the Arm ARM > (DDI0487H.a), but briefly, there is a state machine with three > states: Inactive, Active-not-pending, and Active-pending. > > * Inactive is when MDSCR_EL1.SS is 0 or debug exceptions are > disabled from the current EL or security state. > > * Active-not-pending is when we're not Inactive (ie MDSCR_EL1.SS is 1 > and so on) and PSTATE.SS is 1. This is the state for "we're currently > pointing at the instruction we would like to step". The CPU > does the step by doing "execute this one instruction, and then > clear PSTATE.SS". It does *not* take a "single step completed" > exception. (I ignore for the moment the possibility that the > insn resulted in some other exception.) > > * Active-pending is when we're not Inactive and PSTATE.SS is 0. > This state means "Software step is active, and a software step > is pending on the current instruction". > The usual way we get here is that we were in Active-not-pending > and then we executed the instruction and cleared PSTATE.SS. > But you can also get here in other ways (as your test case does). > In Active-pending state, the CPU does "take a software step > exception immediately, without doing anything else" -- which is > what you see. > > In other words, the design effectively separates out the > "execute one instruction" part from the "take the exception > that says we completed a step" part. (This separation is > irrelevant for the 'normal case' where the stepped instruction > doesn't cause any exceptions and no interrupts arrive either, > but it can matter if there is some interrupt to be taken. For > instance, suppose that we do a step, and while the insn is > executing an interrupt comes in that is routed to EL3. We > want to take that interrupt first, before taking the > 'single step complete' exception. Because the distinction > between 'active-not-pending' and 'active-pending' is stored > in PSTATE.SS, this works automatically -- we go to EL3, do > whatever the interrupt handler does, and then on the eret > to where we started, PSTATE.SS is restored to 0: so we then > correctly take the 'single step complete' exception without > executing another instruction.) > > So if you don't want to see single-step exceptions you need > to make sure you stay in the Inactive state. > > thanks > — PMM
I had indeed misunderstood :-) even though I had looked at that section (and the state machine diagram) :-/ Thanks for the EXCELLENT explanation! Very much appreciated. —chris
