Skip to content

Commit 6459b84

Browse files
mrutland-armwilldeacon
authored andcommitted
arm64: entry: consolidate Cortex-A76 erratum 1463225 workaround
The workaround for Cortex-A76 erratum 1463225 is split across the syscall and debug handlers in separate files. This structure currently forces us to do some redundant work for debug exceptions from EL0, is a little difficult to follow, and gets in the way of some future rework of the exception entry code as it requires exceptions to be unmasked late in the syscall handling path. To simplify things, and as a preparatory step for future rework of exception entry, this patch moves all the workaround logic into entry-common.c. As the debug handler only needs to run for EL1 debug exceptions, we no longer call it for EL0 debug exceptions, and no longer need to check user_mode(regs) as this is always false. For clarity cortex_a76_erratum_1463225_debug_handler() is changed to return bool. In the SVC path, the workaround is applied earlier, but this should have no functional impact as exceptions are still masked. In the debug path we run the fixup before explicitly disabling preemption, but we will not attempt to preempt before returning from the exception. There should be no functional change as a result of this patch. Signed-off-by: Mark Rutland <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: James Morse <[email protected]> Cc: Will Deacon <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent c0b15c2 commit 6459b84

File tree

4 files changed

+53
-65
lines changed

4 files changed

+53
-65
lines changed

arch/arm64/kernel/cpu_errata.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,6 @@ cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *cap)
107107
}
108108

109109
#ifdef CONFIG_ARM64_ERRATUM_1463225
110-
DEFINE_PER_CPU(int, __in_cortex_a76_erratum_1463225_wa);
111-
112110
static bool
113111
has_cortex_a76_erratum_1463225(const struct arm64_cpu_capabilities *entry,
114112
int scope)

arch/arm64/kernel/entry-common.c

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,55 @@ asmlinkage void noinstr exit_el1_irq_or_nmi(struct pt_regs *regs)
109109
exit_to_kernel_mode(regs);
110110
}
111111

112+
#ifdef CONFIG_ARM64_ERRATUM_1463225
113+
static DEFINE_PER_CPU(int, __in_cortex_a76_erratum_1463225_wa);
114+
115+
static void cortex_a76_erratum_1463225_svc_handler(void)
116+
{
117+
u32 reg, val;
118+
119+
if (!unlikely(test_thread_flag(TIF_SINGLESTEP)))
120+
return;
121+
122+
if (!unlikely(this_cpu_has_cap(ARM64_WORKAROUND_1463225)))
123+
return;
124+
125+
__this_cpu_write(__in_cortex_a76_erratum_1463225_wa, 1);
126+
reg = read_sysreg(mdscr_el1);
127+
val = reg | DBG_MDSCR_SS | DBG_MDSCR_KDE;
128+
write_sysreg(val, mdscr_el1);
129+
asm volatile("msr daifclr, #8");
130+
isb();
131+
132+
/* We will have taken a single-step exception by this point */
133+
134+
write_sysreg(reg, mdscr_el1);
135+
__this_cpu_write(__in_cortex_a76_erratum_1463225_wa, 0);
136+
}
137+
138+
static bool cortex_a76_erratum_1463225_debug_handler(struct pt_regs *regs)
139+
{
140+
if (!__this_cpu_read(__in_cortex_a76_erratum_1463225_wa))
141+
return false;
142+
143+
/*
144+
* We've taken a dummy step exception from the kernel to ensure
145+
* that interrupts are re-enabled on the syscall path. Return back
146+
* to cortex_a76_erratum_1463225_svc_handler() with debug exceptions
147+
* masked so that we can safely restore the mdscr and get on with
148+
* handling the syscall.
149+
*/
150+
regs->pstate |= PSR_D_BIT;
151+
return true;
152+
}
153+
#else /* CONFIG_ARM64_ERRATUM_1463225 */
154+
static void cortex_a76_erratum_1463225_svc_handler(void) { }
155+
static bool cortex_a76_erratum_1463225_debug_handler(struct pt_regs *regs)
156+
{
157+
return false;
158+
}
159+
#endif /* CONFIG_ARM64_ERRATUM_1463225 */
160+
112161
static void noinstr el1_abort(struct pt_regs *regs, unsigned long esr)
113162
{
114163
unsigned long far = read_sysreg(far_el1);
@@ -186,7 +235,8 @@ static void noinstr el1_dbg(struct pt_regs *regs, unsigned long esr)
186235
gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET);
187236

188237
arm64_enter_el1_dbg(regs);
189-
do_debug_exception(far, esr, regs);
238+
if (!cortex_a76_erratum_1463225_debug_handler(regs))
239+
do_debug_exception(far, esr, regs);
190240
arm64_exit_el1_dbg(regs);
191241
}
192242

