Release 4.14 arch/powerpc/xmon/xmon.c
/*
* Routines providing a simple monitor for use on the PowerMac.
*
* Copyright (C) 1996-2005 Paul Mackerras.
* Copyright (C) 2001 PPC64 Team, IBM Corp
* Copyrignt (C) 2006 Michael Ellerman, IBM Corp
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/sched/signal.h>
#include <linux/smp.h>
#include <linux/mm.h>
#include <linux/reboot.h>
#include <linux/delay.h>
#include <linux/kallsyms.h>
#include <linux/kmsg_dump.h>
#include <linux/cpumask.h>
#include <linux/export.h>
#include <linux/sysrq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/bug.h>
#include <linux/nmi.h>
#include <linux/ctype.h>
#include <asm/debugfs.h>
#include <asm/ptrace.h>
#include <asm/smp.h>
#include <asm/string.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/xmon.h>
#include <asm/processor.h>
#include <asm/pgtable.h>
#include <asm/mmu.h>
#include <asm/mmu_context.h>
#include <asm/cputable.h>
#include <asm/rtas.h>
#include <asm/sstep.h>
#include <asm/irq_regs.h>
#include <asm/spu.h>
#include <asm/spu_priv1.h>
#include <asm/setjmp.h>
#include <asm/reg.h>
#include <asm/debug.h>
#include <asm/hw_breakpoint.h>
#include <asm/xive.h>
#include <asm/opal.h>
#include <asm/firmware.h>
#include <asm/code-patching.h>
#ifdef CONFIG_PPC64
#include <asm/hvcall.h>
#include <asm/paca.h>
#endif
#if defined(CONFIG_PPC_SPLPAR)
#include <asm/plpar_wrappers.h>
#else
static inline long plapr_set_ciabr(unsigned long ciabr) {return 0; }Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anshuman Khandual | 14 | 100.00% | 1 | 100.00% |
Total | 14 | 100.00% | 1 | 100.00% |
;
#endif
#include "nonstdio.h"
#include "dis-asm.h"
#ifdef CONFIG_SMP
static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
static unsigned long xmon_taken = 1;
static int xmon_owner;
static int xmon_gate;
#else
#define xmon_owner 0
#endif /* CONFIG_SMP */
static unsigned long in_xmon __read_mostly = 0;
static int xmon_on = IS_ENABLED(CONFIG_XMON_DEFAULT);
static unsigned long adrs;
static int size = 1;
#define MAX_DUMP (128 * 1024)
static unsigned long ndump = 64;
static unsigned long nidump = 16;
static unsigned long ncsum = 4096;
static int termch;
static char tmpstr[128];
static int tracing_enabled;
static long bus_error_jmp[JMP_BUF_LEN];
static int catch_memory_errors;
static int catch_spr_faults;
static long *xmon_fault_jmp[NR_CPUS];
/* Breakpoint stuff */
struct bpt {
unsigned long address;
unsigned int instr[2];
atomic_t ref_count;
int enabled;
unsigned long pad;
};
/* Bits in bpt.enabled */
#define BP_CIABR 1
#define BP_TRAP 2
#define BP_DABR 4
#define NBPTS 256
static struct bpt bpts[NBPTS];
static struct bpt dabr;
static struct bpt *iabr;
static unsigned bpinstr = 0x7fe00008;
/* trap */
#define BP_NUM(bp) ((bp) - bpts + 1)
/* Prototypes */
static int cmds(struct pt_regs *);
static int mread(unsigned long, void *, int);
static int mwrite(unsigned long, void *, int);
static int handle_fault(struct pt_regs *);
static void byterev(unsigned char *, int);
static void memex(void);
static int bsesc(void);
static void dump(void);
static void prdump(unsigned long, long);
static int ppc_inst_dump(unsigned long, long, int);
static void dump_log_buf(void);
#ifdef CONFIG_PPC_POWERNV
static void dump_opal_msglog(void);
#else
static inline void dump_opal_msglog(void)
{
printf("Machine is not running OPAL firmware.\n");
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Donnellan | 14 | 100.00% | 1 | 100.00% |
Total | 14 | 100.00% | 1 | 100.00% |
#endif
static void backtrace(struct pt_regs *);
static void excprint(struct pt_regs *);
static void prregs(struct pt_regs *);
static void memops(int);
static void memlocate(void);
static void memzcan(void);
static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
int skipbl(void);
int scanhex(unsigned long *valp);
static void scannl(void);
static int hexdigit(int);
void getstring(char *, int);
static void flush_input(void);
static int inchar(void);
static void take_input(char *);
static int read_spr(int, unsigned long *);
static void write_spr(int, unsigned long);
static void super_regs(void);
static void remove_bpts(void);
static void insert_bpts(void);
static void remove_cpu_bpts(void);
static void insert_cpu_bpts(void);
static struct bpt *at_breakpoint(unsigned long pc);
static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
static int do_step(struct pt_regs *);
static void bpt_cmds(void);
static void cacheflush(void);
static int cpu_cmd(void);
static void csum(void);
static void bootcmds(void);
static void proccall(void);
static void show_tasks(void);
void dump_segments(void);
static void symbol_lookup(void);
static void xmon_show_stack(unsigned long sp, unsigned long lr,
unsigned long pc);
static void xmon_print_symbol(unsigned long address, const char *mid,
const char *after);
static const char *getvecname(unsigned long vec);
static int do_spu_cmd(void);
#ifdef CONFIG_44x
static void dump_tlb_44x(void);
#endif
#ifdef CONFIG_PPC_BOOK3E
static void dump_tlb_book3e(void);
#endif
#ifdef CONFIG_PPC64
#define REG "%.16lx"
#else
#define REG "%.8lx"
#endif
#ifdef __LITTLE_ENDIAN__
#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
#else
#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
#endif
static char *help_string = "\
Commands:\n\
b show breakpoints\n\
bd set data breakpoint\n\
bi set instruction breakpoint\n\
bc clear breakpoint\n"
#ifdef CONFIG_SMP
"\
c print cpus stopped in xmon\n\
c# try to switch to cpu number h (in hex)\n"
#endif
"\
C checksum\n\
d dump bytes\n\
d1 dump 1 byte values\n\
d2 dump 2 byte values\n\
d4 dump 4 byte values\n\
d8 dump 8 byte values\n\
di dump instructions\n\
df dump float values\n\
dd dump double values\n\
dl dump the kernel log buffer\n"
#ifdef CONFIG_PPC_POWERNV
"\
do dump the OPAL message log\n"
#endif
#ifdef CONFIG_PPC64
"\
dp[#] dump paca for current cpu, or cpu #\n\
dpa dump paca for all possible cpus\n"
#endif
"\
dr dump stream of raw bytes\n\
dt dump the tracing buffers (uses printk)\n\
dtc dump the tracing buffers for current CPU (uses printk)\n\
"
#ifdef CONFIG_PPC_POWERNV
" dx# dump xive on CPU #\n\
dxi# dump xive irq state #\n\
dxa dump xive on all CPUs\n"
#endif
" e print exception information\n\
f flush cache\n\
la lookup symbol+offset of specified address\n\
ls lookup address of specified symbol\n\
m examine/change memory\n\
mm move a block of memory\n\
ms set a block of memory\n\
md compare two blocks of memory\n\
ml locate a block of memory\n\
mz zero a block of memory\n\
mi show information about memory allocation\n\
p call a procedure\n\
P list processes/tasks\n\
r print registers\n\
s single step\n"
#ifdef CONFIG_SPU_BASE
" ss stop execution on all spus\n\
sr restore execution on stopped spus\n\
sf # dump spu fields for spu # (in hex)\n\
sd # dump spu local store for spu # (in hex)\n\
sdi # disassemble spu local store for spu # (in hex)\n"
#endif
" S print special registers\n\
Sa print all SPRs\n\
Sr # read SPR #\n\
Sw #v write v to SPR #\n\
t print backtrace\n\
x exit monitor and recover\n\
X exit monitor and don't recover\n"
#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
" u dump segment table or SLB\n"
#elif defined(CONFIG_PPC_STD_MMU_32)
" u dump segment registers\n"
#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
" u dump TLB\n"
#endif
" ? help\n"
" # n limit output to n lines per page (for dp, dpa, dl)\n"
" zr reboot\n\
zh halt\n"
;
static struct pt_regs *xmon_regs;
static inline void sync(void)
{
asm volatile("sync; isync");
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anton Blanchard | 11 | 91.67% | 1 | 50.00% |
Paul Mackerras | 1 | 8.33% | 1 | 50.00% |
Total | 12 | 100.00% | 2 | 100.00% |
static inline void store_inst(void *p)
{
asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Mackerras | 14 | 100.00% | 1 | 100.00% |
Total | 14 | 100.00% | 1 | 100.00% |
static inline void cflush(void *p)
{
asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Mackerras | 14 | 100.00% | 1 | 100.00% |
Total | 14 | 100.00% | 1 | 100.00% |
static inline void cinval(void *p)
{
asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Mackerras | 14 | 100.00% | 1 | 100.00% |
Total | 14 | 100.00% | 1 | 100.00% |
/**
* write_ciabr() - write the CIABR SPR
* @ciabr: The value to write.
*
* This function writes a value to the CIARB register either directly
* through mtspr instruction if the kernel is in HV privilege mode or
* call a hypervisor function to achieve the same in case the kernel
* is in supervisor privilege mode.
*/
static void write_ciabr(unsigned long ciabr)
{
if (!cpu_has_feature(CPU_FTR_ARCH_207S))
return;
if (cpu_has_feature(CPU_FTR_HVMODE)) {
mtspr(SPRN_CIABR, ciabr);
return;
}
plapr_set_ciabr(ciabr);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anshuman Khandual | 41 | 100.00% | 1 | 100.00% |
Total | 41 | 100.00% | 1 | 100.00% |
/**
* set_ciabr() - set the CIABR
* @addr: The value to set.
*
* This function sets the correct privilege value into the the HW
* breakpoint address before writing it up in the CIABR register.
*/
static void set_ciabr(unsigned long addr)
{
addr &= ~CIABR_PRIV;
if (cpu_has_feature(CPU_FTR_HVMODE))
addr |= CIABR_PRIV_HYPER;
else
addr |= CIABR_PRIV_SUPER;
write_ciabr(addr);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anshuman Khandual | 36 | 100.00% | 1 | 100.00% |
Total | 36 | 100.00% | 1 | 100.00% |
/*
* Disable surveillance (the service processor watchdog function)
* while we are in xmon.
* XXX we should re-enable it when we leave. :)
*/
#define SURVEILLANCE_TOKEN 9000
static inline void disable_surveillance(void)
{
#ifdef CONFIG_PPC_PSERIES
/* Since this can't be a module, args should end up below 4GB. */
static struct rtas_args args;
int token;
/*
* At this point we have got all the cpus we can into
* xmon, so there is hopefully no other cpu calling RTAS
* at the moment, even though we don't take rtas.lock.
* If we did try to take rtas.lock there would be a
* real possibility of deadlock.
*/
token = rtas_token("set-indicator");
if (token == RTAS_UNKNOWN_SERVICE)
return;
rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0);
#endif /* CONFIG_PPC_PSERIES */
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Anton Blanchard | 22 | 37.29% | 2 | 28.57% |
Andrew Morton | 16 | 27.12% | 2 | 28.57% |
Michael Ellerman | 13 | 22.03% | 1 | 14.29% |
Benjamin Herrenschmidt | 5 | 8.47% | 1 | 14.29% |
Laurent Dufour | 3 | 5.08% | 1 | 14.29% |
Total | 59 | 100.00% | 7 | 100.00% |
#ifdef CONFIG_SMP
static int xmon_speaker;
static void get_output_lock(void)
{
int me = smp_processor_id() + 0x100;
int last_speaker = 0, prev;
long timeout;
if (xmon_speaker == me)
return;
for (;;) {
last_speaker = cmpxchg(&xmon_speaker, 0, me);
if (last_speaker == 0)
return;
/*
* Wait a full second for the lock, we might be on a slow
* console, but check every 100us.
*/
timeout = 10000;
while (xmon_speaker == last_speaker) {
if (--timeout > 0) {
udelay(100);
continue;
}
/* hostile takeover */
prev = cmpxchg(&xmon_speaker, last_speaker, me);
if (prev == last_speaker)
return;
break;
}
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 80 | 74.07% | 2 | 50.00% |
Anton Blanchard | 19 | 17.59% | 1 | 25.00% |
Michael Ellerman | 9 | 8.33% | 1 | 25.00% |
Total | 108 | 100.00% | 4 | 100.00% |
static void release_output_lock(void)
{
xmon_speaker = 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 8 | 66.67% | 1 | 50.00% |
Anton Blanchard | 4 | 33.33% | 1 | 50.00% |
Total | 12 | 100.00% | 2 | 100.00% |
int cpus_are_in_xmon(void)
{
return !cpumask_empty(&cpus_in_xmon);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Michael Ellerman | 13 | 86.67% | 1 | 50.00% |
Motohiro Kosaki | 2 | 13.33% | 1 | 50.00% |
Total | 15 | 100.00% | 2 | 100.00% |
static bool wait_for_other_cpus(int ncpus)
{
unsigned long timeout;
/* We wait for 2s, which is a metric "little while" */
for (timeout = 20000; timeout != 0; --timeout) {
if (cpumask_weight(&cpus_in_xmon) >= ncpus)
return true;
udelay(100);
barrier();
}
return false;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nicholas Piggin | 53 | 100.00% | 1 | 100.00% |
Total | 53 | 100.00% | 1 | 100.00% |
#endif /* CONFIG_SMP */
static inline int unrecoverable_excp(struct pt_regs *regs)
{
#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
/* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
return 0;
#else
return ((regs->msr & MSR_RI) == 0);
#endif
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Josh Boyer | 33 | 75.00% | 1 | 33.33% |
Jimi Xenidis | 11 | 25.00% | 2 | 66.67% |
Total | 44 | 100.00% | 3 | 100.00% |
static int xmon_core(struct pt_regs *regs, int fromipi)
{
int cmd = 0;
struct bpt *bp;
long recurse_jmp[JMP_BUF_LEN];
unsigned long offset;
unsigned long flags;
#ifdef CONFIG_SMP
int cpu;
int secondary;
#endif
local_irq_save(flags);
hard_irq_disable();
tracing_enabled = tracing_is_on();
tracing_off();
bp = in_breakpoint_table(regs->nip, &offset);
if (bp != NULL) {
regs->nip = bp->address + offset;
atomic_dec(&bp->ref_count);
}
remove_cpu_bpts();
#ifdef CONFIG_SMP
cpu = smp_processor_id();
if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
/*
* We catch SPR read/write faults here because the 0x700, 0xf60
* etc. handlers don't call debugger_fault_handler().
*/
if (catch_spr_faults)
longjmp(bus_error_jmp, 1);
get_output_lock();
excprint(regs);
printf("cpu 0x%x: Exception %lx %s in xmon, "
"returning to main loop\n",
cpu, regs->trap, getvecname(TRAP(regs)));
release_output_lock();
longjmp(xmon_fault_jmp[cpu], 1);
}
if (setjmp(recurse_jmp) != 0) {
if (!in_xmon || !xmon_gate) {
get_output_lock();
printf("xmon: WARNING: bad recursive fault "
"on cpu 0x%x\n", cpu);
release_output_lock();
goto waiting;
}
secondary = !(xmon_taken && cpu == xmon_owner);
goto cmdloop;
}
xmon_fault_jmp[cpu] = recurse_jmp;
bp = NULL;
if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
bp = at_breakpoint(regs->nip);
if (bp || unrecoverable_excp(regs))
fromipi = 0;
if (!fromipi) {
get_output_lock();
excprint(regs);
if (bp) {
printf("cpu 0x%x stopped at breakpoint 0x%lx (",
cpu, BP_NUM(bp));
xmon_print_symbol(regs->nip, " ", ")\n");
}
if (unrecoverable_excp(regs))
printf("WARNING: exception is not recoverable, "
"can't continue\n");
release_output_lock();
}
cpumask_set_cpu(cpu, &cpus_in_xmon);
waiting:
secondary = 1;
while (secondary && !xmon_gate) {
if (in_xmon == 0) {
if (fromipi)
goto leave;
secondary = test_and_set_bit(0, &in_xmon);
}
barrier();
}
if (!secondary && !xmon_gate) {
/* we are the first cpu to come in */
/* interrupt other cpu(s) */
int ncpus = num_online_cpus();
xmon_owner = cpu;
mb();
if (ncpus > 1) {
/*
* A system reset (trap == 0x100) can be triggered on
* all CPUs, so when we come in via 0x100 try waiting
* for the other CPUs to come in before we send the
* debugger break (IPI). This is similar to
* crash_kexec_secondary().
*/
if (TRAP(regs) != 0x100 || !wait_for_other_cpus(ncpus))
smp_send_debugger_break();
wait_for_other_cpus(ncpus);
}
remove_bpts();
disable_surveillance();
/* for breakpoint or single step, print the current instr. */
if (bp || TRAP(regs) == 0xd00)
ppc_inst_dump(regs->nip, 1, 0);
printf("enter ? for help\n");
mb();
xmon_gate = 1;
barrier();
}
cmdloop:
while (in_xmon) {
if (secondary) {
if (cpu == xmon_owner) {
if (!test_and_set_bit(0, &xmon_taken)) {
secondary = 0;
continue;
}
/* missed it */
while (cpu == xmon_owner)
barrier();
}
barrier();
} else {
cmd = cmds(regs);
if (cmd != 0) {
/* exiting xmon */
insert_bpts();
xmon_gate = 0;
wmb();
in_xmon = 0;
break;
}
/* have switched to some other cpu */
secondary = 1;
}
}
leave:
cpumask_clear_cpu(cpu, &cpus_in_xmon);
xmon_fault_jmp[cpu] = NULL;
#else
/* UP is simple... */
if (in_xmon) {
printf("Exception %lx %s in xmon, returning to main loop\n",
regs->trap, getvecname(TRAP(regs)));
longjmp(xmon_fault_jmp[0], 1);
}
if (setjmp(recurse_jmp) == 0) {
xmon_fault_jmp[0] = recurse_jmp;
in_xmon = 1;
excprint(regs);
bp = at_breakpoint(regs->nip);
if (bp) {
printf("Stopped at breakpoint %lx (", BP_NUM(bp));
xmon_print_symbol(regs->nip, " ", ")\n");
}
if (unrecoverable_excp(regs))
printf("WARNING: exception is not recoverable, "
"can't continue\n");
remove_bpts();
disable_surveillance();
/* for breakpoint or single step, print the current instr. */
if (bp || TRAP(regs) == 0xd00)
ppc_inst_dump(regs->nip, 1, 0);
printf("enter ? for help\n");
}
cmd = cmds(regs);
insert_bpts();
in_xmon = 0;
#endif
#ifdef CONFIG_BOOKE
if (regs->msr & MSR_DE) {
bp = at_breakpoint(regs->nip);
if (bp != NULL) {
regs->nip = (unsigned long) &bp->instr[0];
atomic_inc(&bp->ref_count);
}
}
#else
if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
bp = at_breakpoint(regs->nip);
if (bp != NULL) {
int stepped = emulate_step(regs, bp->instr[0]);
if (stepped == 0) {
regs->nip = (unsigned long) &bp->instr[0];
atomic_inc(&bp->ref_count);
} else if (stepped < 0) {
printf("Couldn't single-step %s instruction\n",
(IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
}
}
}
#endif
insert_cpu_bpts();
touch_nmi_watchdog();
local_irq_restore(flags);
return cmd != 'X' && cmd != EOF;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 583 | 60.41% | 5 | 20.83% |
Anton Blanchard | 215 | 22.28% | 5 | 20.83% |
Josh Boyer | 67 | 6.94% | 2 | 8.33% |
Paul Mackerras | 48 | 4.97% | 4 | 16.67% |
Nicholas Piggin | 16 | 1.66% | 1 | 4.17% |
Michael Ellerman | 14 | 1.45% | 3 | 12.50% |
Haren Myneni | 9 | 0.93% | 1 | 4.17% |
Breno Leitão | 8 | 0.83% | 1 | 4.17% |
Motohiro Kosaki | 4 | 0.41% | 1 | 4.17% |
Arnd Bergmann | 1 | 0.10% | 1 | 4.17% |
Total | 965 | 100.00% | 24 | 100.00% |
int xmon(struct pt_regs *excp)
{
struct pt_regs regs;
if (excp == NULL) {
ppc_save_regs(®s);
excp = ®s;
}
return xmon_core(excp, 0);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 33 | 80.49% | 1 | 25.00% |
Anton Blanchard | 4 | 9.76% | 1 | 25.00% |
Paul Mackerras | 3 | 7.32% | 1 | 25.00% |
Anton Vorontsov | 1 | 2.44% | 1 | 25.00% |
Total | 41 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL(xmon);
irqreturn_t xmon_irq(int irq, void *d)
{
unsigned long flags;
local_irq_save(flags);
printf("Keyboard interrupt\n");
xmon(get_irq_regs());
local_irq_restore(flags);
return IRQ_HANDLED;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Paul Mackerras | 40 | 100.00% | 2 | 100.00% |
Total | 40 | 100.00% | 2 | 100.00% |
static int xmon_bpt(struct pt_regs *regs)
{
struct bpt *bp;
unsigned long offset;
if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
return 0;
/* Are we at the trap at bp->instr[1] for some bp? */
bp = in_breakpoint_table(regs->nip, &offset);
if (bp != NULL && offset == 4) {
regs->nip = bp->address + 4;
atomic_dec(&bp->ref_count);
return 1;
}
/* Are we at a breakpoint? */
bp = at_breakpoint(regs->nip);
if (!bp)
return 0;
xmon_core(regs, 0);
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 83 | 69.75% | 1 | 16.67% |
Anton Blanchard | 33 | 27.73% | 3 | 50.00% |
Michael Ellerman | 2 | 1.68% | 1 | 16.67% |
Arnd Bergmann | 1 | 0.84% | 1 | 16.67% |
Total | 119 | 100.00% | 6 | 100.00% |
static int xmon_sstep(struct pt_regs *regs)
{
if (user_mode(regs))
return 0;
xmon_core(regs, 0);
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 30 | 96.77% | 1 | 50.00% |
Arnd Bergmann | 1 | 3.23% | 1 | 50.00% |
Total | 31 | 100.00% | 2 | 100.00% |
static int xmon_break_match(struct pt_regs *regs)
{
if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
return 0;
if (dabr.enabled == 0)
return 0;
xmon_core(regs, 0);
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 42 | 73.68% | 1 | 20.00% |
Anton Blanchard | 11 | 19.30% | 1 | 20.00% |
Michael Ellerman | 2 | 3.51% | 1 | 20.00% |
Arnd Bergmann | 1 | 1.75% | 1 | 20.00% |
Michael Neuling | 1 | 1.75% | 1 | 20.00% |
Total | 57 | 100.00% | 5 | 100.00% |
static int xmon_iabr_match(struct pt_regs *regs)
{
if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
return 0;
if (iabr == NULL)
return 0;
xmon_core(regs, 0);
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 51 | 92.73% | 1 | 25.00% |
Michael Ellerman | 3 | 5.45% | 2 | 50.00% |
Arnd Bergmann | 1 | 1.82% | 1 | 25.00% |
Total | 55 | 100.00% | 4 | 100.00% |
static int xmon_ipi(struct pt_regs *regs)
{
#ifdef CONFIG_SMP
if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
xmon_core(regs, 1);
#endif
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 37 | 92.50% | 1 | 33.33% |
Motohiro Kosaki | 2 | 5.00% | 1 | 33.33% |
Arnd Bergmann | 1 | 2.50% | 1 | 33.33% |
Total | 40 | 100.00% | 3 | 100.00% |
static int xmon_fault_handler(struct pt_regs *regs)
{
struct bpt *bp;
unsigned long offset;
if (in_xmon && catch_memory_errors)
handle_fault(regs); /* doesn't return */
if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
bp = in_breakpoint_table(regs->nip, &offset);
if (bp != NULL) {
regs->nip = bp->address + offset;
atomic_dec(&bp->ref_count);
}
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andrew Morton | 94 | 96.91% | 1 | 33.33% |
Michael Ellerman | 2 | 2.06% | 1 | 33.33% |
Arnd Bergmann | 1 | 1.03% | 1 | 33.33% |
Total | 97 | 100.00% | 3 | 100.00% |
static struct bpt *at_breakpoint(unsigned long pc)
{
int i;
struct bpt *bp;
bp = bpts;
for (i = 0