blob: 07a8508cb7fae6cd1d0a742eb0c1d4c19769eeac [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Routines providing a simple monitor for use on the PowerMac.
3 *
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004 * Copyright (C) 1996-2005 Paul Mackerras.
Michael Ellerman476792832006-10-03 14:12:08 +10005 * Copyright (C) 2001 PPC64 Team, IBM Corp
6 * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/smp.h>
16#include <linux/mm.h>
17#include <linux/reboot.h>
18#include <linux/delay.h>
19#include <linux/kallsyms.h>
Michael Ellermanca5dd392012-08-23 22:09:12 +000020#include <linux/kmsg_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040022#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110023#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080024#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010025#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080026#include <linux/bug.h>
Anton Blancharda71d64b2014-08-05 14:55:00 +100027#include <linux/nmi.h>
Vincent Bernat05b981f2014-07-15 13:43:47 +020028#include <linux/ctype.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <asm/ptrace.h>
31#include <asm/string.h>
32#include <asm/prom.h>
33#include <asm/machdep.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100034#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/processor.h>
36#include <asm/pgtable.h>
37#include <asm/mmu.h>
38#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/cputable.h>
40#include <asm/rtas.h>
41#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100042#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020043#include <asm/spu.h>
44#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110045#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000046#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010047#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000048#include <asm/hw_breakpoint.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100049
50#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100052#include <asm/paca.h>
53#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Anshuman Khandual1ad7d702014-11-28 10:06:42 +053055#if defined(CONFIG_PPC_SPLPAR)
56#include <asm/plpar_wrappers.h>
57#else
58static inline long plapr_set_ciabr(unsigned long ciabr) {return 0; };
59#endif
60
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010062#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100065static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066static unsigned long xmon_taken = 1;
67static int xmon_owner;
68static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000069#else
70#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#endif /* CONFIG_SMP */
72
Anton Blanchard5be34922010-01-12 00:50:14 +000073static unsigned long in_xmon __read_mostly = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
75static unsigned long adrs;
76static int size = 1;
77#define MAX_DUMP (128 * 1024)
78static unsigned long ndump = 64;
79static unsigned long nidump = 16;
80static unsigned long ncsum = 4096;
81static int termch;
82static char tmpstr[128];
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084static long bus_error_jmp[JMP_BUF_LEN];
85static int catch_memory_errors;
86static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
88/* Breakpoint stuff */
89struct bpt {
90 unsigned long address;
91 unsigned int instr[2];
92 atomic_t ref_count;
93 int enabled;
94 unsigned long pad;
95};
96
97/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +110098#define BP_CIABR 1
99#define BP_TRAP 2
100#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
102#define NBPTS 256
103static struct bpt bpts[NBPTS];
104static struct bpt dabr;
105static struct bpt *iabr;
106static unsigned bpinstr = 0x7fe00008; /* trap */
107
108#define BP_NUM(bp) ((bp) - bpts + 1)
109
110/* Prototypes */
111static int cmds(struct pt_regs *);
112static int mread(unsigned long, void *, int);
113static int mwrite(unsigned long, void *, int);
114static int handle_fault(struct pt_regs *);
115static void byterev(unsigned char *, int);
116static void memex(void);
117static int bsesc(void);
118static void dump(void);
119static void prdump(unsigned long, long);
120static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000121static void dump_log_buf(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122static void backtrace(struct pt_regs *);
123static void excprint(struct pt_regs *);
124static void prregs(struct pt_regs *);
125static void memops(int);
126static void memlocate(void);
127static void memzcan(void);
128static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
129int skipbl(void);
130int scanhex(unsigned long *valp);
131static void scannl(void);
132static int hexdigit(int);
133void getstring(char *, int);
134static void flush_input(void);
135static int inchar(void);
136static void take_input(char *);
137static unsigned long read_spr(int);
138static void write_spr(int, unsigned long);
139static void super_regs(void);
140static void remove_bpts(void);
141static void insert_bpts(void);
142static void remove_cpu_bpts(void);
143static void insert_cpu_bpts(void);
144static struct bpt *at_breakpoint(unsigned long pc);
145static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
146static int do_step(struct pt_regs *);
147static void bpt_cmds(void);
148static void cacheflush(void);
149static int cpu_cmd(void);
150static void csum(void);
151static void bootcmds(void);
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000152static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153void dump_segments(void);
154static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200155static void xmon_show_stack(unsigned long sp, unsigned long lr,
156 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157static void xmon_print_symbol(unsigned long address, const char *mid,
158 const char *after);
159static const char *getvecname(unsigned long vec);
160
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200161static int do_spu_cmd(void);
162
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100163#ifdef CONFIG_44x
164static void dump_tlb_44x(void);
165#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000166#ifdef CONFIG_PPC_BOOK3E
167static void dump_tlb_book3e(void);
168#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100169
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000170static int xmon_no_auto_backtrace;
Olaf Hering26c8af52006-09-08 16:29:21 +0200171
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000172extern void xmon_enter(void);
173extern void xmon_leave(void);
174
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000175#ifdef CONFIG_PPC64
176#define REG "%.16lx"
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000177#else
178#define REG "%.8lx"
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000179#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100181#ifdef __LITTLE_ENDIAN__
182#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
183#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100185#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static char *help_string = "\
188Commands:\n\
189 b show breakpoints\n\
190 bd set data breakpoint\n\
191 bi set instruction breakpoint\n\
192 bc clear breakpoint\n"
193#ifdef CONFIG_SMP
194 "\
195 c print cpus stopped in xmon\n\
196 c# try to switch to cpu number h (in hex)\n"
197#endif
198 "\
199 C checksum\n\
200 d dump bytes\n\
201 di dump instructions\n\
202 df dump float values\n\
203 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000204 dl dump the kernel log buffer\n"
205#ifdef CONFIG_PPC64
206 "\
207 dp[#] dump paca for current cpu, or cpu #\n\
208 dpa dump paca for all possible cpus\n"
209#endif
210 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100211 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 e print exception information\n\
213 f flush cache\n\
214 la lookup symbol+offset of specified address\n\
215 ls lookup address of specified symbol\n\
216 m examine/change memory\n\
217 mm move a block of memory\n\
218 ms set a block of memory\n\
219 md compare two blocks of memory\n\
220 ml locate a block of memory\n\
221 mz zero a block of memory\n\
222 mi show information about memory allocation\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000223 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200225 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100226#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200227" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200228 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100229 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900230 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100231 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200232#endif
233" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 x exit monitor and recover\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000236 X exit monitor and dont recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000237#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000238" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000239#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000240" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000241#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100242" u dump TLB\n"
243#endif
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000244" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100245" # n limit output to n lines per page (for dp, dpa, dl)\n"
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000246" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 zh halt\n"
248;
249
250static struct pt_regs *xmon_regs;
251
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000252static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253{
254 asm volatile("sync; isync");
255}
256
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000257static inline void store_inst(void *p)
258{
259 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
260}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000262static inline void cflush(void *p)
263{
264 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
265}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000267static inline void cinval(void *p)
268{
269 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
270}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530272/**
273 * write_ciabr() - write the CIABR SPR
274 * @ciabr: The value to write.
275 *
276 * This function writes a value to the CIARB register either directly
277 * through mtspr instruction if the kernel is in HV privilege mode or
278 * call a hypervisor function to achieve the same in case the kernel
279 * is in supervisor privilege mode.
280 */
281static void write_ciabr(unsigned long ciabr)
282{
283 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
284 return;
285
286 if (cpu_has_feature(CPU_FTR_HVMODE)) {
287 mtspr(SPRN_CIABR, ciabr);
288 return;
289 }
290 plapr_set_ciabr(ciabr);
291}
292
293/**
294 * set_ciabr() - set the CIABR
295 * @addr: The value to set.
296 *
297 * This function sets the correct privilege value into the the HW
298 * breakpoint address before writing it up in the CIABR register.
299 */
300static void set_ciabr(unsigned long addr)
301{
302 addr &= ~CIABR_PRIV;
303
304 if (cpu_has_feature(CPU_FTR_HVMODE))
305 addr |= CIABR_PRIV_HYPER;
306 else
307 addr |= CIABR_PRIV_SUPER;
308 write_ciabr(addr);
309}
310
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311/*
312 * Disable surveillance (the service processor watchdog function)
313 * while we are in xmon.
314 * XXX we should re-enable it when we leave. :)
315 */
316#define SURVEILLANCE_TOKEN 9000
317
318static inline void disable_surveillance(void)
319{
320#ifdef CONFIG_PPC_PSERIES
321 /* Since this can't be a module, args should end up below 4GB. */
322 static struct rtas_args args;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100323 int token;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 /*
326 * At this point we have got all the cpus we can into
327 * xmon, so there is hopefully no other cpu calling RTAS
328 * at the moment, even though we don't take rtas.lock.
329 * If we did try to take rtas.lock there would be a
330 * real possibility of deadlock.
331 */
Michael Ellerman08eb1052015-11-24 22:26:09 +1100332 token = rtas_token("set-indicator");
333 if (token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100335
336 rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0);
337
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338#endif /* CONFIG_PPC_PSERIES */
339}
340
341#ifdef CONFIG_SMP
342static int xmon_speaker;
343
344static void get_output_lock(void)
345{
346 int me = smp_processor_id() + 0x100;
347 int last_speaker = 0, prev;
348 long timeout;
349
350 if (xmon_speaker == me)
351 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100354 last_speaker = cmpxchg(&xmon_speaker, 0, me);
355 if (last_speaker == 0)
356 return;
357
Michael Ellerman15075892013-12-23 23:46:05 +1100358 /*
359 * Wait a full second for the lock, we might be on a slow
360 * console, but check every 100us.
361 */
362 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100364 if (--timeout > 0) {
365 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100367 }
368
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 /* hostile takeover */
370 prev = cmpxchg(&xmon_speaker, last_speaker, me);
371 if (prev == last_speaker)
372 return;
373 break;
374 }
375 }
376}
377
378static void release_output_lock(void)
379{
380 xmon_speaker = 0;
381}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000382
383int cpus_are_in_xmon(void)
384{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000385 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000386}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387#endif
388
Josh Boyerdaf8f402009-09-23 03:51:04 +0000389static inline int unrecoverable_excp(struct pt_regs *regs)
390{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000391#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000392 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000393 return 0;
394#else
395 return ((regs->msr & MSR_RI) == 0);
396#endif
397}
398
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000399static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
401 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 struct bpt *bp;
403 long recurse_jmp[JMP_BUF_LEN];
404 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100405 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406#ifdef CONFIG_SMP
407 int cpu;
408 int secondary;
409 unsigned long timeout;
410#endif
411
Anton Blanchardf13659e2007-03-21 01:48:34 +1100412 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000413 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 bp = in_breakpoint_table(regs->nip, &offset);
416 if (bp != NULL) {
417 regs->nip = bp->address + offset;
418 atomic_dec(&bp->ref_count);
419 }
420
421 remove_cpu_bpts();
422
423#ifdef CONFIG_SMP
424 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000425 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 get_output_lock();
427 excprint(regs);
428 printf("cpu 0x%x: Exception %lx %s in xmon, "
429 "returning to main loop\n",
430 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000431 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 longjmp(xmon_fault_jmp[cpu], 1);
433 }
434
435 if (setjmp(recurse_jmp) != 0) {
436 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000437 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 printf("xmon: WARNING: bad recursive fault "
439 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000440 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 goto waiting;
442 }
443 secondary = !(xmon_taken && cpu == xmon_owner);
444 goto cmdloop;
445 }
446
447 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
449 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000450 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000452 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 fromipi = 0;
454
455 if (!fromipi) {
456 get_output_lock();
457 excprint(regs);
458 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000459 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 cpu, BP_NUM(bp));
461 xmon_print_symbol(regs->nip, " ", ")\n");
462 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000463 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 printf("WARNING: exception is not recoverable, "
465 "can't continue\n");
466 release_output_lock();
467 }
468
Michael Ellermand2b496e2013-12-23 23:46:06 +1100469 cpumask_set_cpu(cpu, &cpus_in_xmon);
470
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 waiting:
472 secondary = 1;
473 while (secondary && !xmon_gate) {
474 if (in_xmon == 0) {
475 if (fromipi)
476 goto leave;
477 secondary = test_and_set_bit(0, &in_xmon);
478 }
479 barrier();
480 }
481
482 if (!secondary && !xmon_gate) {
483 /* we are the first cpu to come in */
484 /* interrupt other cpu(s) */
485 int ncpus = num_online_cpus();
486
487 xmon_owner = cpu;
488 mb();
489 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000490 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 /* wait for other cpus to come in */
492 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000493 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 break;
495 barrier();
496 }
497 }
498 remove_bpts();
499 disable_surveillance();
500 /* for breakpoint or single step, print the current instr. */
501 if (bp || TRAP(regs) == 0xd00)
502 ppc_inst_dump(regs->nip, 1, 0);
503 printf("enter ? for help\n");
504 mb();
505 xmon_gate = 1;
506 barrier();
507 }
508
509 cmdloop:
510 while (in_xmon) {
511 if (secondary) {
512 if (cpu == xmon_owner) {
513 if (!test_and_set_bit(0, &xmon_taken)) {
514 secondary = 0;
515 continue;
516 }
517 /* missed it */
518 while (cpu == xmon_owner)
519 barrier();
520 }
521 barrier();
522 } else {
523 cmd = cmds(regs);
524 if (cmd != 0) {
525 /* exiting xmon */
526 insert_bpts();
527 xmon_gate = 0;
528 wmb();
529 in_xmon = 0;
530 break;
531 }
532 /* have switched to some other cpu */
533 secondary = 1;
534 }
535 }
536 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000537 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539#else
540 /* UP is simple... */
541 if (in_xmon) {
542 printf("Exception %lx %s in xmon, returning to main loop\n",
543 regs->trap, getvecname(TRAP(regs)));
544 longjmp(xmon_fault_jmp[0], 1);
545 }
546 if (setjmp(recurse_jmp) == 0) {
547 xmon_fault_jmp[0] = recurse_jmp;
548 in_xmon = 1;
549
550 excprint(regs);
551 bp = at_breakpoint(regs->nip);
552 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000553 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 xmon_print_symbol(regs->nip, " ", ")\n");
555 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000556 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 printf("WARNING: exception is not recoverable, "
558 "can't continue\n");
559 remove_bpts();
560 disable_surveillance();
561 /* for breakpoint or single step, print the current instr. */
562 if (bp || TRAP(regs) == 0xd00)
563 ppc_inst_dump(regs->nip, 1, 0);
564 printf("enter ? for help\n");
565 }
566
567 cmd = cmds(regs);
568
569 insert_bpts();
570 in_xmon = 0;
571#endif
572
Josh Boyercdd39042009-10-05 04:46:05 +0000573#ifdef CONFIG_BOOKE
574 if (regs->msr & MSR_DE) {
575 bp = at_breakpoint(regs->nip);
576 if (bp != NULL) {
577 regs->nip = (unsigned long) &bp->instr[0];
578 atomic_inc(&bp->ref_count);
579 }
580 }
581#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000582 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 bp = at_breakpoint(regs->nip);
584 if (bp != NULL) {
585 int stepped = emulate_step(regs, bp->instr[0]);
586 if (stepped == 0) {
587 regs->nip = (unsigned long) &bp->instr[0];
588 atomic_inc(&bp->ref_count);
589 } else if (stepped < 0) {
590 printf("Couldn't single-step %s instruction\n",
591 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
592 }
593 }
594 }
Josh Boyercdd39042009-10-05 04:46:05 +0000595#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 insert_cpu_bpts();
597
Anton Blancharda71d64b2014-08-05 14:55:00 +1000598 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100599 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000601 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602}
603
604int xmon(struct pt_regs *excp)
605{
606 struct pt_regs regs;
607
608 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000609 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 excp = &regs;
611 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200612
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 return xmon_core(excp, 0);
614}
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000615EXPORT_SYMBOL(xmon);
616
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000617irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000618{
619 unsigned long flags;
620 local_irq_save(flags);
621 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000622 xmon(get_irq_regs());
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000623 local_irq_restore(flags);
624 return IRQ_HANDLED;
625}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000627static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628{
629 struct bpt *bp;
630 unsigned long offset;
631
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000632 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 return 0;
634
635 /* Are we at the trap at bp->instr[1] for some bp? */
636 bp = in_breakpoint_table(regs->nip, &offset);
637 if (bp != NULL && offset == 4) {
638 regs->nip = bp->address + 4;
639 atomic_dec(&bp->ref_count);
640 return 1;
641 }
642
643 /* Are we at a breakpoint? */
644 bp = at_breakpoint(regs->nip);
645 if (!bp)
646 return 0;
647
648 xmon_core(regs, 0);
649
650 return 1;
651}
652
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000653static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654{
655 if (user_mode(regs))
656 return 0;
657 xmon_core(regs, 0);
658 return 1;
659}
660
Michael Neuling9422de32012-12-20 14:06:44 +0000661static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000663 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000665 if (dabr.enabled == 0)
666 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 xmon_core(regs, 0);
668 return 1;
669}
670
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000671static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000673 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000675 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 return 0;
677 xmon_core(regs, 0);
678 return 1;
679}
680
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000681static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
683#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000684 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 xmon_core(regs, 1);
686#endif
687 return 0;
688}
689
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000690static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691{
692 struct bpt *bp;
693 unsigned long offset;
694
695 if (in_xmon && catch_memory_errors)
696 handle_fault(regs); /* doesn't return */
697
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000698 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 bp = in_breakpoint_table(regs->nip, &offset);
700 if (bp != NULL) {
701 regs->nip = bp->address + offset;
702 atomic_dec(&bp->ref_count);
703 }
704 }
705
706 return 0;
707}
708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709static struct bpt *at_breakpoint(unsigned long pc)
710{
711 int i;
712 struct bpt *bp;
713
714 bp = bpts;
715 for (i = 0; i < NBPTS; ++i, ++bp)
716 if (bp->enabled && pc == bp->address)
717 return bp;
718 return NULL;
719}
720
721static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
722{
723 unsigned long off;
724
725 off = nip - (unsigned long) bpts;
726 if (off >= sizeof(bpts))
727 return NULL;
728 off %= sizeof(struct bpt);
729 if (off != offsetof(struct bpt, instr[0])
730 && off != offsetof(struct bpt, instr[1]))
731 return NULL;
732 *offp = off - offsetof(struct bpt, instr[0]);
733 return (struct bpt *) (nip - off);
734}
735
736static struct bpt *new_breakpoint(unsigned long a)
737{
738 struct bpt *bp;
739
740 a &= ~3UL;
741 bp = at_breakpoint(a);
742 if (bp)
743 return bp;
744
745 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
746 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
747 bp->address = a;
748 bp->instr[1] = bpinstr;
749 store_inst(&bp->instr[1]);
750 return bp;
751 }
752 }
753
754 printf("Sorry, no free breakpoints. Please clear one first.\n");
755 return NULL;
756}
757
758static void insert_bpts(void)
759{
760 int i;
761 struct bpt *bp;
762
763 bp = bpts;
764 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100765 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 continue;
767 if (mread(bp->address, &bp->instr[0], 4) != 4) {
768 printf("Couldn't read instruction at %lx, "
769 "disabling breakpoint there\n", bp->address);
770 bp->enabled = 0;
771 continue;
772 }
773 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
774 printf("Breakpoint at %lx is on an mtmsrd or rfid "
775 "instruction, disabling it\n", bp->address);
776 bp->enabled = 0;
777 continue;
778 }
779 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100780 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 continue;
782 if (mwrite(bp->address, &bpinstr, 4) != 4) {
783 printf("Couldn't write instruction at %lx, "
784 "disabling breakpoint there\n", bp->address);
785 bp->enabled &= ~BP_TRAP;
786 continue;
787 }
788 store_inst((void *)bp->address);
789 }
790}
791
792static void insert_cpu_bpts(void)
793{
Michael Neuling9422de32012-12-20 14:06:44 +0000794 struct arch_hw_breakpoint brk;
795
796 if (dabr.enabled) {
797 brk.address = dabr.address;
798 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
799 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400800 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000801 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530802
803 if (iabr)
804 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805}
806
807static void remove_bpts(void)
808{
809 int i;
810 struct bpt *bp;
811 unsigned instr;
812
813 bp = bpts;
814 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100815 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 continue;
817 if (mread(bp->address, &instr, 4) == 4
818 && instr == bpinstr
819 && mwrite(bp->address, &bp->instr, 4) != 4)
820 printf("Couldn't remove breakpoint at %lx\n",
821 bp->address);
822 else
823 store_inst((void *)bp->address);
824 }
825}
826
827static void remove_cpu_bpts(void)
828{
Michael Neuling9422de32012-12-20 14:06:44 +0000829 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530830 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831}
832
Sam bobroff958b7c82015-10-08 11:50:23 +1100833static void set_lpp_cmd(void)
834{
835 unsigned long lpp;
836
837 if (!scanhex(&lpp)) {
838 printf("Invalid number.\n");
839 lpp = 0;
840 }
841 xmon_set_pagination_lpp(lpp);
842}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843/* Command interpreting routine */
844static char *last_cmd;
845
846static int
847cmds(struct pt_regs *excp)
848{
849 int cmd = 0;
850
851 last_cmd = NULL;
852 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200853
854 if (!xmon_no_auto_backtrace) {
855 xmon_no_auto_backtrace = 1;
856 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
857 }
858
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 for(;;) {
860#ifdef CONFIG_SMP
861 printf("%x:", smp_processor_id());
862#endif /* CONFIG_SMP */
863 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 flush_input();
865 termch = 0;
866 cmd = skipbl();
867 if( cmd == '\n' ) {
868 if (last_cmd == NULL)
869 continue;
870 take_input(last_cmd);
871 last_cmd = NULL;
872 cmd = inchar();
873 }
874 switch (cmd) {
875 case 'm':
876 cmd = inchar();
877 switch (cmd) {
878 case 'm':
879 case 's':
880 case 'd':
881 memops(cmd);
882 break;
883 case 'l':
884 memlocate();
885 break;
886 case 'z':
887 memzcan();
888 break;
889 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700890 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 break;
892 default:
893 termch = cmd;
894 memex();
895 }
896 break;
897 case 'd':
898 dump();
899 break;
900 case 'l':
901 symbol_lookup();
902 break;
903 case 'r':
904 prregs(excp); /* print regs */
905 break;
906 case 'e':
907 excprint(excp);
908 break;
909 case 'S':
910 super_regs();
911 break;
912 case 't':
913 backtrace(excp);
914 break;
915 case 'f':
916 cacheflush();
917 break;
918 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200919 if (do_spu_cmd() == 0)
920 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 if (do_step(excp))
922 return cmd;
923 break;
924 case 'x':
925 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100926 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100928 printf(" <no input ...>\n");
929 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 return cmd;
931 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000932 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 break;
Sam bobroff958b7c82015-10-08 11:50:23 +1100934 case '#':
935 set_lpp_cmd();
936 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 case 'b':
938 bpt_cmds();
939 break;
940 case 'C':
941 csum();
942 break;
943 case 'c':
944 if (cpu_cmd())
945 return 0;
946 break;
947 case 'z':
948 bootcmds();
949 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000950 case 'p':
951 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000953#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 case 'u':
955 dump_segments();
956 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +1100957#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100958 case 'u':
959 dump_tlb_44x();
960 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000961#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000962 case 'u':
963 dump_tlb_book3e();
964 break;
965#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 default:
967 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000968 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 if (' ' < cmd && cmd <= '~')
970 putchar(cmd);
971 else
972 printf("\\x%x", cmd);
973 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +0000974 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 printf(" (type ? for help)\n");
976 break;
977 }
978 }
979}
980
Josh Boyercdd39042009-10-05 04:46:05 +0000981#ifdef CONFIG_BOOKE
982static int do_step(struct pt_regs *regs)
983{
984 regs->msr |= MSR_DE;
985 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
986 return 1;
987}
988#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989/*
990 * Step a single instruction.
991 * Some instructions we emulate, others we execute with MSR_SE set.
992 */
993static int do_step(struct pt_regs *regs)
994{
995 unsigned int instr;
996 int stepped;
997
998 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000999 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 if (mread(regs->nip, &instr, 4) == 4) {
1001 stepped = emulate_step(regs, instr);
1002 if (stepped < 0) {
1003 printf("Couldn't single-step %s instruction\n",
1004 (IS_RFID(instr)? "rfid": "mtmsrd"));
1005 return 0;
1006 }
1007 if (stepped > 0) {
1008 regs->trap = 0xd00 | (regs->trap & 1);
1009 printf("stepped to ");
1010 xmon_print_symbol(regs->nip, " ", "\n");
1011 ppc_inst_dump(regs->nip, 1, 0);
1012 return 0;
1013 }
1014 }
1015 }
1016 regs->msr |= MSR_SE;
1017 return 1;
1018}
Josh Boyercdd39042009-10-05 04:46:05 +00001019#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
1021static void bootcmds(void)
1022{
1023 int cmd;
1024
1025 cmd = inchar();
1026 if (cmd == 'r')
1027 ppc_md.restart(NULL);
1028 else if (cmd == 'h')
1029 ppc_md.halt();
1030 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001031 if (pm_power_off)
1032 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033}
1034
1035static int cpu_cmd(void)
1036{
1037#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001038 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
1041 if (!scanhex(&cpu)) {
1042 /* print cpus waiting or in xmon */
1043 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001044 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001045 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001046 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001047 if (cpu == last_cpu + 1) {
1048 last_cpu = cpu;
1049 } else {
1050 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001051 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001052 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001053 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 }
1056 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001057 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001058 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 printf("\n");
1060 return 0;
1061 }
1062 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001063 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 printf("cpu 0x%x isn't in xmon\n", cpu);
1065 return 0;
1066 }
1067 xmon_taken = 0;
1068 mb();
1069 xmon_owner = cpu;
1070 timeout = 10000000;
1071 while (!xmon_taken) {
1072 if (--timeout == 0) {
1073 if (test_and_set_bit(0, &xmon_taken))
1074 break;
1075 /* take control back */
1076 mb();
1077 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001078 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 return 0;
1080 }
1081 barrier();
1082 }
1083 return 1;
1084#else
1085 return 0;
1086#endif /* CONFIG_SMP */
1087}
1088
1089static unsigned short fcstab[256] = {
1090 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1091 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1092 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1093 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1094 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1095 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1096 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1097 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1098 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1099 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1100 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1101 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1102 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1103 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1104 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1105 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1106 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1107 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1108 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1109 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1110 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1111 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1112 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1113 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1114 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1115 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1116 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1117 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1118 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1119 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1120 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1121 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1122};
1123
1124#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1125
1126static void
1127csum(void)
1128{
1129 unsigned int i;
1130 unsigned short fcs;
1131 unsigned char v;
1132
1133 if (!scanhex(&adrs))
1134 return;
1135 if (!scanhex(&ncsum))
1136 return;
1137 fcs = 0xffff;
1138 for (i = 0; i < ncsum; ++i) {
1139 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001140 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 break;
1142 }
1143 fcs = FCS(fcs, v);
1144 }
1145 printf("%x\n", fcs);
1146}
1147
1148/*
1149 * Check if this is a suitable place to put a breakpoint.
1150 */
1151static long check_bp_loc(unsigned long addr)
1152{
1153 unsigned int instr;
1154
1155 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001156 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 printf("Breakpoints may only be placed at kernel addresses\n");
1158 return 0;
1159 }
1160 if (!mread(addr, &instr, sizeof(instr))) {
1161 printf("Can't read instruction at address %lx\n", addr);
1162 return 0;
1163 }
1164 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1165 printf("Breakpoints may not be placed on mtmsrd or rfid "
1166 "instructions\n");
1167 return 0;
1168 }
1169 return 1;
1170}
1171
Michael Ellermane3bc8042012-08-23 22:09:13 +00001172static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 "Breakpoint command usage:\n"
1174 "b show breakpoints\n"
1175 "b <addr> [cnt] set breakpoint at given instr addr\n"
1176 "bc clear all breakpoints\n"
1177 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301178 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 "bd <addr> [cnt] set hardware data breakpoint\n"
1180 "";
1181
1182static void
1183bpt_cmds(void)
1184{
1185 int cmd;
1186 unsigned long a;
1187 int mode, i;
1188 struct bpt *bp;
1189 const char badaddr[] = "Only kernel addresses are permitted "
1190 "for breakpoints\n";
1191
1192 cmd = inchar();
1193 switch (cmd) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001194#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 case 'd': /* bd - hardware data breakpoint */
1196 mode = 7;
1197 cmd = inchar();
1198 if (cmd == 'r')
1199 mode = 5;
1200 else if (cmd == 'w')
1201 mode = 6;
1202 else
1203 termch = cmd;
1204 dabr.address = 0;
1205 dabr.enabled = 0;
1206 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001207 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 printf(badaddr);
1209 break;
1210 }
Michael Neuling9422de32012-12-20 14:06:44 +00001211 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 dabr.enabled = mode | BP_DABR;
1213 }
1214 break;
1215
1216 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301217 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 printf("Hardware instruction breakpoint "
1219 "not supported on this cpu\n");
1220 break;
1221 }
1222 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001223 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 iabr = NULL;
1225 }
1226 if (!scanhex(&a))
1227 break;
1228 if (!check_bp_loc(a))
1229 break;
1230 bp = new_breakpoint(a);
1231 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001232 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 iabr = bp;
1234 }
1235 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001236#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
1238 case 'c':
1239 if (!scanhex(&a)) {
1240 /* clear all breakpoints */
1241 for (i = 0; i < NBPTS; ++i)
1242 bpts[i].enabled = 0;
1243 iabr = NULL;
1244 dabr.enabled = 0;
1245 printf("All breakpoints cleared\n");
1246 break;
1247 }
1248
1249 if (a <= NBPTS && a >= 1) {
1250 /* assume a breakpoint number */
1251 bp = &bpts[a-1]; /* bp nums are 1 based */
1252 } else {
1253 /* assume a breakpoint address */
1254 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001255 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001256 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 break;
1258 }
1259 }
1260
Michael Ellerman736256e2014-05-26 21:02:14 +10001261 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 xmon_print_symbol(bp->address, " ", ")\n");
1263 bp->enabled = 0;
1264 break;
1265
1266 default:
1267 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001268 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 if (cmd == '?') {
1270 printf(breakpoint_help_string);
1271 break;
1272 }
1273 termch = cmd;
1274 if (!scanhex(&a)) {
1275 /* print all breakpoints */
1276 printf(" type address\n");
1277 if (dabr.enabled) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001278 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 if (dabr.enabled & 1)
1280 printf("r");
1281 if (dabr.enabled & 2)
1282 printf("w");
1283 printf("]\n");
1284 }
1285 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1286 if (!bp->enabled)
1287 continue;
1288 printf("%2x %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001289 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 xmon_print_symbol(bp->address, " ", "\n");
1291 }
1292 break;
1293 }
1294
1295 if (!check_bp_loc(a))
1296 break;
1297 bp = new_breakpoint(a);
1298 if (bp != NULL)
1299 bp->enabled |= BP_TRAP;
1300 break;
1301 }
1302}
1303
1304/* Very cheap human name for vector lookup. */
1305static
1306const char *getvecname(unsigned long vec)
1307{
1308 char *ret;
1309
1310 switch (vec) {
1311 case 0x100: ret = "(System Reset)"; break;
1312 case 0x200: ret = "(Machine Check)"; break;
1313 case 0x300: ret = "(Data Access)"; break;
1314 case 0x380: ret = "(Data SLB Access)"; break;
1315 case 0x400: ret = "(Instruction Access)"; break;
1316 case 0x480: ret = "(Instruction SLB Access)"; break;
1317 case 0x500: ret = "(Hardware Interrupt)"; break;
1318 case 0x600: ret = "(Alignment)"; break;
1319 case 0x700: ret = "(Program Check)"; break;
1320 case 0x800: ret = "(FPU Unavailable)"; break;
1321 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001322 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1323 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 case 0xc00: ret = "(System Call)"; break;
1325 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001326 case 0xe40: ret = "(Emulation Assist)"; break;
1327 case 0xe60: ret = "(HMI)"; break;
1328 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 case 0xf00: ret = "(Performance Monitor)"; break;
1330 case 0xf20: ret = "(Altivec Unavailable)"; break;
1331 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001332 case 0x1500: ret = "(Denormalisation)"; break;
1333 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 default: ret = "";
1335 }
1336 return ret;
1337}
1338
1339static void get_function_bounds(unsigned long pc, unsigned long *startp,
1340 unsigned long *endp)
1341{
1342 unsigned long size, offset;
1343 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
1345 *startp = *endp = 0;
1346 if (pc == 0)
1347 return;
1348 if (setjmp(bus_error_jmp) == 0) {
1349 catch_memory_errors = 1;
1350 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001351 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 if (name != NULL) {
1353 *startp = pc - offset;
1354 *endp = pc - offset + size;
1355 }
1356 sync();
1357 }
1358 catch_memory_errors = 0;
1359}
1360
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001361#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1362#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1363
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364static void xmon_show_stack(unsigned long sp, unsigned long lr,
1365 unsigned long pc)
1366{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001367 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 unsigned long ip;
1369 unsigned long newsp;
1370 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 struct pt_regs regs;
1372
Michael Ellerman0104cd62012-10-09 04:20:36 +00001373 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 if (sp < PAGE_OFFSET) {
1375 if (sp != 0)
1376 printf("SP (%lx) is in userspace\n", sp);
1377 break;
1378 }
1379
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001380 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 || !mread(sp, &newsp, sizeof(unsigned long))) {
1382 printf("Couldn't read stack frame at %lx\n", sp);
1383 break;
1384 }
1385
1386 /*
1387 * For the first stack frame, try to work out if
1388 * LR and/or the saved LR value in the bottommost
1389 * stack frame are valid.
1390 */
1391 if ((pc | lr) != 0) {
1392 unsigned long fnstart, fnend;
1393 unsigned long nextip;
1394 int printip = 1;
1395
1396 get_function_bounds(pc, &fnstart, &fnend);
1397 nextip = 0;
1398 if (newsp > sp)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001399 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 sizeof(unsigned long));
1401 if (lr == ip) {
1402 if (lr < PAGE_OFFSET
1403 || (fnstart <= lr && lr < fnend))
1404 printip = 0;
1405 } else if (lr == nextip) {
1406 printip = 0;
1407 } else if (lr >= PAGE_OFFSET
1408 && !(fnstart <= lr && lr < fnend)) {
1409 printf("[link register ] ");
1410 xmon_print_symbol(lr, " ", "\n");
1411 }
1412 if (printip) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001413 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 xmon_print_symbol(ip, " ", " (unreliable)\n");
1415 }
1416 pc = lr = 0;
1417
1418 } else {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001419 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 xmon_print_symbol(ip, " ", "\n");
1421 }
1422
1423 /* Look for "regshere" marker to see if this is
1424 an exception frame. */
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001425 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001426 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001427 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 != sizeof(regs)) {
1429 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001430 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 break;
1432 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001433 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 getvecname(TRAP(&regs)));
1435 pc = regs.nip;
1436 lr = regs.link;
1437 xmon_print_symbol(pc, " ", "\n");
1438 }
1439
1440 if (newsp == 0)
1441 break;
1442
1443 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445}
1446
1447static void backtrace(struct pt_regs *excp)
1448{
1449 unsigned long sp;
1450
1451 if (scanhex(&sp))
1452 xmon_show_stack(sp, 0, 0);
1453 else
1454 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1455 scannl();
1456}
1457
1458static void print_bug_trap(struct pt_regs *regs)
1459{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001460#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001461 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 unsigned long addr;
1463
1464 if (regs->msr & MSR_PR)
1465 return; /* not in kernel */
1466 addr = regs->nip; /* address of trap instruction */
1467 if (addr < PAGE_OFFSET)
1468 return;
1469 bug = find_bug(regs->nip);
1470 if (bug == NULL)
1471 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001472 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 return;
1474
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001475#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001476 printf("kernel BUG at %s:%u!\n",
1477 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001478#else
1479 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1480#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001481#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482}
1483
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001484static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485{
1486 unsigned long trap;
1487
1488#ifdef CONFIG_SMP
1489 printf("cpu 0x%x: ", smp_processor_id());
1490#endif /* CONFIG_SMP */
1491
1492 trap = TRAP(fp);
1493 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1494 printf(" pc: ");
1495 xmon_print_symbol(fp->nip, ": ", "\n");
1496
1497 printf(" lr: ", fp->link);
1498 xmon_print_symbol(fp->link, ": ", "\n");
1499
1500 printf(" sp: %lx\n", fp->gpr[1]);
1501 printf(" msr: %lx\n", fp->msr);
1502
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001503 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 printf(" dar: %lx\n", fp->dar);
1505 if (trap != 0x380)
1506 printf(" dsisr: %lx\n", fp->dsisr);
1507 }
1508
1509 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001510#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001511 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1512 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001513#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 if (current) {
1515 printf(" pid = %ld, comm = %s\n",
1516 current->pid, current->comm);
1517 }
1518
1519 if (trap == 0x700)
1520 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001521
1522 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523}
1524
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001525static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001527 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 unsigned long base;
1529 struct pt_regs regs;
1530
1531 if (scanhex(&base)) {
1532 if (setjmp(bus_error_jmp) == 0) {
1533 catch_memory_errors = 1;
1534 sync();
1535 regs = *(struct pt_regs *)base;
1536 sync();
1537 __delay(200);
1538 } else {
1539 catch_memory_errors = 0;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001540 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 base);
1542 return;
1543 }
1544 catch_memory_errors = 0;
1545 fp = &regs;
1546 }
1547
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001548#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 if (FULL_REGS(fp)) {
1550 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001551 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1553 } else {
1554 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001555 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1557 }
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001558#else
1559 for (n = 0; n < 32; ++n) {
1560 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1561 (n & 3) == 3? "\n": " ");
1562 if (n == 12 && !FULL_REGS(fp)) {
1563 printf("\n");
1564 break;
1565 }
1566 }
1567#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 printf("pc = ");
1569 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001570 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1571 printf("cfar= ");
1572 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 printf("lr = ");
1575 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001576 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1577 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001579 trap = TRAP(fp);
1580 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1581 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582}
1583
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001584static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585{
1586 int cmd;
1587 unsigned long nflush;
1588
1589 cmd = inchar();
1590 if (cmd != 'i')
1591 termch = cmd;
1592 scanhex((void *)&adrs);
1593 if (termch != '\n')
1594 termch = 0;
1595 nflush = 1;
1596 scanhex(&nflush);
1597 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1598 if (setjmp(bus_error_jmp) == 0) {
1599 catch_memory_errors = 1;
1600 sync();
1601
1602 if (cmd != 'i') {
1603 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1604 cflush((void *) adrs);
1605 } else {
1606 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1607 cinval((void *) adrs);
1608 }
1609 sync();
1610 /* wait a little while to see if we get a machine check */
1611 __delay(200);
1612 }
1613 catch_memory_errors = 0;
1614}
1615
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001616static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617read_spr(int n)
1618{
1619 unsigned int instrs[2];
1620 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001622#ifdef CONFIG_PPC64
1623 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 opd[0] = (unsigned long)instrs;
1626 opd[1] = 0;
1627 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001628 code = (unsigned long (*)(void)) opd;
1629#else
1630 code = (unsigned long (*)(void)) instrs;
1631#endif
1632
1633 /* mfspr r3,n; blr */
1634 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1635 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 store_inst(instrs);
1637 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638
1639 if (setjmp(bus_error_jmp) == 0) {
1640 catch_memory_errors = 1;
1641 sync();
1642
1643 ret = code();
1644
1645 sync();
1646 /* wait a little while to see if we get a machine check */
1647 __delay(200);
1648 n = size;
1649 }
1650
1651 return ret;
1652}
1653
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001654static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655write_spr(int n, unsigned long val)
1656{
1657 unsigned int instrs[2];
1658 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001659#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 unsigned long opd[3];
1661
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 opd[0] = (unsigned long)instrs;
1663 opd[1] = 0;
1664 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001665 code = (unsigned long (*)(unsigned long)) opd;
1666#else
1667 code = (unsigned long (*)(unsigned long)) instrs;
1668#endif
1669
1670 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1671 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 store_inst(instrs);
1673 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
1675 if (setjmp(bus_error_jmp) == 0) {
1676 catch_memory_errors = 1;
1677 sync();
1678
1679 code(val);
1680
1681 sync();
1682 /* wait a little while to see if we get a machine check */
1683 __delay(200);
1684 n = size;
1685 }
1686}
1687
1688static unsigned long regno;
1689extern char exc_prolog;
1690extern char dec_exc;
1691
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001692static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693{
1694 int cmd;
1695 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 cmd = skipbl();
1698 if (cmd == '\n') {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001699 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 asm("mr %0,1" : "=r" (sp) :);
1701 asm("mr %0,2" : "=r" (toc) :);
1702
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001703 printf("msr = "REG" sprg0= "REG"\n",
1704 mfmsr(), mfspr(SPRN_SPRG0));
1705 printf("pvr = "REG" sprg1= "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001706 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001707 printf("dec = "REG" sprg2= "REG"\n",
1708 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1709 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1710 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711
1712 return;
1713 }
1714
1715 scanhex(&regno);
1716 switch (cmd) {
1717 case 'w':
1718 val = read_spr(regno);
1719 scanhex(&val);
1720 write_spr(regno, val);
1721 /* fall through */
1722 case 'r':
1723 printf("spr %lx = %lx\n", regno, read_spr(regno));
1724 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 }
1726 scannl();
1727}
1728
1729/*
1730 * Stuff for reading and writing memory safely
1731 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001732static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733mread(unsigned long adrs, void *buf, int size)
1734{
1735 volatile int n;
1736 char *p, *q;
1737
1738 n = 0;
1739 if (setjmp(bus_error_jmp) == 0) {
1740 catch_memory_errors = 1;
1741 sync();
1742 p = (char *)adrs;
1743 q = (char *)buf;
1744 switch (size) {
1745 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001746 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 break;
1748 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001749 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 break;
1751 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001752 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 break;
1754 default:
1755 for( ; n < size; ++n) {
1756 *q++ = *p++;
1757 sync();
1758 }
1759 }
1760 sync();
1761 /* wait a little while to see if we get a machine check */
1762 __delay(200);
1763 n = size;
1764 }
1765 catch_memory_errors = 0;
1766 return n;
1767}
1768
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001769static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770mwrite(unsigned long adrs, void *buf, int size)
1771{
1772 volatile int n;
1773 char *p, *q;
1774
1775 n = 0;
1776 if (setjmp(bus_error_jmp) == 0) {
1777 catch_memory_errors = 1;
1778 sync();
1779 p = (char *) adrs;
1780 q = (char *) buf;
1781 switch (size) {
1782 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001783 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 break;
1785 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001786 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 break;
1788 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001789 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 break;
1791 default:
1792 for ( ; n < size; ++n) {
1793 *p++ = *q++;
1794 sync();
1795 }
1796 }
1797 sync();
1798 /* wait a little while to see if we get a machine check */
1799 __delay(200);
1800 n = size;
1801 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10001802 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 }
1804 catch_memory_errors = 0;
1805 return n;
1806}
1807
1808static int fault_type;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001809static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810static char *fault_chars[] = { "--", "**", "##" };
1811
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001812static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001814 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 switch (TRAP(regs)) {
1816 case 0x200:
1817 fault_type = 0;
1818 break;
1819 case 0x300:
1820 case 0x380:
1821 fault_type = 1;
1822 break;
1823 default:
1824 fault_type = 2;
1825 }
1826
1827 longjmp(bus_error_jmp, 1);
1828
1829 return 0;
1830}
1831
1832#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1833
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001834static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835byterev(unsigned char *val, int size)
1836{
1837 int t;
1838
1839 switch (size) {
1840 case 2:
1841 SWAP(val[0], val[1], t);
1842 break;
1843 case 4:
1844 SWAP(val[0], val[3], t);
1845 SWAP(val[1], val[2], t);
1846 break;
1847 case 8: /* is there really any use for this? */
1848 SWAP(val[0], val[7], t);
1849 SWAP(val[1], val[6], t);
1850 SWAP(val[2], val[5], t);
1851 SWAP(val[3], val[4], t);
1852 break;
1853 }
1854}
1855
1856static int brev;
1857static int mnoread;
1858
Michael Ellermane3bc8042012-08-23 22:09:13 +00001859static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 "Memory examine command usage:\n"
1861 "m [addr] [flags] examine/change memory\n"
1862 " addr is optional. will start where left off.\n"
1863 " flags may include chars from this set:\n"
1864 " b modify by bytes (default)\n"
1865 " w modify by words (2 byte)\n"
1866 " l modify by longs (4 byte)\n"
1867 " d modify by doubleword (8 byte)\n"
1868 " r toggle reverse byte order mode\n"
1869 " n do not read memory (for i/o spaces)\n"
1870 " . ok to read (default)\n"
1871 "NOTE: flags are saved as defaults\n"
1872 "";
1873
Michael Ellermane3bc8042012-08-23 22:09:13 +00001874static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 "Memory examine subcommands:\n"
1876 " hexval write this val to current location\n"
1877 " 'string' write chars from string to this location\n"
1878 " ' increment address\n"
1879 " ^ decrement address\n"
1880 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1881 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1882 " ` clear no-read flag\n"
1883 " ; stay at this addr\n"
1884 " v change to byte mode\n"
1885 " w change to word (2 byte) mode\n"
1886 " l change to long (4 byte) mode\n"
1887 " u change to doubleword (8 byte) mode\n"
1888 " m addr change current addr\n"
1889 " n toggle no-read flag\n"
1890 " r toggle byte reverse flag\n"
1891 " < count back up count bytes\n"
1892 " > count skip forward count bytes\n"
1893 " x exit this mode\n"
1894 "";
1895
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001896static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897memex(void)
1898{
1899 int cmd, inc, i, nslash;
1900 unsigned long n;
1901 unsigned char val[16];
1902
1903 scanhex((void *)&adrs);
1904 cmd = skipbl();
1905 if (cmd == '?') {
1906 printf(memex_help_string);
1907 return;
1908 } else {
1909 termch = cmd;
1910 }
1911 last_cmd = "m\n";
1912 while ((cmd = skipbl()) != '\n') {
1913 switch( cmd ){
1914 case 'b': size = 1; break;
1915 case 'w': size = 2; break;
1916 case 'l': size = 4; break;
1917 case 'd': size = 8; break;
1918 case 'r': brev = !brev; break;
1919 case 'n': mnoread = 1; break;
1920 case '.': mnoread = 0; break;
1921 }
1922 }
1923 if( size <= 0 )
1924 size = 1;
1925 else if( size > 8 )
1926 size = 8;
1927 for(;;){
1928 if (!mnoread)
1929 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001930 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 if (!mnoread) {
1932 if (brev)
1933 byterev(val, size);
1934 putchar(' ');
1935 for (i = 0; i < n; ++i)
1936 printf("%.2x", val[i]);
1937 for (; i < size; ++i)
1938 printf("%s", fault_chars[fault_type]);
1939 }
1940 putchar(' ');
1941 inc = size;
1942 nslash = 0;
1943 for(;;){
1944 if( scanhex(&n) ){
1945 for (i = 0; i < size; ++i)
1946 val[i] = n >> (i * 8);
1947 if (!brev)
1948 byterev(val, size);
1949 mwrite(adrs, val, size);
1950 inc = size;
1951 }
1952 cmd = skipbl();
1953 if (cmd == '\n')
1954 break;
1955 inc = 0;
1956 switch (cmd) {
1957 case '\'':
1958 for(;;){
1959 n = inchar();
1960 if( n == '\\' )
1961 n = bsesc();
1962 else if( n == '\'' )
1963 break;
1964 for (i = 0; i < size; ++i)
1965 val[i] = n >> (i * 8);
1966 if (!brev)
1967 byterev(val, size);
1968 mwrite(adrs, val, size);
1969 adrs += size;
1970 }
1971 adrs -= size;
1972 inc = size;
1973 break;
1974 case ',':
1975 adrs += size;
1976 break;
1977 case '.':
1978 mnoread = 0;
1979 break;
1980 case ';':
1981 break;
1982 case 'x':
1983 case EOF:
1984 scannl();
1985 return;
1986 case 'b':
1987 case 'v':
1988 size = 1;
1989 break;
1990 case 'w':
1991 size = 2;
1992 break;
1993 case 'l':
1994 size = 4;
1995 break;
1996 case 'u':
1997 size = 8;
1998 break;
1999 case '^':
2000 adrs -= size;
2001 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 case '/':
2003 if (nslash > 0)
2004 adrs -= 1 << nslash;
2005 else
2006 nslash = 0;
2007 nslash += 4;
2008 adrs += 1 << nslash;
2009 break;
2010 case '\\':
2011 if (nslash < 0)
2012 adrs += 1 << -nslash;
2013 else
2014 nslash = 0;
2015 nslash -= 4;
2016 adrs -= 1 << -nslash;
2017 break;
2018 case 'm':
2019 scanhex((void *)&adrs);
2020 break;
2021 case 'n':
2022 mnoread = 1;
2023 break;
2024 case 'r':
2025 brev = !brev;
2026 break;
2027 case '<':
2028 n = size;
2029 scanhex(&n);
2030 adrs -= n;
2031 break;
2032 case '>':
2033 n = size;
2034 scanhex(&n);
2035 adrs += n;
2036 break;
2037 case '?':
2038 printf(memex_subcmd_help_string);
2039 break;
2040 }
2041 }
2042 adrs += inc;
2043 }
2044}
2045
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002046static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047bsesc(void)
2048{
2049 int c;
2050
2051 c = inchar();
2052 switch( c ){
2053 case 'n': c = '\n'; break;
2054 case 'r': c = '\r'; break;
2055 case 'b': c = '\b'; break;
2056 case 't': c = '\t'; break;
2057 }
2058 return c;
2059}
2060
Olaf Hering7e5b5932006-03-08 20:40:28 +01002061static void xmon_rawdump (unsigned long adrs, long ndump)
2062{
2063 long n, m, r, nr;
2064 unsigned char temp[16];
2065
2066 for (n = ndump; n > 0;) {
2067 r = n < 16? n: 16;
2068 nr = mread(adrs, temp, r);
2069 adrs += nr;
2070 for (m = 0; m < r; ++m) {
2071 if (m < nr)
2072 printf("%.2x", temp[m]);
2073 else
2074 printf("%s", fault_chars[fault_type]);
2075 }
2076 n -= r;
2077 if (nr < r)
2078 break;
2079 }
2080 printf("\n");
2081}
2082
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002083#ifdef CONFIG_PPC64
2084static void dump_one_paca(int cpu)
2085{
2086 struct paca_struct *p;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002087#ifdef CONFIG_PPC_STD_MMU_64
2088 int i = 0;
2089#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002090
2091 if (setjmp(bus_error_jmp) != 0) {
2092 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2093 return;
2094 }
2095
2096 catch_memory_errors = 1;
2097 sync();
2098
2099 p = &paca[cpu];
2100
2101 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2102
Michael Ellermanad987fc2015-10-14 16:58:36 +11002103 printf(" %-*s = %s\n", 20, "possible", cpu_possible(cpu) ? "yes" : "no");
2104 printf(" %-*s = %s\n", 20, "present", cpu_present(cpu) ? "yes" : "no");
2105 printf(" %-*s = %s\n", 20, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002106
2107#define DUMP(paca, name, format) \
Michael Ellermanad987fc2015-10-14 16:58:36 +11002108 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 20, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002109 offsetof(struct paca_struct, name));
2110
2111 DUMP(p, lock_token, "x");
2112 DUMP(p, paca_index, "x");
2113 DUMP(p, kernel_toc, "lx");
2114 DUMP(p, kernelbase, "lx");
2115 DUMP(p, kernel_msr, "lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002116 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302117#ifdef CONFIG_PPC_BOOK3S_64
2118 DUMP(p, mc_emergency_sp, "p");
2119 DUMP(p, in_mce, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002120 DUMP(p, hmi_event_available, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302121#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002122 DUMP(p, data_offset, "lx");
2123 DUMP(p, hw_cpu_id, "x");
2124 DUMP(p, cpu_start, "x");
2125 DUMP(p, kexec_state, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002126#ifdef CONFIG_PPC_STD_MMU_64
2127 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2128 u64 esid, vsid;
2129
2130 if (!p->slb_shadow_ptr)
2131 continue;
2132
2133 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2134 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
2135
2136 if (esid || vsid) {
2137 printf(" slb_shadow[%d]: = 0x%016lx 0x%016lx\n",
2138 i, esid, vsid);
2139 }
2140 }
2141 DUMP(p, vmalloc_sllp, "x");
2142 DUMP(p, slb_cache_ptr, "x");
2143 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2144 printf(" slb_cache[%d]: = 0x%016lx\n", i, p->slb_cache[i]);
2145#endif
2146 DUMP(p, dscr_default, "llx");
2147#ifdef CONFIG_PPC_BOOK3E
2148 DUMP(p, pgd, "p");
2149 DUMP(p, kernel_pgd, "p");
2150 DUMP(p, tcd_ptr, "p");
2151 DUMP(p, mc_kstack, "p");
2152 DUMP(p, crit_kstack, "p");
2153 DUMP(p, dbg_kstack, "p");
2154#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002155 DUMP(p, __current, "p");
2156 DUMP(p, kstack, "lx");
2157 DUMP(p, stab_rr, "lx");
2158 DUMP(p, saved_r1, "lx");
2159 DUMP(p, trap_save, "x");
2160 DUMP(p, soft_enabled, "x");
2161 DUMP(p, irq_happened, "x");
2162 DUMP(p, io_sync, "x");
2163 DUMP(p, irq_work_pending, "x");
2164 DUMP(p, nap_state_lost, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002165 DUMP(p, sprg_vdso, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002166
Michael Ellermanad987fc2015-10-14 16:58:36 +11002167#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
2168 DUMP(p, tm_scratch, "llx");
2169#endif
2170
2171#ifdef CONFIG_PPC_POWERNV
2172 DUMP(p, core_idle_state_ptr, "p");
2173 DUMP(p, thread_idle_state, "x");
2174 DUMP(p, thread_mask, "x");
2175 DUMP(p, subcore_sibling_mask, "x");
2176#endif
2177
2178 DUMP(p, user_time, "llx");
2179 DUMP(p, system_time, "llx");
2180 DUMP(p, user_time_scaled, "llx");
2181 DUMP(p, starttime, "llx");
2182 DUMP(p, starttime_user, "llx");
2183 DUMP(p, startspurr, "llx");
2184 DUMP(p, utime_sspurr, "llx");
2185 DUMP(p, stolen_time, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002186#undef DUMP
2187
2188 catch_memory_errors = 0;
2189 sync();
2190}
2191
2192static void dump_all_pacas(void)
2193{
2194 int cpu;
2195
2196 if (num_possible_cpus() == 0) {
2197 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2198 return;
2199 }
2200
2201 for_each_possible_cpu(cpu)
2202 dump_one_paca(cpu);
2203}
2204
2205static void dump_pacas(void)
2206{
2207 unsigned long num;
2208 int c;
2209
2210 c = inchar();
2211 if (c == 'a') {
2212 dump_all_pacas();
2213 return;
2214 }
2215
2216 termch = c; /* Put c back, it wasn't 'a' */
2217
2218 if (scanhex(&num))
2219 dump_one_paca(num);
2220 else
2221 dump_one_paca(xmon_owner);
2222}
2223#endif
2224
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002225static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226dump(void)
2227{
2228 int c;
2229
2230 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002231
2232#ifdef CONFIG_PPC64
2233 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002234 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002235 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002236 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002237 return;
2238 }
2239#endif
2240
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2242 termch = c;
2243 scanhex((void *)&adrs);
2244 if (termch != '\n')
2245 termch = 0;
2246 if (c == 'i') {
2247 scanhex(&nidump);
2248 if (nidump == 0)
2249 nidump = 16;
2250 else if (nidump > MAX_DUMP)
2251 nidump = MAX_DUMP;
2252 adrs += ppc_inst_dump(adrs, nidump, 1);
2253 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002254 } else if (c == 'l') {
2255 dump_log_buf();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002256 } else if (c == 'r') {
2257 scanhex(&ndump);
2258 if (ndump == 0)
2259 ndump = 64;
2260 xmon_rawdump(adrs, ndump);
2261 adrs += ndump;
2262 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 } else {
2264 scanhex(&ndump);
2265 if (ndump == 0)
2266 ndump = 64;
2267 else if (ndump > MAX_DUMP)
2268 ndump = MAX_DUMP;
2269 prdump(adrs, ndump);
2270 adrs += ndump;
2271 last_cmd = "d\n";
2272 }
2273}
2274
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002275static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276prdump(unsigned long adrs, long ndump)
2277{
2278 long n, m, c, r, nr;
2279 unsigned char temp[16];
2280
2281 for (n = ndump; n > 0;) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002282 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 putchar(' ');
2284 r = n < 16? n: 16;
2285 nr = mread(adrs, temp, r);
2286 adrs += nr;
2287 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002288 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002289 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 if (m < nr)
2291 printf("%.2x", temp[m]);
2292 else
2293 printf("%s", fault_chars[fault_type]);
2294 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002295 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002296 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002297 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 printf(" |");
2301 for (m = 0; m < r; ++m) {
2302 if (m < nr) {
2303 c = temp[m];
2304 putchar(' ' <= c && c <= '~'? c: '.');
2305 } else
2306 putchar(' ');
2307 }
2308 n -= r;
2309 for (; m < 16; ++m)
2310 putchar(' ');
2311 printf("|\n");
2312 if (nr < r)
2313 break;
2314 }
2315}
2316
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002317typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2318
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002319static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002320generic_inst_dump(unsigned long adr, long count, int praddr,
2321 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322{
2323 int nr, dotted;
2324 unsigned long first_adr;
2325 unsigned long inst, last_inst = 0;
2326 unsigned char val[4];
2327
2328 dotted = 0;
2329 for (first_adr = adr; count > 0; --count, adr += 4) {
2330 nr = mread(adr, val, 4);
2331 if (nr == 0) {
2332 if (praddr) {
2333 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002334 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 }
2336 break;
2337 }
2338 inst = GETWORD(val);
2339 if (adr > first_adr && inst == last_inst) {
2340 if (!dotted) {
2341 printf(" ...\n");
2342 dotted = 1;
2343 }
2344 continue;
2345 }
2346 dotted = 0;
2347 last_inst = inst;
2348 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002349 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002351 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 printf("\n");
2353 }
2354 return adr - first_adr;
2355}
2356
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002357static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002358ppc_inst_dump(unsigned long adr, long count, int praddr)
2359{
2360 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2361}
2362
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363void
2364print_address(unsigned long addr)
2365{
2366 xmon_print_symbol(addr, "\t# ", "");
2367}
2368
Vinay Sridharf312deb2009-05-14 23:13:07 +00002369void
2370dump_log_buf(void)
2371{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002372 struct kmsg_dumper dumper = { .active = 1 };
2373 unsigned char buf[128];
2374 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002375
Michael Ellermane3bc8042012-08-23 22:09:13 +00002376 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002377 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002378 return;
2379 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002380
Michael Ellermane3bc8042012-08-23 22:09:13 +00002381 catch_memory_errors = 1;
2382 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002383
Michael Ellermanca5dd392012-08-23 22:09:12 +00002384 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002385 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002386 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2387 buf[len] = '\0';
2388 printf("%s", buf);
2389 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002390 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002391
Michael Ellermane3bc8042012-08-23 22:09:13 +00002392 sync();
2393 /* wait a little while to see if we get a machine check */
2394 __delay(200);
2395 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002396}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
2398/*
2399 * Memory operations - move, set, print differences
2400 */
2401static unsigned long mdest; /* destination address */
2402static unsigned long msrc; /* source address */
2403static unsigned long mval; /* byte value to set memory to */
2404static unsigned long mcount; /* # bytes to affect */
2405static unsigned long mdiffs; /* max # differences to print */
2406
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002407static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408memops(int cmd)
2409{
2410 scanhex((void *)&mdest);
2411 if( termch != '\n' )
2412 termch = 0;
2413 scanhex((void *)(cmd == 's'? &mval: &msrc));
2414 if( termch != '\n' )
2415 termch = 0;
2416 scanhex((void *)&mcount);
2417 switch( cmd ){
2418 case 'm':
2419 memmove((void *)mdest, (void *)msrc, mcount);
2420 break;
2421 case 's':
2422 memset((void *)mdest, mval, mcount);
2423 break;
2424 case 'd':
2425 if( termch != '\n' )
2426 termch = 0;
2427 scanhex((void *)&mdiffs);
2428 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2429 break;
2430 }
2431}
2432
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002433static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2435{
2436 unsigned n, prt;
2437
2438 prt = 0;
2439 for( n = nb; n > 0; --n )
2440 if( *p1++ != *p2++ )
2441 if( ++prt <= maxpr )
2442 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2443 p1[-1], p2 - 1, p2[-1]);
2444 if( prt > maxpr )
2445 printf("Total of %d differences\n", prt);
2446}
2447
2448static unsigned mend;
2449static unsigned mask;
2450
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002451static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452memlocate(void)
2453{
2454 unsigned a, n;
2455 unsigned char val[4];
2456
2457 last_cmd = "ml";
2458 scanhex((void *)&mdest);
2459 if (termch != '\n') {
2460 termch = 0;
2461 scanhex((void *)&mend);
2462 if (termch != '\n') {
2463 termch = 0;
2464 scanhex((void *)&mval);
2465 mask = ~0;
2466 if (termch != '\n') termch = 0;
2467 scanhex((void *)&mask);
2468 }
2469 }
2470 n = 0;
2471 for (a = mdest; a < mend; a += 4) {
2472 if (mread(a, val, 4) == 4
2473 && ((GETWORD(val) ^ mval) & mask) == 0) {
2474 printf("%.16x: %.16x\n", a, GETWORD(val));
2475 if (++n >= 10)
2476 break;
2477 }
2478 }
2479}
2480
2481static unsigned long mskip = 0x1000;
2482static unsigned long mlim = 0xffffffff;
2483
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002484static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485memzcan(void)
2486{
2487 unsigned char v;
2488 unsigned a;
2489 int ok, ook;
2490
2491 scanhex(&mdest);
2492 if (termch != '\n') termch = 0;
2493 scanhex(&mskip);
2494 if (termch != '\n') termch = 0;
2495 scanhex(&mlim);
2496 ook = 0;
2497 for (a = mdest; a < mlim; a += mskip) {
2498 ok = mread(a, &v, 1);
2499 if (ok && !ook) {
2500 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 } else if (!ok && ook)
2502 printf("%.8x\n", a - mskip);
2503 ook = ok;
2504 if (a + mskip < a)
2505 break;
2506 }
2507 if (ook)
2508 printf("%.8x\n", a - mskip);
2509}
2510
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002511static void proccall(void)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002512{
2513 unsigned long args[8];
2514 unsigned long ret;
2515 int i;
2516 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2517 unsigned long, unsigned long, unsigned long,
2518 unsigned long, unsigned long, unsigned long);
2519 callfunc_t func;
2520
2521 if (!scanhex(&adrs))
2522 return;
2523 if (termch != '\n')
2524 termch = 0;
2525 for (i = 0; i < 8; ++i)
2526 args[i] = 0;
2527 for (i = 0; i < 8; ++i) {
2528 if (!scanhex(&args[i]) || termch == '\n')
2529 break;
2530 termch = 0;
2531 }
2532 func = (callfunc_t) adrs;
2533 ret = 0;
2534 if (setjmp(bus_error_jmp) == 0) {
2535 catch_memory_errors = 1;
2536 sync();
2537 ret = func(args[0], args[1], args[2], args[3],
2538 args[4], args[5], args[6], args[7]);
2539 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10002540 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002541 } else {
2542 printf("*** %x exception occurred\n", fault_except);
2543 }
2544 catch_memory_errors = 0;
2545}
2546
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547/* Input scanning routines */
2548int
2549skipbl(void)
2550{
2551 int c;
2552
2553 if( termch != 0 ){
2554 c = termch;
2555 termch = 0;
2556 } else
2557 c = inchar();
2558 while( c == ' ' || c == '\t' )
2559 c = inchar();
2560 return c;
2561}
2562
2563#define N_PTREGS 44
2564static char *regnames[N_PTREGS] = {
2565 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2566 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2567 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2568 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002569 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2570#ifdef CONFIG_PPC64
2571 "softe",
2572#else
2573 "mq",
2574#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 "trap", "dar", "dsisr", "res"
2576};
2577
2578int
2579scanhex(unsigned long *vp)
2580{
2581 int c, d;
2582 unsigned long v;
2583
2584 c = skipbl();
2585 if (c == '%') {
2586 /* parse register name */
2587 char regname[8];
2588 int i;
2589
2590 for (i = 0; i < sizeof(regname) - 1; ++i) {
2591 c = inchar();
2592 if (!isalnum(c)) {
2593 termch = c;
2594 break;
2595 }
2596 regname[i] = c;
2597 }
2598 regname[i] = 0;
2599 for (i = 0; i < N_PTREGS; ++i) {
2600 if (strcmp(regnames[i], regname) == 0) {
2601 if (xmon_regs == NULL) {
2602 printf("regs not available\n");
2603 return 0;
2604 }
2605 *vp = ((unsigned long *)xmon_regs)[i];
2606 return 1;
2607 }
2608 }
2609 printf("invalid register name '%%%s'\n", regname);
2610 return 0;
2611 }
2612
2613 /* skip leading "0x" if any */
2614
2615 if (c == '0') {
2616 c = inchar();
2617 if (c == 'x') {
2618 c = inchar();
2619 } else {
2620 d = hexdigit(c);
2621 if (d == EOF) {
2622 termch = c;
2623 *vp = 0;
2624 return 1;
2625 }
2626 }
2627 } else if (c == '$') {
2628 int i;
2629 for (i=0; i<63; i++) {
2630 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02002631 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 termch = c;
2633 break;
2634 }
2635 tmpstr[i] = c;
2636 }
2637 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002638 *vp = 0;
2639 if (setjmp(bus_error_jmp) == 0) {
2640 catch_memory_errors = 1;
2641 sync();
2642 *vp = kallsyms_lookup_name(tmpstr);
2643 sync();
2644 }
2645 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 if (!(*vp)) {
2647 printf("unknown symbol '%s'\n", tmpstr);
2648 return 0;
2649 }
2650 return 1;
2651 }
2652
2653 d = hexdigit(c);
2654 if (d == EOF) {
2655 termch = c;
2656 return 0;
2657 }
2658 v = 0;
2659 do {
2660 v = (v << 4) + d;
2661 c = inchar();
2662 d = hexdigit(c);
2663 } while (d != EOF);
2664 termch = c;
2665 *vp = v;
2666 return 1;
2667}
2668
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002669static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670scannl(void)
2671{
2672 int c;
2673
2674 c = termch;
2675 termch = 0;
2676 while( c != '\n' )
2677 c = inchar();
2678}
2679
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002680static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681{
2682 if( '0' <= c && c <= '9' )
2683 return c - '0';
2684 if( 'A' <= c && c <= 'F' )
2685 return c - ('A' - 10);
2686 if( 'a' <= c && c <= 'f' )
2687 return c - ('a' - 10);
2688 return EOF;
2689}
2690
2691void
2692getstring(char *s, int size)
2693{
2694 int c;
2695
2696 c = skipbl();
2697 do {
2698 if( size > 1 ){
2699 *s++ = c;
2700 --size;
2701 }
2702 c = inchar();
2703 } while( c != ' ' && c != '\t' && c != '\n' );
2704 termch = c;
2705 *s = 0;
2706}
2707
2708static char line[256];
2709static char *lineptr;
2710
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002711static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712flush_input(void)
2713{
2714 lineptr = NULL;
2715}
2716
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002717static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718inchar(void)
2719{
2720 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002721 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 lineptr = NULL;
2723 return EOF;
2724 }
2725 lineptr = line;
2726 }
2727 return *lineptr++;
2728}
2729
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002730static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731take_input(char *str)
2732{
2733 lineptr = str;
2734}
2735
2736
2737static void
2738symbol_lookup(void)
2739{
2740 int type = inchar();
2741 unsigned long addr;
2742 static char tmp[64];
2743
2744 switch (type) {
2745 case 'a':
2746 if (scanhex(&addr))
2747 xmon_print_symbol(addr, ": ", "\n");
2748 termch = 0;
2749 break;
2750 case 's':
2751 getstring(tmp, 64);
2752 if (setjmp(bus_error_jmp) == 0) {
2753 catch_memory_errors = 1;
2754 sync();
2755 addr = kallsyms_lookup_name(tmp);
2756 if (addr)
2757 printf("%s: %lx\n", tmp, addr);
2758 else
2759 printf("Symbol '%s' not found.\n", tmp);
2760 sync();
2761 }
2762 catch_memory_errors = 0;
2763 termch = 0;
2764 break;
2765 }
2766}
2767
2768
2769/* Print an address in numeric and symbolic form (if possible) */
2770static void xmon_print_symbol(unsigned long address, const char *mid,
2771 const char *after)
2772{
2773 char *modname;
2774 const char *name = NULL;
2775 unsigned long offset, size;
2776
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002777 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 if (setjmp(bus_error_jmp) == 0) {
2779 catch_memory_errors = 1;
2780 sync();
2781 name = kallsyms_lookup(address, &size, &offset, &modname,
2782 tmpstr);
2783 sync();
2784 /* wait a little while to see if we get a machine check */
2785 __delay(200);
2786 }
2787
2788 catch_memory_errors = 0;
2789
2790 if (name) {
2791 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2792 if (modname)
2793 printf(" [%s]", modname);
2794 }
2795 printf("%s", after);
2796}
2797
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002798#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10002799void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800{
2801 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05302802 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11002803 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
Michael Ellerman736256e2014-05-26 21:02:14 +10002805 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806
Michael Neuling584f8b72007-12-06 17:24:48 +11002807 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002808 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2809 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Anshuman Khandual8218a302015-07-29 12:40:04 +05302810 if (esid || vsid) {
will schmidtb3b95952007-12-07 08:22:23 +11002811 printf("%02d %016lx %016lx", i, esid, vsid);
Anshuman Khandual8218a302015-07-29 12:40:04 +05302812 if (esid & SLB_ESID_V) {
will schmidtb3b95952007-12-07 08:22:23 +11002813 llp = vsid & SLB_VSID_LLP;
2814 if (vsid & SLB_VSID_B_1T) {
2815 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2816 GET_ESID_1T(esid),
2817 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2818 llp);
2819 } else {
2820 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2821 GET_ESID(esid),
2822 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2823 llp);
2824 }
2825 } else
2826 printf("\n");
2827 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 }
2829}
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002830#endif
2831
2832#ifdef CONFIG_PPC_STD_MMU_32
2833void dump_segments(void)
2834{
2835 int i;
2836
2837 printf("sr0-15 =");
2838 for (i = 0; i < 16; ++i)
2839 printf(" %x", mfsrin(i));
2840 printf("\n");
2841}
2842#endif
2843
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002844#ifdef CONFIG_44x
2845static void dump_tlb_44x(void)
2846{
2847 int i;
2848
2849 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2850 unsigned long w0,w1,w2;
2851 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2852 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2853 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2854 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2855 if (w0 & PPC44x_TLB_VALID) {
2856 printf("V %08x -> %01x%08x %c%c%c%c%c",
2857 w0 & PPC44x_TLB_EPN_MASK,
2858 w1 & PPC44x_TLB_ERPN_MASK,
2859 w1 & PPC44x_TLB_RPN_MASK,
2860 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2861 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2862 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2863 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2864 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2865 }
2866 printf("\n");
2867 }
2868}
2869#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002870
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002871#ifdef CONFIG_PPC_BOOK3E
2872static void dump_tlb_book3e(void)
2873{
2874 u32 mmucfg, pidmask, lpidmask;
2875 u64 ramask;
2876 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2877 int mmu_version;
2878 static const char *pgsz_names[] = {
2879 " 1K",
2880 " 2K",
2881 " 4K",
2882 " 8K",
2883 " 16K",
2884 " 32K",
2885 " 64K",
2886 "128K",
2887 "256K",
2888 "512K",
2889 " 1M",
2890 " 2M",
2891 " 4M",
2892 " 8M",
2893 " 16M",
2894 " 32M",
2895 " 64M",
2896 "128M",
2897 "256M",
2898 "512M",
2899 " 1G",
2900 " 2G",
2901 " 4G",
2902 " 8G",
2903 " 16G",
2904 " 32G",
2905 " 64G",
2906 "128G",
2907 "256G",
2908 "512G",
2909 " 1T",
2910 " 2T",
2911 };
2912
2913 /* Gather some infos about the MMU */
2914 mmucfg = mfspr(SPRN_MMUCFG);
2915 mmu_version = (mmucfg & 3) + 1;
2916 ntlbs = ((mmucfg >> 2) & 3) + 1;
2917 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2918 lpidsz = (mmucfg >> 24) & 0xf;
2919 rasz = (mmucfg >> 16) & 0x7f;
2920 if ((mmu_version > 1) && (mmucfg & 0x10000))
2921 lrat = 1;
2922 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2923 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2924 pidmask = (1ul << pidsz) - 1;
2925 lpidmask = (1ul << lpidsz) - 1;
2926 ramask = (1ull << rasz) - 1;
2927
2928 for (tlb = 0; tlb < ntlbs; tlb++) {
2929 u32 tlbcfg;
2930 int nent, assoc, new_cc = 1;
2931 printf("TLB %d:\n------\n", tlb);
2932 switch(tlb) {
2933 case 0:
2934 tlbcfg = mfspr(SPRN_TLB0CFG);
2935 break;
2936 case 1:
2937 tlbcfg = mfspr(SPRN_TLB1CFG);
2938 break;
2939 case 2:
2940 tlbcfg = mfspr(SPRN_TLB2CFG);
2941 break;
2942 case 3:
2943 tlbcfg = mfspr(SPRN_TLB3CFG);
2944 break;
2945 default:
2946 printf("Unsupported TLB number !\n");
2947 continue;
2948 }
2949 nent = tlbcfg & 0xfff;
2950 assoc = (tlbcfg >> 24) & 0xff;
2951 for (i = 0; i < nent; i++) {
2952 u32 mas0 = MAS0_TLBSEL(tlb);
2953 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
2954 u64 mas2 = 0;
2955 u64 mas7_mas3;
2956 int esel = i, cc = i;
2957
2958 if (assoc != 0) {
2959 cc = i / assoc;
2960 esel = i % assoc;
2961 mas2 = cc * 0x1000;
2962 }
2963
2964 mas0 |= MAS0_ESEL(esel);
2965 mtspr(SPRN_MAS0, mas0);
2966 mtspr(SPRN_MAS1, mas1);
2967 mtspr(SPRN_MAS2, mas2);
2968 asm volatile("tlbre 0,0,0" : : : "memory");
2969 mas1 = mfspr(SPRN_MAS1);
2970 mas2 = mfspr(SPRN_MAS2);
2971 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
2972 if (assoc && (i % assoc) == 0)
2973 new_cc = 1;
2974 if (!(mas1 & MAS1_VALID))
2975 continue;
2976 if (assoc == 0)
2977 printf("%04x- ", i);
2978 else if (new_cc)
2979 printf("%04x-%c", cc, 'A' + esel);
2980 else
2981 printf(" |%c", 'A' + esel);
2982 new_cc = 0;
2983 printf(" %016llx %04x %s %c%c AS%c",
2984 mas2 & ~0x3ffull,
2985 (mas1 >> 16) & 0x3fff,
2986 pgsz_names[(mas1 >> 7) & 0x1f],
2987 mas1 & MAS1_IND ? 'I' : ' ',
2988 mas1 & MAS1_IPROT ? 'P' : ' ',
2989 mas1 & MAS1_TS ? '1' : '0');
2990 printf(" %c%c%c%c%c%c%c",
2991 mas2 & MAS2_X0 ? 'a' : ' ',
2992 mas2 & MAS2_X1 ? 'v' : ' ',
2993 mas2 & MAS2_W ? 'w' : ' ',
2994 mas2 & MAS2_I ? 'i' : ' ',
2995 mas2 & MAS2_M ? 'm' : ' ',
2996 mas2 & MAS2_G ? 'g' : ' ',
2997 mas2 & MAS2_E ? 'e' : ' ');
2998 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
2999 if (mas1 & MAS1_IND)
3000 printf(" %s\n",
3001 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3002 else
3003 printf(" U%c%c%c S%c%c%c\n",
3004 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3005 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3006 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3007 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3008 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3009 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3010 }
3011 }
3012}
3013#endif /* CONFIG_PPC_BOOK3E */
3014
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003015static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003017 if (enable) {
3018 __debugger = xmon;
3019 __debugger_ipi = xmon_ipi;
3020 __debugger_bpt = xmon_bpt;
3021 __debugger_sstep = xmon_sstep;
3022 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003023 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003024 __debugger_fault_handler = xmon_fault_handler;
3025 } else {
3026 __debugger = NULL;
3027 __debugger_ipi = NULL;
3028 __debugger_bpt = NULL;
3029 __debugger_sstep = NULL;
3030 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003031 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003032 __debugger_fault_handler = NULL;
3033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003035
3036#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003037static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003038{
3039 /* ensure xmon is enabled */
3040 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003041 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003042}
3043
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003044static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003045 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003046 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003047 .action_msg = "Entering xmon",
3048};
3049
3050static int __init setup_xmon_sysrq(void)
3051{
3052 register_sysrq_key('x', &sysrq_xmon_op);
3053 return 0;
3054}
3055__initcall(setup_xmon_sysrq);
3056#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003057
Olaf Heringf5e6a282007-06-24 16:57:08 +10003058static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10003059
3060static int __init early_parse_xmon(char *p)
3061{
3062 if (!p || strncmp(p, "early", 5) == 0) {
3063 /* just "xmon" is equivalent to "xmon=early" */
3064 xmon_init(1);
3065 xmon_early = 1;
3066 } else if (strncmp(p, "on", 2) == 0)
3067 xmon_init(1);
3068 else if (strncmp(p, "off", 3) == 0)
3069 xmon_off = 1;
3070 else if (strncmp(p, "nobt", 4) == 0)
3071 xmon_no_auto_backtrace = 1;
3072 else
3073 return 1;
3074
3075 return 0;
3076}
3077early_param("xmon", early_parse_xmon);
3078
3079void __init xmon_setup(void)
3080{
3081#ifdef CONFIG_XMON_DEFAULT
3082 if (!xmon_off)
3083 xmon_init(1);
3084#endif
3085 if (xmon_early)
3086 debugger(NULL);
3087}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003088
Arnd Bergmanne0555952006-11-27 19:18:55 +01003089#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003090
3091struct spu_info {
3092 struct spu *spu;
3093 u64 saved_mfc_sr1_RW;
3094 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003095 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003096 u8 stopped_ok;
3097};
3098
3099#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3100
3101static struct spu_info spu_info[XMON_NUM_SPUS];
3102
3103void xmon_register_spus(struct list_head *list)
3104{
3105 struct spu *spu;
3106
3107 list_for_each_entry(spu, list, full_list) {
3108 if (spu->number >= XMON_NUM_SPUS) {
3109 WARN_ON(1);
3110 continue;
3111 }
3112
3113 spu_info[spu->number].spu = spu;
3114 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003115 spu_info[spu->number].dump_addr = (unsigned long)
3116 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003117 }
3118}
3119
3120static void stop_spus(void)
3121{
3122 struct spu *spu;
3123 int i;
3124 u64 tmp;
3125
3126 for (i = 0; i < XMON_NUM_SPUS; i++) {
3127 if (!spu_info[i].spu)
3128 continue;
3129
3130 if (setjmp(bus_error_jmp) == 0) {
3131 catch_memory_errors = 1;
3132 sync();
3133
3134 spu = spu_info[i].spu;
3135
3136 spu_info[i].saved_spu_runcntl_RW =
3137 in_be32(&spu->problem->spu_runcntl_RW);
3138
3139 tmp = spu_mfc_sr1_get(spu);
3140 spu_info[i].saved_mfc_sr1_RW = tmp;
3141
3142 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3143 spu_mfc_sr1_set(spu, tmp);
3144
3145 sync();
3146 __delay(200);
3147
3148 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003149
3150 printf("Stopped spu %.2d (was %s)\n", i,
3151 spu_info[i].saved_spu_runcntl_RW ?
3152 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003153 } else {
3154 catch_memory_errors = 0;
3155 printf("*** Error stopping spu %.2d\n", i);
3156 }
3157 catch_memory_errors = 0;
3158 }
3159}
3160
3161static void restart_spus(void)
3162{
3163 struct spu *spu;
3164 int i;
3165
3166 for (i = 0; i < XMON_NUM_SPUS; i++) {
3167 if (!spu_info[i].spu)
3168 continue;
3169
3170 if (!spu_info[i].stopped_ok) {
3171 printf("*** Error, spu %d was not successfully stopped"
3172 ", not restarting\n", i);
3173 continue;
3174 }
3175
3176 if (setjmp(bus_error_jmp) == 0) {
3177 catch_memory_errors = 1;
3178 sync();
3179
3180 spu = spu_info[i].spu;
3181 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3182 out_be32(&spu->problem->spu_runcntl_RW,
3183 spu_info[i].saved_spu_runcntl_RW);
3184
3185 sync();
3186 __delay(200);
3187
3188 printf("Restarted spu %.2d\n", i);
3189 } else {
3190 catch_memory_errors = 0;
3191 printf("*** Error restarting spu %.2d\n", i);
3192 }
3193 catch_memory_errors = 0;
3194 }
3195}
3196
Michael Ellermana8984972006-10-24 18:31:28 +02003197#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003198#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003199do { \
3200 if (setjmp(bus_error_jmp) == 0) { \
3201 catch_memory_errors = 1; \
3202 sync(); \
3203 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003204 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003205 sync(); \
3206 __delay(200); \
3207 } else { \
3208 catch_memory_errors = 0; \
3209 printf(" %-*s = *** Error reading field.\n", \
3210 DUMP_WIDTH, #field); \
3211 } \
3212 catch_memory_errors = 0; \
3213} while (0)
3214
Michael Ellerman437a0702006-11-23 00:46:39 +01003215#define DUMP_FIELD(obj, format, field) \
3216 DUMP_VALUE(format, field, obj->field)
3217
Michael Ellermana8984972006-10-24 18:31:28 +02003218static void dump_spu_fields(struct spu *spu)
3219{
3220 printf("Dumping spu fields at address %p:\n", spu);
3221
3222 DUMP_FIELD(spu, "0x%x", number);
3223 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003224 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3225 DUMP_FIELD(spu, "0x%p", local_store);
3226 DUMP_FIELD(spu, "0x%lx", ls_size);
3227 DUMP_FIELD(spu, "0x%x", node);
3228 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003229 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003230 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003231 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3232 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003233 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3234 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3235 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3236 DUMP_FIELD(spu, "0x%x", slb_replace);
3237 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003238 DUMP_FIELD(spu, "0x%p", mm);
3239 DUMP_FIELD(spu, "0x%p", ctx);
3240 DUMP_FIELD(spu, "0x%p", rq);
3241 DUMP_FIELD(spu, "0x%p", timestamp);
3242 DUMP_FIELD(spu, "0x%lx", problem_phys);
3243 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003244 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3245 in_be32(&spu->problem->spu_runcntl_RW));
3246 DUMP_VALUE("0x%x", problem->spu_status_R,
3247 in_be32(&spu->problem->spu_status_R));
3248 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3249 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003250 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003251 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003252}
3253
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003254int
3255spu_inst_dump(unsigned long adr, long count, int praddr)
3256{
3257 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3258}
3259
3260static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003261{
3262 unsigned long offset, addr, ls_addr;
3263
3264 if (setjmp(bus_error_jmp) == 0) {
3265 catch_memory_errors = 1;
3266 sync();
3267 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3268 sync();
3269 __delay(200);
3270 } else {
3271 catch_memory_errors = 0;
3272 printf("*** Error: accessing spu info for spu %d\n", num);
3273 return;
3274 }
3275 catch_memory_errors = 0;
3276
3277 if (scanhex(&offset))
3278 addr = ls_addr + offset;
3279 else
3280 addr = spu_info[num].dump_addr;
3281
3282 if (addr >= ls_addr + LS_SIZE) {
3283 printf("*** Error: address outside of local store\n");
3284 return;
3285 }
3286
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003287 switch (subcmd) {
3288 case 'i':
3289 addr += spu_inst_dump(addr, 16, 1);
3290 last_cmd = "sdi\n";
3291 break;
3292 default:
3293 prdump(addr, 64);
3294 addr += 64;
3295 last_cmd = "sd\n";
3296 break;
3297 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003298
3299 spu_info[num].dump_addr = addr;
3300}
3301
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003302static int do_spu_cmd(void)
3303{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003304 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003305 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003306
3307 cmd = inchar();
3308 switch (cmd) {
3309 case 's':
3310 stop_spus();
3311 break;
3312 case 'r':
3313 restart_spus();
3314 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003315 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003316 subcmd = inchar();
3317 if (isxdigit(subcmd) || subcmd == '\n')
3318 termch = subcmd;
3319 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003320 scanhex(&num);
3321 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003322 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003323 return 0;
3324 }
3325
3326 switch (cmd) {
3327 case 'f':
3328 dump_spu_fields(spu_info[num].spu);
3329 break;
3330 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003331 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003332 break;
3333 }
3334
Michael Ellermana8984972006-10-24 18:31:28 +02003335 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003336 default:
3337 return -1;
3338 }
3339
3340 return 0;
3341}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003342#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003343static int do_spu_cmd(void)
3344{
3345 return -1;
3346}
3347#endif