aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/xmon/xmon.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/xmon/xmon.c')
-rw-r--r--arch/powerpc/xmon/xmon.c566
1 files changed, 397 insertions, 169 deletions
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 4e6152c1376..d199bfa2f1f 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -17,8 +17,9 @@
#include <linux/reboot.h>
#include <linux/delay.h>
#include <linux/kallsyms.h>
+#include <linux/kmsg_dump.h>
#include <linux/cpumask.h>
-#include <linux/module.h>
+#include <linux/export.h>
#include <linux/sysrq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -39,9 +40,10 @@
#include <asm/irq_regs.h>
#include <asm/spu.h>
#include <asm/spu_priv1.h>
-#include <asm/firmware.h>
#include <asm/setjmp.h>
#include <asm/reg.h>
+#include <asm/debug.h>
+#include <asm/hw_breakpoint.h>
#ifdef CONFIG_PPC64
#include <asm/hvcall.h>
@@ -51,17 +53,16 @@
#include "nonstdio.h"
#include "dis-asm.h"
-#define scanhex xmon_scanhex
-#define skipbl xmon_skipbl
-
#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 = 0;
+static unsigned long in_xmon __read_mostly = 0;
static unsigned long adrs;
static int size = 1;
@@ -155,6 +156,9 @@ 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
static int xmon_no_auto_backtrace;
@@ -163,15 +167,15 @@ extern void xmon_leave(void);
#ifdef CONFIG_PPC64
#define REG "%.16lx"
-#define REGS_PER_LINE 4
-#define LAST_VOLATILE 13
#else
#define REG "%.8lx"
-#define REGS_PER_LINE 8
-#define LAST_VOLATILE 12
#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
#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
|| ('a' <= (c) && (c) <= 'f') \
@@ -198,7 +202,13 @@ Commands:\n\
di dump instructions\n\
df dump float values\n\
dd dump double values\n\
- dl dump the kernel log buffer\n\
+ dl dump the kernel log buffer\n"
+#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\
e print exception information\n\
f flush cache\n\
@@ -225,13 +235,11 @@ Commands:\n\
t print backtrace\n\
x exit monitor and recover\n\
X exit monitor and dont recover\n"
-#ifdef CONFIG_PPC64
+#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
" u dump segment table or SLB\n"
-#endif
-#ifdef CONFIG_PPC_STD_MMU_32
+#elif defined(CONFIG_PPC_STD_MMU_32)
" u dump segment registers\n"
-#endif
-#ifdef CONFIG_44x
+#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
" u dump TLB\n"
#endif
" ? help\n"
@@ -305,16 +313,23 @@ static void get_output_lock(void)
if (xmon_speaker == me)
return;
+
for (;;) {
- if (xmon_speaker == 0) {
- last_speaker = cmpxchg(&xmon_speaker, 0, me);
- if (last_speaker == 0)
- return;
- }
- timeout = 10000000;
+ 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)
+ if (--timeout > 0) {
+ udelay(100);
continue;
+ }
+
/* hostile takeover */
prev = cmpxchg(&xmon_speaker, last_speaker, me);
if (prev == last_speaker)
@@ -331,14 +346,14 @@ static void release_output_lock(void)
int cpus_are_in_xmon(void)
{
- return !cpus_empty(cpus_in_xmon);
+ return !cpumask_empty(&cpus_in_xmon);
}
#endif
static inline int unrecoverable_excp(struct pt_regs *regs)
{
-#ifdef CONFIG_4xx
- /* We have no MSR_RI bit on 4xx, so we simply return false */
+#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);
@@ -370,7 +385,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
#ifdef CONFIG_SMP
cpu = smp_processor_id();
- if (cpu_isset(cpu, cpus_in_xmon)) {
+ if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
get_output_lock();
excprint(regs);
printf("cpu 0x%x: Exception %lx %s in xmon, "
@@ -393,10 +408,9 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
}
xmon_fault_jmp[cpu] = recurse_jmp;
- cpu_set(cpu, cpus_in_xmon);
bp = NULL;
- if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF))
+ 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;
@@ -405,7 +419,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
get_output_lock();
excprint(regs);
if (bp) {
- printf("cpu 0x%x stopped at breakpoint 0x%x (",
+ printf("cpu 0x%x stopped at breakpoint 0x%lx (",
cpu, BP_NUM(bp));
xmon_print_symbol(regs->nip, " ", ")\n");
}
@@ -415,6 +429,8 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
release_output_lock();
}
+ cpumask_set_cpu(cpu, &cpus_in_xmon);
+
waiting:
secondary = 1;
while (secondary && !xmon_gate) {
@@ -434,10 +450,10 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
xmon_owner = cpu;
mb();
if (ncpus > 1) {
- smp_send_debugger_break(MSG_ALL_BUT_SELF);
+ smp_send_debugger_break();
/* wait for other cpus to come in */
for (timeout = 100000000; timeout != 0; --timeout) {
- if (cpus_weight(cpus_in_xmon) >= ncpus)
+ if (cpumask_weight(&cpus_in_xmon) >= ncpus)
break;
barrier();
}
@@ -481,7 +497,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
}
}
leave:
- cpu_clear(cpu, cpus_in_xmon);
+ cpumask_clear_cpu(cpu, &cpus_in_xmon);
xmon_fault_jmp[cpu] = NULL;
#else
/* UP is simple... */
@@ -497,7 +513,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
excprint(regs);
bp = at_breakpoint(regs->nip);
if (bp) {
- printf("Stopped at breakpoint %x (", BP_NUM(bp));
+ printf("Stopped at breakpoint %lx (", BP_NUM(bp));
xmon_print_symbol(regs->nip, " ", ")\n");
}
if (unrecoverable_excp(regs))
@@ -526,7 +542,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
}
}
#else
- if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
+ 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]);
@@ -575,7 +591,7 @@ static int xmon_bpt(struct pt_regs *regs)
struct bpt *bp;
unsigned long offset;
- if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
+ 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? */
@@ -604,9 +620,9 @@ static int xmon_sstep(struct pt_regs *regs)
return 1;
}
-static int xmon_dabr_match(struct pt_regs *regs)
+static int xmon_break_match(struct pt_regs *regs)
{
- if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
+ if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
return 0;
if (dabr.enabled == 0)
return 0;
@@ -616,7 +632,7 @@ static int xmon_dabr_match(struct pt_regs *regs)
static int xmon_iabr_match(struct pt_regs *regs)
{
- if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
+ if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
return 0;
if (iabr == NULL)
return 0;
@@ -627,7 +643,7 @@ static int xmon_iabr_match(struct pt_regs *regs)
static int xmon_ipi(struct pt_regs *regs)
{
#ifdef CONFIG_SMP
- if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon))
+ if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
xmon_core(regs, 1);
#endif
return 0;
@@ -641,7 +657,7 @@ static int xmon_fault_handler(struct pt_regs *regs)
if (in_xmon && catch_memory_errors)
handle_fault(regs); /* doesn't return */
- if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
+ 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;
@@ -737,8 +753,14 @@ static void insert_bpts(void)
static void insert_cpu_bpts(void)
{
- if (dabr.enabled)
- set_dabr(dabr.address | (dabr.enabled & 7));
+ struct arch_hw_breakpoint brk;
+
+ if (dabr.enabled) {
+ brk.address = dabr.address;
+ brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
+ brk.len = 8;
+ __set_breakpoint(&brk);
+ }
if (iabr && cpu_has_feature(CPU_FTR_IABR))
mtspr(SPRN_IABR, iabr->address
| (iabr->enabled & (BP_IABR|BP_IABR_TE)));
@@ -766,7 +788,7 @@ static void remove_bpts(void)
static void remove_cpu_bpts(void)
{
- set_dabr(0);
+ hw_breakpoint_disable();
if (cpu_has_feature(CPU_FTR_IABR))
mtspr(SPRN_IABR, 0);
}
@@ -818,7 +840,7 @@ cmds(struct pt_regs *excp)
memzcan();
break;
case 'i':
- show_mem();
+ show_mem(0);
break;
default:
termch = cmd;
@@ -882,21 +904,24 @@ cmds(struct pt_regs *excp)
case 'u':
dump_segments();
break;
-#endif
-#ifdef CONFIG_4xx
+#elif defined(CONFIG_4xx)
case 'u':
dump_tlb_44x();
break;
+#elif defined(CONFIG_PPC_BOOK3E)
+ case 'u':
+ dump_tlb_book3e();
+ break;
#endif
default:
printf("Unrecognized command: ");
- do {
+ do {
if (' ' < cmd && cmd <= '~')
putchar(cmd);
else
printf("\\x%x", cmd);
cmd = inchar();
- } while (cmd != '\n');
+ } while (cmd != '\n');
printf(" (type ? for help)\n");
break;
}
@@ -921,7 +946,7 @@ static int do_step(struct pt_regs *regs)
int stepped;
/* check we are in 64-bit kernel mode, translation enabled */
- if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) {
+ if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
if (mread(regs->nip, &instr, 4) == 4) {
stepped = emulate_step(regs, instr);
if (stepped < 0) {
@@ -959,32 +984,32 @@ static void bootcmds(void)
static int cpu_cmd(void)
{
#ifdef CONFIG_SMP
- unsigned long cpu;
+ unsigned long cpu, first_cpu, last_cpu;
int timeout;
- int count;
if (!scanhex(&cpu)) {
/* print cpus waiting or in xmon */
printf("cpus stopped:");
- count = 0;
- for (cpu = 0; cpu < NR_CPUS; ++cpu) {
- if (cpu_isset(cpu, cpus_in_xmon)) {
- if (count == 0)
- printf(" %x", cpu);
- ++count;
- } else {
- if (count > 1)
- printf("-%x", cpu - 1);
- count = 0;
+ last_cpu = first_cpu = NR_CPUS;
+ for_each_possible_cpu(cpu) {
+ if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
+ if (cpu == last_cpu + 1) {
+ last_cpu = cpu;
+ } else {
+ if (last_cpu != first_cpu)
+ printf("-0x%lx", last_cpu);
+ last_cpu = first_cpu = cpu;
+ printf(" 0x%lx", cpu);
+ }
}
}
- if (count > 1)
- printf("-%x", NR_CPUS - 1);
+ if (last_cpu != first_cpu)
+ printf("-0x%lx", last_cpu);
printf("\n");
return 0;
}
/* try to switch to cpu specified */
- if (!cpu_isset(cpu, cpus_in_xmon)) {
+ if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
printf("cpu 0x%x isn't in xmon\n", cpu);
return 0;
}
@@ -999,7 +1024,7 @@ static int cpu_cmd(void)
/* take control back */
mb();
xmon_owner = smp_processor_id();
- printf("cpu %u didn't take control\n", cpu);
+ printf("cpu 0x%x didn't take control\n", cpu);
return 0;
}
barrier();
@@ -1061,7 +1086,7 @@ csum(void)
fcs = 0xffff;
for (i = 0; i < ncsum; ++i) {
if (mread(adrs+i, &v, 1) == 0) {
- printf("csum stopped at %x\n", adrs+i);
+ printf("csum stopped at "REG"\n", adrs+i);
break;
}
fcs = FCS(fcs, v);
@@ -1093,7 +1118,7 @@ static long check_bp_loc(unsigned long addr)
return 1;
}
-static char *breakpoint_help_string =
+static char *breakpoint_help_string =
"Breakpoint command usage:\n"
"b show breakpoints\n"
"b <addr> [cnt] set breakpoint at given instr addr\n"
@@ -1132,7 +1157,7 @@ bpt_cmds(void)
printf(badaddr);
break;
}
- dabr.address &= ~7;
+ dabr.address &= ~HW_BRK_TYPE_DABR;
dabr.enabled = mode | BP_DABR;
}
break;
@@ -1177,19 +1202,19 @@ bpt_cmds(void)
/* assume a breakpoint address */
bp = at_breakpoint(a);
if (bp == NULL) {
- printf("No breakpoint at %x\n", a);
+ printf("No breakpoint at %lx\n", a);
break;
}
}
- printf("Cleared breakpoint %x (", BP_NUM(bp));
+ printf("Cleared breakpoint %lx (", BP_NUM(bp));
xmon_print_symbol(bp->address, " ", ")\n");
bp->enabled = 0;
break;
default:
termch = cmd;
- cmd = skipbl();
+ cmd = skipbl();
if (cmd == '?') {
printf(breakpoint_help_string);
break;
@@ -1243,11 +1268,18 @@ const char *getvecname(unsigned long vec)
case 0x700: ret = "(Program Check)"; break;
case 0x800: ret = "(FPU Unavailable)"; break;
case 0x900: ret = "(Decrementer)"; break;
+ case 0x980: ret = "(Hypervisor Decrementer)"; break;
+ case 0xa00: ret = "(Doorbell)"; break;
case 0xc00: ret = "(System Call)"; break;
case 0xd00: ret = "(Single Step)"; break;
+ case 0xe40: ret = "(Emulation Assist)"; break;
+ case 0xe60: ret = "(HMI)"; break;
+ case 0xe80: ret = "(Hypervisor Doorbell)"; break;
case 0xf00: ret = "(Performance Monitor)"; break;
case 0xf20: ret = "(Altivec Unavailable)"; break;
case 0x1300: ret = "(Instruction Breakpoint)"; break;
+ case 0x1500: ret = "(Denormalisation)"; break;
+ case 0x1700: ret = "(Altivec Assist)"; break;
default: ret = "";
}
return ret;
@@ -1275,27 +1307,19 @@ static void get_function_bounds(unsigned long pc, unsigned long *startp,
catch_memory_errors = 0;
}
-static int xmon_depth_to_print = 64;
-
#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
-#ifdef __powerpc64__
-#define REGS_OFFSET 0x70
-#else
-#define REGS_OFFSET 16
-#endif
-
static void xmon_show_stack(unsigned long sp, unsigned long lr,
unsigned long pc)
{
+ int max_to_print = 64;
unsigned long ip;
unsigned long newsp;
unsigned long marker;
- int count = 0;
struct pt_regs regs;
- do {
+ while (max_to_print--) {
if (sp < PAGE_OFFSET) {
if (sp != 0)
printf("SP (%lx) is in userspace\n", sp);
@@ -1349,13 +1373,13 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr,
an exception frame. */
if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
&& marker == STACK_FRAME_REGS_MARKER) {
- if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
+ if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
!= sizeof(regs)) {
printf("Couldn't read registers at %lx\n",
- sp + REGS_OFFSET);
+ sp + STACK_FRAME_OVERHEAD);
break;
}
- printf("--- Exception: %lx %s at ", regs.trap,
+ printf("--- Exception: %lx %s at ", regs.trap,
getvecname(TRAP(&regs)));
pc = regs.nip;
lr = regs.link;
@@ -1366,7 +1390,7 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr,
break;
sp = newsp;
- } while (count++ < xmon_depth_to_print);
+ }
}
static void backtrace(struct pt_regs *excp)
@@ -1425,7 +1449,7 @@ static void excprint(struct pt_regs *fp)
printf(" sp: %lx\n", fp->gpr[1]);
printf(" msr: %lx\n", fp->msr);
- if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
+ if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
printf(" dar: %lx\n", fp->dar);
if (trap != 0x380)
printf(" dsisr: %lx\n", fp->dsisr);
@@ -1433,7 +1457,8 @@ static void excprint(struct pt_regs *fp)
printf(" current = 0x%lx\n", current);
#ifdef CONFIG_PPC64
- printf(" paca = 0x%lx\n", get_paca());
+ printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
+ local_paca, local_paca->soft_enabled, local_paca->irq_happened);
#endif
if (current) {
printf(" pid = %ld, comm = %s\n",
@@ -1489,6 +1514,10 @@ static void prregs(struct pt_regs *fp)
#endif
printf("pc = ");
xmon_print_symbol(fp->nip, " ", "\n");
+ if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
+ printf("cfar= ");
+ xmon_print_symbol(fp->orig_gpr3, " ", "\n");
+ }
printf("lr = ");
xmon_print_symbol(fp->link, " ", "\n");
printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
@@ -1614,37 +1643,18 @@ static void super_regs(void)
cmd = skipbl();
if (cmd == '\n') {
- unsigned long sp, toc;
+ unsigned long sp, toc;
asm("mr %0,1" : "=r" (sp) :);
asm("mr %0,2" : "=r" (toc) :);
printf("msr = "REG" sprg0= "REG"\n",
mfmsr(), mfspr(SPRN_SPRG0));
printf("pvr = "REG" sprg1= "REG"\n",
- mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
+ mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
printf("dec = "REG" sprg2= "REG"\n",
mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
-#ifdef CONFIG_PPC_ISERIES
- if (firmware_has_feature(FW_FEATURE_ISERIES)) {
- struct paca_struct *ptrPaca;
- struct lppaca *ptrLpPaca;
-
- /* Dump out relevant Paca data areas. */
- printf("Paca: \n");
- ptrPaca = get_paca();
-
- printf(" Local Processor Control Area (LpPaca): \n");
- ptrLpPaca = ptrPaca->lppaca_ptr;
- printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n",
- ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
- printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n",
- ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
- printf(" Saved Gpr5=%.16lx \n",
- ptrLpPaca->gpr5_dword.saved_gpr5);
- }
-#endif
return;
}
@@ -1736,7 +1746,7 @@ mwrite(unsigned long adrs, void *buf, int size)
__delay(200);
n = size;
} else {
- printf("*** Error writing address %x\n", adrs + n);
+ printf("*** Error writing address "REG"\n", adrs + n);
}
catch_memory_errors = 0;
return n;
@@ -1793,7 +1803,7 @@ byterev(unsigned char *val, int size)
static int brev;
static int mnoread;
-static char *memex_help_string =
+static char *memex_help_string =
"Memory examine command usage:\n"
"m [addr] [flags] examine/change memory\n"
" addr is optional. will start where left off.\n"
@@ -1808,7 +1818,7 @@ static char *memex_help_string =
"NOTE: flags are saved as defaults\n"
"";
-static char *memex_subcmd_help_string =
+static char *memex_subcmd_help_string =
"Memory examine subcommands:\n"
" hexval write this val to current location\n"
" 'string' write chars from string to this location\n"
@@ -2018,6 +2028,99 @@ static void xmon_rawdump (unsigned long adrs, long ndump)
printf("\n");
}
+#ifdef CONFIG_PPC64
+static void dump_one_paca(int cpu)
+{
+ struct paca_struct *p;
+
+ if (setjmp(bus_error_jmp) != 0) {
+ printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
+ return;
+ }
+
+ catch_memory_errors = 1;
+ sync();
+
+ p = &paca[cpu];
+
+ printf("paca for cpu 0x%x @ %p:\n", cpu, p);
+
+ printf(" %-*s = %s\n", 16, "possible", cpu_possible(cpu) ? "yes" : "no");
+ printf(" %-*s = %s\n", 16, "present", cpu_present(cpu) ? "yes" : "no");
+ printf(" %-*s = %s\n", 16, "online", cpu_online(cpu) ? "yes" : "no");
+
+#define DUMP(paca, name, format) \
+ printf(" %-*s = %#-*"format"\t(0x%lx)\n", 16, #name, 18, paca->name, \
+ offsetof(struct paca_struct, name));
+
+ DUMP(p, lock_token, "x");
+ DUMP(p, paca_index, "x");
+ DUMP(p, kernel_toc, "lx");
+ DUMP(p, kernelbase, "lx");
+ DUMP(p, kernel_msr, "lx");
+#ifdef CONFIG_PPC_STD_MMU_64
+ DUMP(p, stab_real, "lx");
+ DUMP(p, stab_addr, "lx");
+#endif
+ DUMP(p, emergency_sp, "p");
+#ifdef CONFIG_PPC_BOOK3S_64
+ DUMP(p, mc_emergency_sp, "p");
+ DUMP(p, in_mce, "x");
+#endif
+ DUMP(p, data_offset, "lx");
+ DUMP(p, hw_cpu_id, "x");
+ DUMP(p, cpu_start, "x");
+ DUMP(p, kexec_state, "x");
+ DUMP(p, __current, "p");
+ DUMP(p, kstack, "lx");
+ DUMP(p, stab_rr, "lx");
+ DUMP(p, saved_r1, "lx");
+ DUMP(p, trap_save, "x");
+ DUMP(p, soft_enabled, "x");
+ DUMP(p, irq_happened, "x");
+ DUMP(p, io_sync, "x");
+ DUMP(p, irq_work_pending, "x");
+ DUMP(p, nap_state_lost, "x");
+
+#undef DUMP
+
+ catch_memory_errors = 0;
+ sync();
+}
+
+static void dump_all_pacas(void)
+{
+ int cpu;
+
+ if (num_possible_cpus() == 0) {
+ printf("No possible cpus, use 'dp #' to dump individual cpus\n");
+ return;
+ }
+
+ for_each_possible_cpu(cpu)
+ dump_one_paca(cpu);
+}
+
+static void dump_pacas(void)
+{
+ unsigned long num;
+ int c;
+
+ c = inchar();
+ if (c == 'a') {
+ dump_all_pacas();
+ return;
+ }
+
+ termch = c; /* Put c back, it wasn't 'a' */
+
+ if (scanhex(&num))
+ dump_one_paca(num);
+ else
+ dump_one_paca(xmon_owner);
+}
+#endif
+
#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
|| ('a' <= (c) && (c) <= 'f') \
|| ('A' <= (c) && (c) <= 'F'))
@@ -2027,6 +2130,14 @@ dump(void)
int c;
c = inchar();
+
+#ifdef CONFIG_PPC64
+ if (c == 'p') {
+ dump_pacas();
+ return;
+ }
+#endif
+
if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
termch = c;
scanhex((void *)&adrs);
@@ -2074,7 +2185,7 @@ prdump(unsigned long adrs, long ndump)
nr = mread(adrs, temp, r);
adrs += nr;
for (m = 0; m < r; ++m) {
- if ((m & (sizeof(long) - 1)) == 0 && m > 0)
+ if ((m & (sizeof(long) - 1)) == 0 && m > 0)
putchar(' ');
if (m < nr)
printf("%.2x", temp[m]);
@@ -2082,7 +2193,7 @@ prdump(unsigned long adrs, long ndump)
printf("%s", fault_chars[fault_type]);
}
for (; m < 16; ++m) {
- if ((m & (sizeof(long) - 1)) == 0)
+ if ((m & (sizeof(long) - 1)) == 0)
putchar(' ');
printf(" ");
}
@@ -2158,45 +2269,28 @@ print_address(unsigned long addr)
void
dump_log_buf(void)
{
- const unsigned long size = 128;
- unsigned long end, addr;
- unsigned char buf[size + 1];
-
- addr = 0;
- buf[size] = '\0';
-
- if (setjmp(bus_error_jmp) != 0) {
- printf("Unable to lookup symbol __log_buf!\n");
- return;
- }
+ struct kmsg_dumper dumper = { .active = 1 };
+ unsigned char buf[128];
+ size_t len;
- catch_memory_errors = 1;
- sync();
- addr = kallsyms_lookup_name("__log_buf");
-
- if (! addr)
- printf("Symbol __log_buf not found!\n");
- else {
- end = addr + (1 << CONFIG_LOG_BUF_SHIFT);
- while (addr < end) {
- if (! mread(addr, buf, size)) {
- printf("Can't read memory at address 0x%lx\n", addr);
- break;
- }
-
- printf("%s", buf);
+ if (setjmp(bus_error_jmp) != 0) {
+ printf("Error dumping printk buffer!\n");
+ return;
+ }
- if (strlen(buf) < size)
- break;
+ catch_memory_errors = 1;
+ sync();
- addr += size;
- }
- }
+ kmsg_dump_rewind_nolock(&dumper);
+ while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
+ buf[len] = '\0';
+ printf("%s", buf);
+ }
- sync();
- /* wait a little while to see if we get a machine check */
- __delay(200);
- catch_memory_errors = 0;
+ sync();
+ /* wait a little while to see if we get a machine check */
+ __delay(200);
+ catch_memory_errors = 0;
}
/*
@@ -2341,7 +2435,7 @@ static void proccall(void)
ret = func(args[0], args[1], args[2], args[3],
args[4], args[5], args[6], args[7]);
sync();
- printf("return value is %x\n", ret);
+ printf("return value is 0x%lx\n", ret);
} else {
printf("*** %x exception occurred\n", fault_except);
}
@@ -2606,7 +2700,7 @@ static void dump_slb(void)
unsigned long esid,vsid,valid;
unsigned long llp;
- printf("SLB contents of cpu %x\n", smp_processor_id());
+ printf("SLB contents of cpu 0x%x\n", smp_processor_id());
for (i = 0; i < mmu_slb_size; i++) {
asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
@@ -2636,9 +2730,9 @@ static void dump_slb(void)
static void dump_stab(void)
{
int i;
- unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
+ unsigned long *tmp = (unsigned long *)local_paca->stab_addr;
- printf("Segment table contents of cpu %x\n", smp_processor_id());
+ printf("Segment table contents of cpu 0x%x\n", smp_processor_id());
for (i = 0; i < PAGE_SIZE/16; i++) {
unsigned long a, b;
@@ -2655,7 +2749,7 @@ static void dump_stab(void)
void dump_segments(void)
{
- if (cpu_has_feature(CPU_FTR_SLB))
+ if (mmu_has_feature(MMU_FTR_SLB))
dump_slb();
else
dump_stab();
@@ -2701,19 +2795,159 @@ static void dump_tlb_44x(void)
}
#endif /* CONFIG_44x */
+#ifdef CONFIG_PPC_BOOK3E
+static void dump_tlb_book3e(void)
+{
+ u32 mmucfg, pidmask, lpidmask;
+ u64 ramask;
+ int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
+ int mmu_version;
+ static const char *pgsz_names[] = {
+ " 1K",
+ " 2K",
+ " 4K",
+ " 8K",
+ " 16K",
+ " 32K",
+ " 64K",
+ "128K",
+ "256K",
+ "512K",
+ " 1M",
+ " 2M",
+ " 4M",
+ " 8M",
+ " 16M",
+ " 32M",
+ " 64M",
+ "128M",
+ "256M",
+ "512M",
+ " 1G",
+ " 2G",
+ " 4G",
+ " 8G",
+ " 16G",
+ " 32G",
+ " 64G",
+ "128G",
+ "256G",
+ "512G",
+ " 1T",
+ " 2T",
+ };
+
+ /* Gather some infos about the MMU */
+ mmucfg = mfspr(SPRN_MMUCFG);
+ mmu_version = (mmucfg & 3) + 1;
+ ntlbs = ((mmucfg >> 2) & 3) + 1;
+ pidsz = ((mmucfg >> 6) & 0x1f) + 1;
+ lpidsz = (mmucfg >> 24) & 0xf;
+ rasz = (mmucfg >> 16) & 0x7f;
+ if ((mmu_version > 1) && (mmucfg & 0x10000))
+ lrat = 1;
+ printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
+ mmu_version, ntlbs, pidsz, lpidsz, rasz);
+ pidmask = (1ul << pidsz) - 1;
+ lpidmask = (1ul << lpidsz) - 1;
+ ramask = (1ull << rasz) - 1;
+
+ for (tlb = 0; tlb < ntlbs; tlb++) {
+ u32 tlbcfg;
+ int nent, assoc, new_cc = 1;
+ printf("TLB %d:\n------\n", tlb);
+ switch(tlb) {
+ case 0:
+ tlbcfg = mfspr(SPRN_TLB0CFG);
+ break;
+ case 1:
+ tlbcfg = mfspr(SPRN_TLB1CFG);
+ break;
+ case 2:
+ tlbcfg = mfspr(SPRN_TLB2CFG);
+ break;
+ case 3:
+ tlbcfg = mfspr(SPRN_TLB3CFG);
+ break;
+ default:
+ printf("Unsupported TLB number !\n");
+ continue;
+ }
+ nent = tlbcfg & 0xfff;
+ assoc = (tlbcfg >> 24) & 0xff;
+ for (i = 0; i < nent; i++) {
+ u32 mas0 = MAS0_TLBSEL(tlb);
+ u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
+ u64 mas2 = 0;
+ u64 mas7_mas3;
+ int esel = i, cc = i;
+
+ if (assoc != 0) {
+ cc = i / assoc;
+ esel = i % assoc;
+ mas2 = cc * 0x1000;
+ }
+
+ mas0 |= MAS0_ESEL(esel);
+ mtspr(SPRN_MAS0, mas0);
+ mtspr(SPRN_MAS1, mas1);
+ mtspr(SPRN_MAS2, mas2);
+ asm volatile("tlbre 0,0,0" : : : "memory");
+ mas1 = mfspr(SPRN_MAS1);
+ mas2 = mfspr(SPRN_MAS2);
+ mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
+ if (assoc && (i % assoc) == 0)
+ new_cc = 1;
+ if (!(mas1 & MAS1_VALID))
+ continue;
+ if (assoc == 0)
+ printf("%04x- ", i);
+ else if (new_cc)
+ printf("%04x-%c", cc, 'A' + esel);
+ else
+ printf(" |%c", 'A' + esel);
+ new_cc = 0;
+ printf(" %016llx %04x %s %c%c AS%c",
+ mas2 & ~0x3ffull,
+ (mas1 >> 16) & 0x3fff,
+ pgsz_names[(mas1 >> 7) & 0x1f],
+ mas1 & MAS1_IND ? 'I' : ' ',
+ mas1 & MAS1_IPROT ? 'P' : ' ',
+ mas1 & MAS1_TS ? '1' : '0');
+ printf(" %c%c%c%c%c%c%c",
+ mas2 & MAS2_X0 ? 'a' : ' ',
+ mas2 & MAS2_X1 ? 'v' : ' ',
+ mas2 & MAS2_W ? 'w' : ' ',
+ mas2 & MAS2_I ? 'i' : ' ',
+ mas2 & MAS2_M ? 'm' : ' ',
+ mas2 & MAS2_G ? 'g' : ' ',
+ mas2 & MAS2_E ? 'e' : ' ');
+ printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
+ if (mas1 & MAS1_IND)
+ printf(" %s\n",
+ pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
+ else
+ printf(" U%c%c%c S%c%c%c\n",
+ mas7_mas3 & MAS3_UX ? 'x' : ' ',
+ mas7_mas3 & MAS3_UW ? 'w' : ' ',
+ mas7_mas3 & MAS3_UR ? 'r' : ' ',
+ mas7_mas3 & MAS3_SX ? 'x' : ' ',
+ mas7_mas3 & MAS3_SW ? 'w' : ' ',
+ mas7_mas3 & MAS3_SR ? 'r' : ' ');
+ }
+ }
+}
+#endif /* CONFIG_PPC_BOOK3E */
+
static void xmon_init(int enable)
{
-#ifdef CONFIG_PPC_ISERIES
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- return;
-#endif
if (enable) {
__debugger = xmon;
__debugger_ipi = xmon_ipi;
__debugger_bpt = xmon_bpt;
__debugger_sstep = xmon_sstep;
__debugger_iabr_match = xmon_iabr_match;
- __debugger_dabr_match = xmon_dabr_match;
+ __debugger_break_match = xmon_break_match;
__debugger_fault_handler = xmon_fault_handler;
} else {
__debugger = NULL;
@@ -2721,33 +2955,27 @@ static void xmon_init(int enable)
__debugger_bpt = NULL;
__debugger_sstep = NULL;
__debugger_iabr_match = NULL;
- __debugger_dabr_match = NULL;
+ __debugger_break_match = NULL;
__debugger_fault_handler = NULL;
}
- xmon_map_scc();
}
#ifdef CONFIG_MAGIC_SYSRQ
-static void sysrq_handle_xmon(int key, struct tty_struct *tty)
+static void sysrq_handle_xmon(int key)
{
/* ensure xmon is enabled */
xmon_init(1);
debugger(get_irq_regs());
}
-static struct sysrq_key_op sysrq_xmon_op =
-{
+static struct sysrq_key_op sysrq_xmon_op = {
.handler = sysrq_handle_xmon,
- .help_msg = "Xmon",
+ .help_msg = "xmon(x)",
.action_msg = "Entering xmon",
};
static int __init setup_xmon_sysrq(void)
{
-#ifdef CONFIG_PPC_ISERIES
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- return 0;
-#endif
register_sysrq_key('x', &sysrq_xmon_op);
return 0;
}