diff options
author | Geoff Levand <geoff@infradead.org> | 2020-03-27 15:45:27 -0700 |
---|---|---|
committer | Geoff Levand <geoff@infradead.org> | 2023-06-26 08:14:28 -0500 |
commit | 554322b00dec4989e624a7c1e49c2f7f05ceb346 (patch) | |
tree | 7d44765338d6fc6726e6e485e6e73828f4bfebca | |
parent | 181dc45fb75daffa0a57469bba5f5420edc555e3 (diff) | |
download | ps3-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.h | 9 | ||||
-rw-r--r-- | arch/powerpc/kernel/process.c | 12 | ||||
-rw-r--r-- | arch/powerpc/mm/fault.c | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/setup.c | 32 |
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) { |