In v8-A the following registers provide the OS save and restore mechanism:
The OS Lock Access Register, OSLAR_EL1 locks the OS lock to restrict access to debug registers before starting an OS save sequence, and releases the OS lock after an OS restore sequence. The OS Lock Status Register, OSLSR_EL1 shows the status of the OS lock.
The External Debug Execution Control Register, EDECR can be programmed to generate a debug event when the OS lock is cleared.
The OS Double Lock Register, OSDLR_EL1 locks out the external debug interface entirely. Only used by software immediately before a powerdown sequence.
See also Debug over power-down on page 252.
11.2.1 Behavior when the OS lock is locked
The main purpose of the OS lock is to prevent updates to debug registers during an OS save or OS restore operation. The OS lock is locked on a Cold reset.
When the OS lock is locked:
Access to debug registers through the system register interface is mainly unchanged, except that: — the registers can be read and written without side-effects
— fields in MDSCR_EL1 and OSECCR_EL1 that are normally read-only become read/write. These changes mean the current state can be saved or restored. For more information, see Accessing debug system registers on page 63.
Access to some debug registers by external debug interface is restricted to prevent an external debugger modifying the registers that are being saved or restored. For more information, see External debug interface register access permissions on page 195.
Software debug events other than Software Breakpoint Instruction debug events are ignored. The OS lock has no effect on Software Breakpoint Instruction debug events and Halting debug events.
11.2.2 Behavior on unlocking the OS lock
When the OS lock is unlocked, an OS Unlock Catch debug event is generated if EDECR.OUCE is set to 1. See OS Unlock Catch debug event on page 136.
11.2.3 Behavior when the OS double-lock is locked
The OS double-lock is locked before a power-down sequence. The OS double-lock ensures that it is safe to remove Core power by forcing the debug interfaces to be quiescent.
When DoubleLockStatus() == TRUE:
Access to debug registers by the external debug interface is restricted, so that the interface is quiescent prior to removing power. See External debug interface register access permissions on page 195.
Software debug events, other than Software Breakpoint Instruction debug events, are ignored. Halting is prohibited. See Halting allowed and halting prohibited on page 139.
Note: Pending Halting debug events might be lost when Core power is removed. No asynchronous debug events are WFI or WFE wake-up events.
Software must synchronize the update to OSDLR_EL1 before it indicates to the system that Core power can be removed. The interface between a processor and its power controller is IMPLEMENTATION DEFINED.
Typically, software indicates that Core power can be removed by entering the Wait For Interrupt state, and so software must explicitly synchronize the OSDLR_EL1 update before issuing the WFI instruction.
OSDLR_EL1.DLK is ignored and DoubleLockStatus() == FALSE if either: the processor is in Debug state
DBGPRCR_EL1.CORENPDRQ is set to 1.
Note: It is possible to enter Debug state with OSDLR_EL1.DLK set to 1. This is because a context synchronization operation is required to ensure the OS double-lock is locked, meaning that Debug state might be entered before the OSDLR_EL1 update is synchronized.
Because OSDLR_EL1.DLK is ignored when DBGPRCR_EL1.CORENPDRQ is set to 1, and an external debugger can write to DBGPRCR_EL1.CORENPDRQ, software must not rely on using the OS double-lock to disable debug exceptions and/or prohibit halting. ARM deprecates use of the OS double-lock for these purposes, and instead recommends software:
Uses the OS lock to disable debug exceptions during save/restore sequences.
Uses the debug authentication interface to prohibit halting and external debug access to debug registers at times other than prior to removing power.
As the purpose of the OS double-lock is to ensure that it is safe to remove Core power, it is important that the implementation avoids races that defeat this purpose. ARM recommends that:
Once the write to OSDLR_EL1.DLK has been synchronized by a context synchronization operation (CSO) and DoubleLockStatus() == TRUE, a processor must:
— not allow a debug event generated before the CSO to cause entry to Debug state or wake-up a WFI or WFE instruction after the CSO has completed
— complete any external debug access started before the CSO by the time the CSO completes. Note: A debug register access might be in progress when software sets OSDLR_EL1.DLK to 1. An
implementation must not permit the synchronization of locking the OS double-lock to stall indefinitely waiting for that access to complete. This means that any debug register access that is in progress when software sets OSDLR_EL1.DLK to 1 must complete or return an error as soon as possible.
If a write to DBGPRCR_EL1 or EDPRCR made when OSDLR_EL1.DLK == 1 changes CORENPDRQ from 1 to 0, meaning DoubleLockStatus() changes from FALSE to TRUE, then before signaling to the system that CORENPDRQ has been cleared and emulation of power-down is no longer requested (meaning the system can remove Core power) the processor must ensure that all the requirements for
DoubleLockStatus() == TRUE listed above are met.
In the standard OS save sequence, the OS lock is locked before the OS double-lock is locked. This means that writes to CORENPDRQ are being ignored by the time the OS double-lock is locked. However, if
DoubleLockStatus() == FALSE, an external debugger can clear the OS lock at any time (and then write to
11.2.4 Pseudocode details of the OS lock and OS double-lock
// Function 61: OSLockStatus // =========================
boolean OSLockStatus()
// Returns the value of OSLSR_EL1.OSLK: return OSLSR_EL1.OSLK == ‘1’;
// Function 62: DoubleLockStatus // =============================
boolean DoubleLockStatus()
// Returns the status of the OS double-lock:
// FALSE if OSDLR_EL1.DLK == 0 or DBGPRCR_EL1.CORENPDRQ == 1 or the processor is in Debug state. // TRUE if OSDLR_EL1.DLK == 1 and DBGPRCR_EL1.CORENPDRQ == 0 and the processor is in Non-debug // state.
return OSDLR_EL1.DLK == ‘1’ && DBGPRCR_EL1.CORENPDRQ == ‘0’ && !Halted();