* [PATCH] powerpc: Check DAWR before setting watchpoint
@ 2017-11-17 11:52 pedromfc
0 siblings, 0 replies; only message in thread
From: pedromfc @ 2017-11-17 11:52 UTC (permalink / raw)
To: linuxppc-dev; +Cc: mikey, ananth
Parse the PVR to check if DAWR was disabled by firmware
for POWER9 DD2.0 and if so return in error from ptrace.
Based on initial code provided by Michael Neuling <mikey@neuling.org>.
Suggested-by: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Signed-off-by: Pedro Franco de Carvalho <pedromfc@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/debug.h | 1 +
arch/powerpc/kernel/hw_breakpoint.c | 2 ++
arch/powerpc/kernel/process.c | 24 ++++++++++++++++++++++++
arch/powerpc/kernel/ptrace.c | 18 ++++++++++++++++--
4 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/include/asm/debug.h b/arch/powerpc/include/asm/debug.h
index 14e71ff6579e..9b0381abeb0a 100644
--- a/arch/powerpc/include/asm/debug.h
+++ b/arch/powerpc/include/asm/debug.h
@@ -47,6 +47,7 @@ static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; }
void set_breakpoint(struct arch_hw_breakpoint *brk);
void __set_breakpoint(struct arch_hw_breakpoint *brk);
+bool breakpoint_enabled(void);
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
extern void do_send_trap(struct pt_regs *regs, unsigned long address,
unsigned long error_code, int signal_code, int brkpt);
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index 53b9c1dfd7d9..42a6c692f22a 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -173,6 +173,8 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
*/
length_max = 8; /* DABR */
if (cpu_has_feature(CPU_FTR_DAWR)) {
+ if(!breakpoint_enabled())
+ return -ENODEV;
length_max = 512 ; /* 64 doublewords */
/* DAWR region can't cross 512 boundary */
if ((bp->attr.bp_addr >> 10) !=
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index a0c74bbf3454..73dd45dcc5b1 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -809,6 +809,30 @@ void set_breakpoint(struct arch_hw_breakpoint *brk)
preempt_enable();
}
+/*
+ * Check if DAWR is enabled.
+ *
+ * Firmware for POWER9 DD2.0 has DAWR disabled.
+ * There is no way to determine this pragmatically or from
+ * firmware so unfortunately we need to do this based on the PVR.
+ */
+bool breakpoint_enabled(void)
+{
+ unsigned long pvr;
+ unsigned short maj;
+ unsigned short min;
+
+ pvr = mfspr(SPRN_PVR);
+
+ maj = (pvr >> 8) & 0x0F;
+ min = pvr & 0xFF;
+
+ if ((PVR_VER(pvr) == PVR_POWER9) && (maj == 2) && (min == 0))
+ return false;
+
+ return true;
+}
+
#ifdef CONFIG_PPC64
DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array);
#endif
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index f52ad5bb7109..632fc7b2ca90 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -35,6 +35,7 @@
#include <linux/context_tracking.h>
#include <linux/uaccess.h>
+#include <asm/debug.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/switch_to.h>
@@ -2300,6 +2301,7 @@ static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
struct perf_event_attr attr;
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
#ifndef CONFIG_PPC_ADV_DEBUG_REGS
+ bool clear_bp = false;
struct arch_hw_breakpoint hw_brk;
#endif
@@ -2333,9 +2335,10 @@ static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
hw_brk.address = data & (~HW_BRK_TYPE_DABR);
hw_brk.type = (data & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
hw_brk.len = 8;
+ clear_bp = (!data) || !(hw_brk.type & HW_BRK_TYPE_RDWR);
#ifdef CONFIG_HAVE_HW_BREAKPOINT
bp = thread->ptrace_bps[0];
- if ((!data) || !(hw_brk.type & HW_BRK_TYPE_RDWR)) {
+ if (clear_bp) {
if (bp) {
unregister_hw_breakpoint(bp);
thread->ptrace_bps[0] = NULL;
@@ -2372,7 +2375,15 @@ static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
return PTR_ERR(bp);
}
-#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+#else /* !CONFIG_HAVE_HW_BREAKPOINT */
+ /* Only check if DAWR is enabled if we are actually
+ * setting a watchpoint that can be triggered (i.e. clear_bp is false).
+ * This emulates the behavior when CONFIG_HAVE_HW_BREAKPOINT is set,
+ * which checks DAWR when register_user_hw_breakpoint is called.
+ */
+ if((!clear_bp) && (!breakpoint_enabled()))
+ return -ENODEV;
+#endif /* !CONFIG_HAVE_HW_BREAKPOINT */
task->thread.hw_brk = hw_brk;
#else /* CONFIG_PPC_ADV_DEBUG_REGS */
/* As described above, it was assumed 3 bits were passed with the data
@@ -2826,6 +2837,9 @@ static long ppc_set_hwdebug(struct task_struct *child,
if (child->thread.hw_brk.address)
return -ENOSPC;
+ if (!breakpoint_enabled())
+ return -ENODEV;
+
child->thread.hw_brk = brk;
return 1;
--
2.13.6
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2017-11-17 11:53 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-11-17 11:52 [PATCH] powerpc: Check DAWR before setting watchpoint pedromfc
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).