aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeoff Levand <geoff@infradead.org>2020-03-27 15:45:27 -0700
committerGeoff Levand <geoff@infradead.org>2023-06-26 08:14:28 -0500
commit554322b00dec4989e624a7c1e49c2f7f05ceb346 (patch)
tree7d44765338d6fc6726e6e485e6e73828f4bfebca
parent181dc45fb75daffa0a57469bba5f5420edc555e3 (diff)
downloadps3-linux-554322b00dec4989e624a7c1e49c2f7f05ceb346.tar.gz
ps3-debugging: Setup DABR register
For debugging only. Helper routine to setup DABR (Data Address Breakpoint) register for kernel use.
-rw-r--r--arch/powerpc/include/asm/ps3.h9
-rw-r--r--arch/powerpc/kernel/process.c12
-rw-r--r--arch/powerpc/mm/fault.c4
-rw-r--r--arch/powerpc/platforms/ps3/setup.c32
4 files changed, 55 insertions, 2 deletions
diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h
index a5f36546a05240..733b9a24a04041 100644
--- a/arch/powerpc/include/asm/ps3.h
+++ b/arch/powerpc/include/asm/ps3.h
@@ -514,4 +514,13 @@ u64 ps3_get_spe_id(void *arg);
void ps3_early_mm_init(void);
+/* kernel debug routines */
+
+#define DABR_TRANSLATION (1UL << 2)
+#define DABR_DATA_WRITE (1UL << 1)
+#define DABR_DATA_READ (1UL << 0)
+
+int ps3_debug_setup_dabr(u64 address, unsigned int dabr_flags,
+ unsigned int dabrx);
+
#endif
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 1fefafb2b29be5..f0b4675f575fe9 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -610,6 +610,9 @@ EXPORT_SYMBOL(flush_all_to_thread);
void do_send_trap(struct pt_regs *regs, unsigned long address,
unsigned long error_code, int breakpt)
{
+ printk("%s:%d: address %016lxh, code %08lxh\n",
+ __func__, __LINE__, address, error_code);
+
current->thread.trap_nr = TRAP_HWBKPT;
if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
11, SIGSEGV) == NOTIFY_STOP)
@@ -618,6 +621,15 @@ void do_send_trap(struct pt_regs *regs, unsigned long address,
/* Deliver the signal to userspace */
force_sig_ptrace_errno_trap(breakpt, /* breakpoint or watchpoint id */
(void __user *)address);
+ /* Clear the breakpoint */
+ hw_breakpoint_disable();
+
+ if (!user_mode(regs)) {
+ show_regs(regs);
+ printk("%s:%d: done: address %016lxh\n", __func__, __LINE__,
+ address);
+ return;
+ }
}
#else /* !CONFIG_PPC_ADV_DEBUG_REGS */
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 531177a4ee0881..ad91fb0d0c7531 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -438,10 +438,10 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,
* take a page fault to a kernel address or a page fault to a user
* address outside of dedicated places
*/
- if (unlikely(!is_user && bad_kernel_fault(regs, error_code, address, is_write))) {
+ if (unlikely(!is_user && bad_kernel_fault(regs, error_code, address, is_write)
+ && !(error_code & DSISR_DABRMATCH))) {
if (kfence_handle_page_fault(address, is_write, regs))
return 0;
-
return SIGSEGV;
}
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index 5144f11359f798..dccc4f56c7a2ee 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -183,6 +183,38 @@ static int ps3_set_dabr(unsigned long dabr, unsigned long dabrx)
return lv1_set_dabr(dabr, dabrx) ? -1 : 0;
}
+/**
+ * ps3_debug_setup_dabr - Setup the DABR for kernel use.
+ * @dabr_flags: DABR_DATA_WRITE, DABR_DATA_READ, DABR_TRANSLATION
+ * @dabrx: DABRX_BTI, DABRX_KERNEL, DABRX_USER
+ */
+
+int ps3_debug_setup_dabr(u64 address, unsigned int dabr_flags,
+ unsigned int dabrx)
+{
+ int result;
+ u64 reg;
+
+ BUG_ON(dabr_flags
+ & ~(DABR_DATA_WRITE | DABR_DATA_READ | DABR_TRANSLATION));
+
+ /* PS3 seems to need DABR_TRANSLATION set to work */
+
+ reg = (address & -8L) | dabr_flags | DABR_TRANSLATION;
+
+ printk("%s: address %016llxh, flags %xh = %016llxh\n", __func__,
+ address, dabr_flags, reg);
+
+ result = ps3_set_dabr(reg, dabrx);
+
+ if (result)
+ printk("%s: failed: %d %s\n", __func__, result,
+ ps3_result(result));
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(ps3_debug_setup_dabr);
+
static ssize_t ps3_fw_version_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{