Skip to content

Commit 65c021b

Browse files
Lorenzo Pieralisictmarinas
authored andcommitted
arm64: kernel: restore HW breakpoint registers in cpu_suspend
When a CPU resumes from low-power, it restores HW breakpoint and watchpoint slots through a CPU PM notifier. Since we want to enable debugging as early as possible in the resume path, the mdscr content is restored along the general purpose registers in the cpu_suspend API and debug exceptions are reenabled when cpu_suspend returns. Since the CPU PM notifier is run after a CPU has been resumed, we cannot expect HW breakpoint registers to contain sane values till the notifier is run, since the HW breakpoints registers content is unknown at reset; this means that the CPU might run with debug exceptions enabled, mdscr restored but HW breakpoint registers containing junk values that can trigger spurious debug exceptions. This patch fixes current HW breakpoints restore by moving the HW breakpoints registers restoration to the cpu_suspend API, before the debug exceptions are enabled. This way, as soon as the cpu_suspend function returns the kernel can resume debugging with sane values in HW breakpoint registers. Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Acked-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
1 parent f4be843 commit 65c021b

File tree

2 files changed

+28
-23
lines changed

2 files changed

+28
-23
lines changed

arch/arm64/kernel/hw_breakpoint.c

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -894,29 +894,10 @@ static struct notifier_block hw_breakpoint_reset_nb = {
894894
.notifier_call = hw_breakpoint_reset_notify,
895895
};
896896

897-
#ifdef CONFIG_CPU_PM
898-
static int hw_breakpoint_cpu_pm_notify(struct notifier_block *self,
899-
unsigned long action,
900-
void *v)
901-
{
902-
if (action == CPU_PM_EXIT) {
903-
hw_breakpoint_reset(NULL);
904-
return NOTIFY_OK;
905-
}
906-
907-
return NOTIFY_DONE;
908-
}
909-
910-
static struct notifier_block hw_breakpoint_cpu_pm_nb = {
911-
.notifier_call = hw_breakpoint_cpu_pm_notify,
912-
};
913-
914-
static void __init hw_breakpoint_pm_init(void)
915-
{
916-
cpu_pm_register_notifier(&hw_breakpoint_cpu_pm_nb);
917-
}
897+
#ifdef CONFIG_ARM64_CPU_SUSPEND
898+
extern void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *));
918899
#else
919-
static inline void hw_breakpoint_pm_init(void)
900+
static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
920901
{
921902
}
922903
#endif
@@ -947,7 +928,8 @@ static int __init arch_hw_breakpoint_init(void)
947928

948929
/* Register hotplug notifier. */
949930
register_cpu_notifier(&hw_breakpoint_reset_nb);
950-
hw_breakpoint_pm_init();
931+
/* Register cpu_suspend hw breakpoint restore hook */
932+
cpu_suspend_set_dbg_restorer(hw_breakpoint_reset);
951933

952934
return 0;
953935
}

arch/arm64/kernel/suspend.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ int __cpu_suspend_finisher(unsigned long arg, struct cpu_suspend_ctx *ptr,
3838
return cpu_ops[cpu]->cpu_suspend(arg);
3939
}
4040

41+
/*
42+
* This hook is provided so that cpu_suspend code can restore HW
43+
* breakpoints as early as possible in the resume path, before reenabling
44+
* debug exceptions. Code cannot be run from a CPU PM notifier since by the
45+
* time the notifier runs debug exceptions might have been enabled already,
46+
* with HW breakpoints registers content still in an unknown state.
47+
*/
48+
void (*hw_breakpoint_restore)(void *);
49+
void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
50+
{
51+
/* Prevent multiple restore hook initializations */
52+
if (WARN_ON(hw_breakpoint_restore))
53+
return;
54+
hw_breakpoint_restore = hw_bp_restore;
55+
}
56+
4157
/**
4258
* cpu_suspend
4359
*
@@ -73,6 +89,13 @@ int cpu_suspend(unsigned long arg)
7389
if (ret == 0) {
7490
cpu_switch_mm(mm->pgd, mm);
7591
flush_tlb_all();
92+
/*
93+
* Restore HW breakpoint registers to sane values
94+
* before debug exceptions are possibly reenabled
95+
* through local_dbg_restore.
96+
*/
97+
if (hw_breakpoint_restore)
98+
hw_breakpoint_restore(NULL);
7699
}
77100

78101
/*

0 commit comments

Comments
 (0)