diff options
Diffstat (limited to 'arch/powerpc/xmon/xmon.c')
| -rw-r--r-- | arch/powerpc/xmon/xmon.c | 566 |
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, ®s, sizeof(regs)) + if (mread(sp + STACK_FRAME_OVERHEAD, ®s, 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(®s))); 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; } |
