patch-2.4.0-test9 linux/arch/ppc/xmon/xmon.c
Next file: linux/arch/sh/boot/compressed/Makefile
Previous file: linux/arch/ppc/xmon/start.c
Back to the patch index
Back to the overall index
- Lines: 343
- Date:
Sun Sep 17 09:48:07 2000
- Orig file:
v2.4.0-test8/linux/arch/ppc/xmon/xmon.c
- Orig date:
Thu Jul 13 09:42:51 2000
diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c
@@ -6,15 +6,23 @@
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
+#include <linux/smp.h>
#include <asm/ptrace.h>
#include <asm/string.h>
#include <asm/prom.h>
+#include <asm/bitops.h>
#include "nonstdio.h"
#include "privinst.h"
#define scanhex xmon_scanhex
#define skipbl xmon_skipbl
+#ifdef CONFIG_SMP
+static unsigned long cpus_in_xmon = 0;
+static unsigned long got_xmon = 0;
+static volatile int take_xmon = -1;
+#endif /* CONFIG_SMP */
+
static unsigned adrs;
static int size = 1;
static unsigned ndump = 64;
@@ -84,6 +92,9 @@
static struct bpt *at_breakpoint(unsigned pc);
static void bpt_cmds(void);
static void cacheflush(void);
+#ifdef CONFIG_SMP
+static void cpu_cmd(void);
+#endif /* CONFIG_SMP */
#if 0 /* Makes compile with -Wall */
static char *pretty_print_addr(unsigned long addr);
static char *lookup_name(unsigned long addr);
@@ -96,8 +107,18 @@
extern int setjmp(u_int *);
extern void longjmp(u_int *, int);
+extern void xmon_enter(void);
+extern void xmon_leave(void);
+
#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
+#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
+ || ('a' <= (c) && (c) <= 'f') \
+ || ('A' <= (c) && (c) <= 'F'))
+#define isalnum(c) (('0' <= (c) && (c) <= '9') \
+ || ('a' <= (c) && (c) <= 'z') \
+ || ('A' <= (c) && (c) <= 'Z'))
+
static char *help_string = "\
Commands:\n\
d dump bytes\n\
@@ -117,10 +138,12 @@
x exit monitor\n\
";
-static int xmon_trace;
+static int xmon_trace[NR_CPUS];
#define SSTEP 1 /* stepping because of 's' command */
#define BRSTEP 2 /* stepping over breakpoint */
+static struct pt_regs *xmon_regs[NR_CPUS];
+
void
xmon(struct pt_regs *excp)
{
@@ -143,27 +166,52 @@
msr = get_msr();
set_msr(msr & ~0x8000); /* disable interrupts */
- remove_bpts();
+ xmon_regs[smp_processor_id()] = excp;
+ xmon_enter();
excprint(excp);
+#ifdef CONFIG_SMP
+ if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon))
+ for (;;)
+ ;
+ while (test_and_set_bit(0, &got_xmon)) {
+ if (take_xmon == smp_processor_id()) {
+ take_xmon = -1;
+ break;
+ }
+ }
+ /*
+ * XXX: breakpoints are removed while any cpu is in xmon
+ */
+#endif /* CONFIG_SMP */
+ remove_bpts();
cmd = cmds(excp);
if (cmd == 's') {
- xmon_trace = SSTEP;
+ xmon_trace[smp_processor_id()] = SSTEP;
excp->msr |= 0x400;
} else if (at_breakpoint(excp->nip)) {
- xmon_trace = BRSTEP;
+ xmon_trace[smp_processor_id()] = BRSTEP;
excp->msr |= 0x400;
} else {
- xmon_trace = 0;
+ xmon_trace[smp_processor_id()] = 0;
insert_bpts();
}
+ xmon_leave();
+ xmon_regs[smp_processor_id()] = 0;
+#ifdef CONFIG_SMP
+ clear_bit(0, &got_xmon);
+ clear_bit(smp_processor_id(), &cpus_in_xmon);
+#endif /* CONFIG_SMP */
set_msr(msr); /* restore interrupt enable */
}
void
xmon_irq(int irq, void *d, struct pt_regs *regs)
{
+ unsigned long flags;
+ save_flags(flags);cli();
printf("Keyboard interrupt\n");
xmon(regs);
+ restore_flags(flags);
}
int
@@ -178,7 +226,7 @@
--bp->count;
remove_bpts();
excprint(regs);
- xmon_trace = BRSTEP;
+ xmon_trace[smp_processor_id()] = BRSTEP;
regs->msr |= 0x400;
} else {
xmon(regs);
@@ -189,10 +237,10 @@
int
xmon_sstep(struct pt_regs *regs)
{
- if (!xmon_trace)
+ if (!xmon_trace[smp_processor_id()])
return 0;
- if (xmon_trace == BRSTEP) {
- xmon_trace = 0;
+ if (xmon_trace[smp_processor_id()] == BRSTEP) {
+ xmon_trace[smp_processor_id()] = 0;
insert_bpts();
} else {
xmon(regs);
@@ -207,7 +255,7 @@
--dabr.count;
remove_bpts();
excprint(regs);
- xmon_trace = BRSTEP;
+ xmon_trace[smp_processor_id()] = BRSTEP;
regs->msr |= 0x400;
} else {
dabr.instr = regs->nip;
@@ -223,7 +271,7 @@
--iabr.count;
remove_bpts();
excprint(regs);
- xmon_trace = BRSTEP;
+ xmon_trace[smp_processor_id()] = BRSTEP;
regs->msr |= 0x400;
} else {
xmon(regs);
@@ -264,6 +312,7 @@
bp->address);
bp->enabled = 0;
}
+ store_inst((void *) bp->address);
}
#if !defined(CONFIG_8xx) && !defined(CONFIG_POWER4)
if (dabr.enabled)
@@ -293,6 +342,7 @@
&& mwrite(bp->address, &bp->instr, 4) != 4)
printf("Couldn't remove breakpoint at %x\n",
bp->address);
+ store_inst((void *) bp->address);
}
}
@@ -306,6 +356,9 @@
last_cmd = NULL;
for(;;) {
+#ifdef CONFIG_SMP
+ printf("%d:", smp_processor_id());
+#endif /* CONFIG_SMP */
printf("mon> ");
fflush(stdout);
flush_input();
@@ -383,12 +436,67 @@
case 'b':
bpt_cmds();
break;
- case 'c':
+ case 'C':
csum();
break;
+#ifdef CONFIG_SMP
+ case 'c':
+ cpu_cmd();
+ break;
+#endif /* CONFIG_SMP */
+ }
+ }
+}
+
+#ifdef CONFIG_SMP
+static void cpu_cmd(void)
+{
+ unsigned cpu;
+ int timeout;
+ int cmd;
+
+ cmd = inchar();
+ if (cmd == 'i') {
+ /* interrupt other cpu(s) */
+ cpu = MSG_ALL_BUT_SELF;
+ scanhex(&cpu);
+ smp_send_xmon_break(cpu);
+ return;
+ }
+ termch = cmd;
+ if (!scanhex(&cpu)) {
+ /* print cpus waiting or in xmon */
+ printf("cpus stopped:");
+ for (cpu = 0; cpu < NR_CPUS; ++cpu) {
+ if (test_bit(cpu, &cpus_in_xmon)) {
+ printf(" %d", cpu);
+ if (cpu == smp_processor_id())
+ printf("*", cpu);
+ }
+ }
+ printf("\n");
+ return;
+ }
+ /* try to switch to cpu specified */
+ take_xmon = cpu;
+ timeout = 10000000;
+ while (take_xmon >= 0) {
+ if (--timeout == 0) {
+ /* yes there's a race here */
+ take_xmon = -1;
+ printf("cpu %u didn't take control\n", cpu);
+ return;
+ }
+ }
+ /* now have to wait to be given control back */
+ while (test_and_set_bit(0, &got_xmon)) {
+ if (take_xmon == smp_processor_id()) {
+ take_xmon = -1;
+ break;
}
}
}
+#endif /* CONFIG_SMP */
static unsigned short fcstab[256] = {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
@@ -551,6 +659,8 @@
extern char lost_irq_ret, do_bottom_half_ret, do_signal_ret;
extern char ret_from_except;
+ printf("backtrace:\n");
+
if (excp != NULL)
sp = excp->gpr[1];
else
@@ -592,6 +702,9 @@
void
excprint(struct pt_regs *fp)
{
+#ifdef CONFIG_SMP
+ printf("cpu %d: ", smp_processor_id());
+#endif /* CONFIG_SMP */
printf("vector: %x at pc = %x",
fp->trap, fp->nip);
printf(", lr = %x, msr = %x, sp = %x [%x]\n",
@@ -1163,9 +1276,6 @@
return c;
}
-#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
- || ('a' <= (c) && (c) <= 'f') \
- || ('A' <= (c) && (c) <= 'F'))
void
dump()
{
@@ -1402,6 +1512,16 @@
return c;
}
+#define N_PTREGS 44
+static char *regnames[N_PTREGS] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+ "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "mq",
+ "trap", "dar", "dsisr", "res"
+};
+
int
scanhex(vp)
unsigned *vp;
@@ -1410,6 +1530,36 @@
unsigned v;
c = skipbl();
+ if (c == '%') {
+ /* parse register name */
+ char regname[8];
+ int i;
+
+ for (i = 0; i < sizeof(regname) - 1; ++i) {
+ c = inchar();
+ if (!isalnum(c)) {
+ termch = c;
+ break;
+ }
+ regname[i] = c;
+ }
+ regname[i] = 0;
+ for (i = 0; i < N_PTREGS; ++i) {
+ if (strcmp(regnames[i], regname) == 0) {
+ unsigned *rp = (unsigned *)
+ xmon_regs[smp_processor_id()];
+ if (rp == NULL) {
+ printf("regs not available\n");
+ return 0;
+ }
+ *vp = rp[i];
+ return 1;
+ }
+ }
+ printf("invalid register name '%%%s'\n", regname);
+ return 0;
+ }
+
d = hexdigit(c);
if( d == EOF ){
termch = c;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)