@@ -362,6 +412,7 @@ static void noinstr el0_svc(struct pt_regs *regs)
362412
gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET);
363413

364414
enter_from_user_mode();
415+
cortex_a76_erratum_1463225_svc_handler();
365416
do_el0_svc(regs);
366417
}
367418

@@ -439,6 +490,7 @@ static void noinstr el0_svc_compat(struct pt_regs *regs)
439490
gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET);
440491

441492
enter_from_user_mode();
493+
cortex_a76_erratum_1463225_svc_handler();
442494
do_el0_svc_compat(regs);
443495
}
444496

arch/arm64/kernel/syscall.c

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -65,35 +65,6 @@ static inline bool has_syscall_work(unsigned long flags)
6565
int syscall_trace_enter(struct pt_regs *regs);
6666
void syscall_trace_exit(struct pt_regs *regs);
6767

68-
#ifdef CONFIG_ARM64_ERRATUM_1463225
69-
DECLARE_PER_CPU(int, __in_cortex_a76_erratum_1463225_wa);
70-
71-
static void cortex_a76_erratum_1463225_svc_handler(void)
72-
{
73-
u32 reg, val;
74-
75-
if (!unlikely(test_thread_flag(TIF_SINGLESTEP)))
76-
return;
77-
78-
if (!unlikely(this_cpu_has_cap(ARM64_WORKAROUND_1463225)))
79-
return;
80-
81-
__this_cpu_write(__in_cortex_a76_erratum_1463225_wa, 1);
82-
reg = read_sysreg(mdscr_el1);
83-
val = reg | DBG_MDSCR_SS | DBG_MDSCR_KDE;
84-
write_sysreg(val, mdscr_el1);
85-
asm volatile("msr daifclr, #8");
86-
isb();
87-
88-
/* We will have taken a single-step exception by this point */
89-
90-
write_sysreg(reg, mdscr_el1);
91-
__this_cpu_write(__in_cortex_a76_erratum_1463225_wa, 0);
92-
}
93-
#else
94-
static void cortex_a76_erratum_1463225_svc_handler(void) { }
95-
#endif /* CONFIG_ARM64_ERRATUM_1463225 */
96-
9768
static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
9869
const syscall_fn_t syscall_table[])
9970
{
@@ -120,7 +91,6 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
12091
* (Similarly for HVC and SMC elsewhere.)
12192
*/
12293

123-
cortex_a76_erratum_1463225_svc_handler();
12494
local_daif_restore(DAIF_PROCCTX);
12595

12696
if (flags & _TIF_MTE_ASYNC_FAULT) {

arch/arm64/mm/fault.c

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -874,44 +874,12 @@ static void debug_exception_exit(struct pt_regs *regs)
874874
}
875875
NOKPROBE_SYMBOL(debug_exception_exit);
876876

877-
#ifdef CONFIG_ARM64_ERRATUM_1463225
878-
DECLARE_PER_CPU(int, __in_cortex_a76_erratum_1463225_wa);
879-
880-
static int cortex_a76_erratum_1463225_debug_handler(struct pt_regs *regs)
881-
{
882-
if (user_mode(regs))
883-
return 0;
884-
885-
if (!__this_cpu_read(__in_cortex_a76_erratum_1463225_wa))
886-
return 0;
887-
888-
/*
889-
* We've taken a dummy step exception from the kernel to ensure
890-
* that interrupts are re-enabled on the syscall path. Return back
891-
* to cortex_a76_erratum_1463225_svc_handler() with debug exceptions
892-
* masked so that we can safely restore the mdscr and get on with
893-
* handling the syscall.
894-
*/
895-
regs->pstate |= PSR_D_BIT;
896-
return 1;
897-
}
898-
#else
899-
static int cortex_a76_erratum_1463225_debug_handler(struct pt_regs *regs)
900-
{
901-
return 0;
902-
}
903-
#endif /* CONFIG_ARM64_ERRATUM_1463225 */
904-
NOKPROBE_SYMBOL(cortex_a76_erratum_1463225_debug_handler);
905-
906877
void do_debug_exception(unsigned long addr_if_watchpoint, unsigned int esr,
907878
struct pt_regs *regs)
908879
{
909880
const struct fault_info *inf = esr_to_debug_fault_info(esr);
910881
unsigned long pc = instruction_pointer(regs);
911882

912-
if (cortex_a76_erratum_1463225_debug_handler(regs))
913-
return;
914-
915883
debug_exception_enter(regs);
916884

917885
if (user_mode(regs) && !is_ttbr0_addr(pc))

0 commit comments

Comments
 (0)