Skip to content

Commit 080297b

Browse files
mrutland-armwilldeacon
authored andcommitted
arm64: defer clearing DAIF.D
For historical reasons we unmask debug exceptions in __cpu_setup(), but it's not necessary to unmask debug exceptions this early in the boot/idle entry paths. It would be better to unmask debug exceptions later in C code as this simplifies the current code and will make it easier to rework exception masking logic to handle non-DAIF bits in future (e.g. PSTATE.{ALLINT,PM}). We started clearing DAIF.D in __cpu_setup() in commit: 2ce39ad ("arm64: debug: unmask PSTATE.D earlier") At the time, we needed to ensure that DAIF.D was clear on the primary CPU before scheduling and preemption were possible, and chose to do this in __cpu_setup() so that this occurred in the same place for primary and secondary CPUs. As we cannot handle debug exceptions this early, we placed an ISB between initializing MDSCR_EL1 and clearing DAIF.D so that no exceptions should be triggered. Subsequently we rewrote the return-from-{idle,suspend} paths to use __cpu_setup() in commit: cabe1c8 ("arm64: Change cpu_resume() to enable mmu early then access sleep_sp by va") ... which allowed for earlier use of the MMU and had the desirable property of using the same code to reset the CPU in the cold and warm boot paths. This introduced a bug: DAIF.D was clear while cpu_do_resume() restored MDSCR_EL1 and other control registers (e.g. breakpoint/watchpoint control/value registers), and so we could unexpectedly take debug exceptions. We fixed that in commit: 744c6c3 ("arm64: kernel: Fix unmasked debug exceptions when restoring mdscr_el1") ... by having cpu_do_resume() use the `disable_dbg` macro to set DAIF.D before restoring MDSCR_EL1 and other control registers. This relies on DAIF.D being subsequently cleared again in cpu_resume(). Subsequently we reworked DAIF masking in commit: 0fbeb31 ("arm64: explicitly mask all exceptions") ... where we began enforcing a policy that DAIF.D being set implies all other DAIF bits are set, and so e.g. we cannot take an IRQ while DAIF.D is set. As part of this the use of `disable_dbg` in cpu_resume() was replaced with `disable_daif` for consistency with the rest of the kernel. These days, there's no need to clear DAIF.D early within __cpu_setup(): * setup_arch() clears DAIF.DA before scheduling and preemption are possible on the primary CPU, avoiding the problem we we originally trying to work around. Note: DAIF.IF get cleared later when interrupts are enabled for the first time. * secondary_start_kernel() clears all DAIF bits before scheduling and preemption are possible on secondary CPUs. Note: with pseudo-NMI, the PMR is initialized here before any DAIF bits are cleared. Similar will be necessary for the architectural NMI. * cpu_suspend() restores all DAIF bits when returning from idle, ensuring that we don't unexpectedly leave DAIF.D clear or set. Note: with pseudo-NMI, the PMR is initialized here before DAIF is cleared. Similar will be necessary for the architectural NMI. This patch removes the unmasking of debug exceptions from __cpu_setup(), relying on the above locations to initialize DAIF. This allows some other cleanups: * It is no longer necessary for cpu_resume() to explicitly mask debug (or other) exceptions, as it is always called with all DAIF bits set. Thus we drop the use of `disable_daif`. * The `enable_dbg` macro is no longer used, and so is dropped. * It is no longer necessary to have an ISB immediately after initializing MDSCR_EL1 in __cpu_setup(), and we can revert to relying on the context synchronization that occurs when the MMU is enabled between __cpu_setup() and code which clears DAIF.D Comments are added to setup_arch() and secondary_start_kernel() to explain the initial unmasking of the DAIF bits. Signed-off-by: Mark Rutland <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Mark Brown <[email protected]> Cc: Will Deacon <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 3a2d2ca commit 080297b

File tree

4 files changed

+16
-16
lines changed

4 files changed

+16
-16
lines changed

arch/arm64/include/asm/assembler.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@
5050
msr daif, \flags
5151
.endm
5252

53-
.macro enable_dbg
54-
msr daifclr, #8
55-
.endm
56-
5753
.macro disable_step_tsk, flgs, tmp
5854
tbz \flgs, #TIF_SINGLESTEP, 9990f
5955
mrs \tmp, mdscr_el1

arch/arm64/kernel/setup.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,15 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
298298
dynamic_scs_init();
299299

300300
/*
301-
* Unmask SError as soon as possible after initializing earlycon so
302-
* that we can report any SErrors immediately.
301+
* The primary CPU enters the kernel with all DAIF exceptions masked.
302+
*
303+
* We must unmask Debug and SError before preemption or scheduling is
304+
* possible to ensure that these are consistently unmasked across
305+
* threads, and we want to unmask SError as soon as possible after
306+
* initializing earlycon so that we can report any SErrors immediately.
307+
*
308+
* IRQ and FIQ will be unmasked after the root irqchip has been
309+
* detected and initialized.
303310
*/
304311
local_daif_restore(DAIF_PROCCTX_NOIRQ);
305312

arch/arm64/kernel/smp.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,13 @@ asmlinkage notrace void secondary_start_kernel(void)
264264
set_cpu_online(cpu, true);
265265
complete(&cpu_running);
266266

267+
/*
268+
* Secondary CPUs enter the kernel with all DAIF exceptions masked.
269+
*
270+
* As with setup_arch() we must unmask Debug and SError exceptions, and
271+
* as the root irqchip has already been detected and initialized we can
272+
* unmask IRQ and FIQ at the same time.
273+
*/
267274
local_daif_restore(DAIF_PROCCTX);
268275

269276
/*

arch/arm64/mm/proc.S

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,6 @@ SYM_FUNC_START(cpu_do_resume)
135135

136136
msr tcr_el1, x8
137137
msr vbar_el1, x9
138-
139-
/*
140-
* __cpu_setup() cleared MDSCR_EL1.MDE and friends, before unmasking
141-
* debug exceptions. By restoring MDSCR_EL1 here, we may take a debug
142-
* exception. Mask them until local_daif_restore() in cpu_suspend()
143-
* resets them.
144-
*/
145-
disable_daif
146138
msr mdscr_el1, x10
147139

148140
msr sctlr_el1, x12
@@ -466,8 +458,6 @@ SYM_FUNC_START(__cpu_setup)
466458
msr cpacr_el1, xzr // Reset cpacr_el1
467459
mov x1, #1 << 12 // Reset mdscr_el1 and disable
468460
msr mdscr_el1, x1 // access to the DCC from EL0
469-
isb // Unmask debug exceptions now,
470-
enable_dbg // since this is per-cpu
471461
reset_pmuserenr_el0 x1 // Disable PMU access from EL0
472462
reset_amuserenr_el0 x1 // Disable AMU access from EL0
473463

0 commit comments

Comments
 (0)