blob: bf8f49a8b3a7d9edbc55043cc34296ed11e04260 [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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-10-28 22:53:37 +100049
50#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-10-28 22:53:37 +1000172extern void xmon_enter(void);
173extern void xmon_leave(void);
174
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000175#ifdef CONFIG_PPC64
176#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000177#else
178#define REG "%.8lx"
Paul Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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;
323
324 /*
325 * At this point we have got all the cpus we can into
326 * xmon, so there is hopefully no other cpu calling RTAS
327 * at the moment, even though we don't take rtas.lock.
328 * If we did try to take rtas.lock there would be a
329 * real possibility of deadlock.
330 */
331 args.token = rtas_token("set-indicator");
332 if (args.token == RTAS_UNKNOWN_SERVICE)
333 return;
Laurent Dufoure6eb2eb2015-01-15 18:23:47 +0100334 args.token = cpu_to_be32(args.token);
Laurent Dufour3b8a3c02014-11-24 15:07:53 +0100335 args.nargs = cpu_to_be32(3);
336 args.nret = cpu_to_be32(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 args.rets = &args.args[3];
Laurent Dufour3b8a3c02014-11-24 15:07:53 +0100338 args.args[0] = cpu_to_be32(SURVEILLANCE_TOKEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 args.args[1] = 0;
340 args.args[2] = 0;
341 enter_rtas(__pa(&args));
342#endif /* CONFIG_PPC_PSERIES */
343}
344
345#ifdef CONFIG_SMP
346static int xmon_speaker;
347
348static void get_output_lock(void)
349{
350 int me = smp_processor_id() + 0x100;
351 int last_speaker = 0, prev;
352 long timeout;
353
354 if (xmon_speaker == me)
355 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100358 last_speaker = cmpxchg(&xmon_speaker, 0, me);
359 if (last_speaker == 0)
360 return;
361
Michael Ellerman15075892013-12-23 23:46:05 +1100362 /*
363 * Wait a full second for the lock, we might be on a slow
364 * console, but check every 100us.
365 */
366 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100368 if (--timeout > 0) {
369 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100371 }
372
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 /* hostile takeover */
374 prev = cmpxchg(&xmon_speaker, last_speaker, me);
375 if (prev == last_speaker)
376 return;
377 break;
378 }
379 }
380}
381
382static void release_output_lock(void)
383{
384 xmon_speaker = 0;
385}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000386
387int cpus_are_in_xmon(void)
388{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000389 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000390}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391#endif
392
Josh Boyerdaf8f402009-09-23 03:51:04 +0000393static inline int unrecoverable_excp(struct pt_regs *regs)
394{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000395#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000396 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000397 return 0;
398#else
399 return ((regs->msr & MSR_RI) == 0);
400#endif
401}
402
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000403static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
405 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 struct bpt *bp;
407 long recurse_jmp[JMP_BUF_LEN];
408 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100409 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410#ifdef CONFIG_SMP
411 int cpu;
412 int secondary;
413 unsigned long timeout;
414#endif
415
Anton Blanchardf13659e2007-03-21 01:48:34 +1100416 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000417 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 bp = in_breakpoint_table(regs->nip, &offset);
420 if (bp != NULL) {
421 regs->nip = bp->address + offset;
422 atomic_dec(&bp->ref_count);
423 }
424
425 remove_cpu_bpts();
426
427#ifdef CONFIG_SMP
428 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000429 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 get_output_lock();
431 excprint(regs);
432 printf("cpu 0x%x: Exception %lx %s in xmon, "
433 "returning to main loop\n",
434 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000435 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 longjmp(xmon_fault_jmp[cpu], 1);
437 }
438
439 if (setjmp(recurse_jmp) != 0) {
440 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000441 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 printf("xmon: WARNING: bad recursive fault "
443 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000444 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 goto waiting;
446 }
447 secondary = !(xmon_taken && cpu == xmon_owner);
448 goto cmdloop;
449 }
450
451 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
453 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000454 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000456 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 fromipi = 0;
458
459 if (!fromipi) {
460 get_output_lock();
461 excprint(regs);
462 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000463 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 cpu, BP_NUM(bp));
465 xmon_print_symbol(regs->nip, " ", ")\n");
466 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000467 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 printf("WARNING: exception is not recoverable, "
469 "can't continue\n");
470 release_output_lock();
471 }
472
Michael Ellermand2b496e2013-12-23 23:46:06 +1100473 cpumask_set_cpu(cpu, &cpus_in_xmon);
474
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 waiting:
476 secondary = 1;
477 while (secondary && !xmon_gate) {
478 if (in_xmon == 0) {
479 if (fromipi)
480 goto leave;
481 secondary = test_and_set_bit(0, &in_xmon);
482 }
483 barrier();
484 }
485
486 if (!secondary && !xmon_gate) {
487 /* we are the first cpu to come in */
488 /* interrupt other cpu(s) */
489 int ncpus = num_online_cpus();
490
491 xmon_owner = cpu;
492 mb();
493 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000494 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 /* wait for other cpus to come in */
496 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000497 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 break;
499 barrier();
500 }
501 }
502 remove_bpts();
503 disable_surveillance();
504 /* for breakpoint or single step, print the current instr. */
505 if (bp || TRAP(regs) == 0xd00)
506 ppc_inst_dump(regs->nip, 1, 0);
507 printf("enter ? for help\n");
508 mb();
509 xmon_gate = 1;
510 barrier();
511 }
512
513 cmdloop:
514 while (in_xmon) {
515 if (secondary) {
516 if (cpu == xmon_owner) {
517 if (!test_and_set_bit(0, &xmon_taken)) {
518 secondary = 0;
519 continue;
520 }
521 /* missed it */
522 while (cpu == xmon_owner)
523 barrier();
524 }
525 barrier();
526 } else {
527 cmd = cmds(regs);
528 if (cmd != 0) {
529 /* exiting xmon */
530 insert_bpts();
531 xmon_gate = 0;
532 wmb();
533 in_xmon = 0;
534 break;
535 }
536 /* have switched to some other cpu */
537 secondary = 1;
538 }
539 }
540 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000541 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543#else
544 /* UP is simple... */
545 if (in_xmon) {
546 printf("Exception %lx %s in xmon, returning to main loop\n",
547 regs->trap, getvecname(TRAP(regs)));
548 longjmp(xmon_fault_jmp[0], 1);
549 }
550 if (setjmp(recurse_jmp) == 0) {
551 xmon_fault_jmp[0] = recurse_jmp;
552 in_xmon = 1;
553
554 excprint(regs);
555 bp = at_breakpoint(regs->nip);
556 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000557 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 xmon_print_symbol(regs->nip, " ", ")\n");
559 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000560 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 printf("WARNING: exception is not recoverable, "
562 "can't continue\n");
563 remove_bpts();
564 disable_surveillance();
565 /* for breakpoint or single step, print the current instr. */
566 if (bp || TRAP(regs) == 0xd00)
567 ppc_inst_dump(regs->nip, 1, 0);
568 printf("enter ? for help\n");
569 }
570
571 cmd = cmds(regs);
572
573 insert_bpts();
574 in_xmon = 0;
575#endif
576
Josh Boyercdd39042009-10-05 04:46:05 +0000577#ifdef CONFIG_BOOKE
578 if (regs->msr & MSR_DE) {
579 bp = at_breakpoint(regs->nip);
580 if (bp != NULL) {
581 regs->nip = (unsigned long) &bp->instr[0];
582 atomic_inc(&bp->ref_count);
583 }
584 }
585#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000586 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 bp = at_breakpoint(regs->nip);
588 if (bp != NULL) {
589 int stepped = emulate_step(regs, bp->instr[0]);
590 if (stepped == 0) {
591 regs->nip = (unsigned long) &bp->instr[0];
592 atomic_inc(&bp->ref_count);
593 } else if (stepped < 0) {
594 printf("Couldn't single-step %s instruction\n",
595 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
596 }
597 }
598 }
Josh Boyercdd39042009-10-05 04:46:05 +0000599#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 insert_cpu_bpts();
601
Anton Blancharda71d64b2014-08-05 14:55:00 +1000602 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100603 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000605 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606}
607
608int xmon(struct pt_regs *excp)
609{
610 struct pt_regs regs;
611
612 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000613 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 excp = &regs;
615 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200616
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 return xmon_core(excp, 0);
618}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000619EXPORT_SYMBOL(xmon);
620
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000621irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000622{
623 unsigned long flags;
624 local_irq_save(flags);
625 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000626 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000627 local_irq_restore(flags);
628 return IRQ_HANDLED;
629}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000631static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632{
633 struct bpt *bp;
634 unsigned long offset;
635
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000636 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 return 0;
638
639 /* Are we at the trap at bp->instr[1] for some bp? */
640 bp = in_breakpoint_table(regs->nip, &offset);
641 if (bp != NULL && offset == 4) {
642 regs->nip = bp->address + 4;
643 atomic_dec(&bp->ref_count);
644 return 1;
645 }
646
647 /* Are we at a breakpoint? */
648 bp = at_breakpoint(regs->nip);
649 if (!bp)
650 return 0;
651
652 xmon_core(regs, 0);
653
654 return 1;
655}
656
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000657static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658{
659 if (user_mode(regs))
660 return 0;
661 xmon_core(regs, 0);
662 return 1;
663}
664
Michael Neuling9422de32012-12-20 14:06:44 +0000665static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000667 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000669 if (dabr.enabled == 0)
670 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 xmon_core(regs, 0);
672 return 1;
673}
674
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000675static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000677 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000679 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 return 0;
681 xmon_core(regs, 0);
682 return 1;
683}
684
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000685static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
687#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000688 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 xmon_core(regs, 1);
690#endif
691 return 0;
692}
693
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000694static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
696 struct bpt *bp;
697 unsigned long offset;
698
699 if (in_xmon && catch_memory_errors)
700 handle_fault(regs); /* doesn't return */
701
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000702 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 bp = in_breakpoint_table(regs->nip, &offset);
704 if (bp != NULL) {
705 regs->nip = bp->address + offset;
706 atomic_dec(&bp->ref_count);
707 }
708 }
709
710 return 0;
711}
712
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713static struct bpt *at_breakpoint(unsigned long pc)
714{
715 int i;
716 struct bpt *bp;
717
718 bp = bpts;
719 for (i = 0; i < NBPTS; ++i, ++bp)
720 if (bp->enabled && pc == bp->address)
721 return bp;
722 return NULL;
723}
724
725static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
726{
727 unsigned long off;
728
729 off = nip - (unsigned long) bpts;
730 if (off >= sizeof(bpts))
731 return NULL;
732 off %= sizeof(struct bpt);
733 if (off != offsetof(struct bpt, instr[0])
734 && off != offsetof(struct bpt, instr[1]))
735 return NULL;
736 *offp = off - offsetof(struct bpt, instr[0]);
737 return (struct bpt *) (nip - off);
738}
739
740static struct bpt *new_breakpoint(unsigned long a)
741{
742 struct bpt *bp;
743
744 a &= ~3UL;
745 bp = at_breakpoint(a);
746 if (bp)
747 return bp;
748
749 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
750 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
751 bp->address = a;
752 bp->instr[1] = bpinstr;
753 store_inst(&bp->instr[1]);
754 return bp;
755 }
756 }
757
758 printf("Sorry, no free breakpoints. Please clear one first.\n");
759 return NULL;
760}
761
762static void insert_bpts(void)
763{
764 int i;
765 struct bpt *bp;
766
767 bp = bpts;
768 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100769 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 continue;
771 if (mread(bp->address, &bp->instr[0], 4) != 4) {
772 printf("Couldn't read instruction at %lx, "
773 "disabling breakpoint there\n", bp->address);
774 bp->enabled = 0;
775 continue;
776 }
777 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
778 printf("Breakpoint at %lx is on an mtmsrd or rfid "
779 "instruction, disabling it\n", bp->address);
780 bp->enabled = 0;
781 continue;
782 }
783 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100784 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 continue;
786 if (mwrite(bp->address, &bpinstr, 4) != 4) {
787 printf("Couldn't write instruction at %lx, "
788 "disabling breakpoint there\n", bp->address);
789 bp->enabled &= ~BP_TRAP;
790 continue;
791 }
792 store_inst((void *)bp->address);
793 }
794}
795
796static void insert_cpu_bpts(void)
797{
Michael Neuling9422de32012-12-20 14:06:44 +0000798 struct arch_hw_breakpoint brk;
799
800 if (dabr.enabled) {
801 brk.address = dabr.address;
802 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
803 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400804 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000805 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530806
807 if (iabr)
808 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809}
810
811static void remove_bpts(void)
812{
813 int i;
814 struct bpt *bp;
815 unsigned instr;
816
817 bp = bpts;
818 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100819 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 continue;
821 if (mread(bp->address, &instr, 4) == 4
822 && instr == bpinstr
823 && mwrite(bp->address, &bp->instr, 4) != 4)
824 printf("Couldn't remove breakpoint at %lx\n",
825 bp->address);
826 else
827 store_inst((void *)bp->address);
828 }
829}
830
831static void remove_cpu_bpts(void)
832{
Michael Neuling9422de32012-12-20 14:06:44 +0000833 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530834 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835}
836
Sam bobroff958b7c82015-10-08 11:50:23 +1100837static void set_lpp_cmd(void)
838{
839 unsigned long lpp;
840
841 if (!scanhex(&lpp)) {
842 printf("Invalid number.\n");
843 lpp = 0;
844 }
845 xmon_set_pagination_lpp(lpp);
846}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847/* Command interpreting routine */
848static char *last_cmd;
849
850static int
851cmds(struct pt_regs *excp)
852{
853 int cmd = 0;
854
855 last_cmd = NULL;
856 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200857
858 if (!xmon_no_auto_backtrace) {
859 xmon_no_auto_backtrace = 1;
860 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
861 }
862
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 for(;;) {
864#ifdef CONFIG_SMP
865 printf("%x:", smp_processor_id());
866#endif /* CONFIG_SMP */
867 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 flush_input();
869 termch = 0;
870 cmd = skipbl();
871 if( cmd == '\n' ) {
872 if (last_cmd == NULL)
873 continue;
874 take_input(last_cmd);
875 last_cmd = NULL;
876 cmd = inchar();
877 }
878 switch (cmd) {
879 case 'm':
880 cmd = inchar();
881 switch (cmd) {
882 case 'm':
883 case 's':
884 case 'd':
885 memops(cmd);
886 break;
887 case 'l':
888 memlocate();
889 break;
890 case 'z':
891 memzcan();
892 break;
893 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700894 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 break;
896 default:
897 termch = cmd;
898 memex();
899 }
900 break;
901 case 'd':
902 dump();
903 break;
904 case 'l':
905 symbol_lookup();
906 break;
907 case 'r':
908 prregs(excp); /* print regs */
909 break;
910 case 'e':
911 excprint(excp);
912 break;
913 case 'S':
914 super_regs();
915 break;
916 case 't':
917 backtrace(excp);
918 break;
919 case 'f':
920 cacheflush();
921 break;
922 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200923 if (do_spu_cmd() == 0)
924 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 if (do_step(excp))
926 return cmd;
927 break;
928 case 'x':
929 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100930 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100932 printf(" <no input ...>\n");
933 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 return cmd;
935 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000936 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 break;
Sam bobroff958b7c82015-10-08 11:50:23 +1100938 case '#':
939 set_lpp_cmd();
940 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 case 'b':
942 bpt_cmds();
943 break;
944 case 'C':
945 csum();
946 break;
947 case 'c':
948 if (cpu_cmd())
949 return 0;
950 break;
951 case 'z':
952 bootcmds();
953 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000954 case 'p':
955 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000957#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 case 'u':
959 dump_segments();
960 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +1100961#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100962 case 'u':
963 dump_tlb_44x();
964 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000965#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000966 case 'u':
967 dump_tlb_book3e();
968 break;
969#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 default:
971 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000972 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 if (' ' < cmd && cmd <= '~')
974 putchar(cmd);
975 else
976 printf("\\x%x", cmd);
977 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +0000978 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 printf(" (type ? for help)\n");
980 break;
981 }
982 }
983}
984
Josh Boyercdd39042009-10-05 04:46:05 +0000985#ifdef CONFIG_BOOKE
986static int do_step(struct pt_regs *regs)
987{
988 regs->msr |= MSR_DE;
989 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
990 return 1;
991}
992#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993/*
994 * Step a single instruction.
995 * Some instructions we emulate, others we execute with MSR_SE set.
996 */
997static int do_step(struct pt_regs *regs)
998{
999 unsigned int instr;
1000 int stepped;
1001
1002 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001003 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 if (mread(regs->nip, &instr, 4) == 4) {
1005 stepped = emulate_step(regs, instr);
1006 if (stepped < 0) {
1007 printf("Couldn't single-step %s instruction\n",
1008 (IS_RFID(instr)? "rfid": "mtmsrd"));
1009 return 0;
1010 }
1011 if (stepped > 0) {
1012 regs->trap = 0xd00 | (regs->trap & 1);
1013 printf("stepped to ");
1014 xmon_print_symbol(regs->nip, " ", "\n");
1015 ppc_inst_dump(regs->nip, 1, 0);
1016 return 0;
1017 }
1018 }
1019 }
1020 regs->msr |= MSR_SE;
1021 return 1;
1022}
Josh Boyercdd39042009-10-05 04:46:05 +00001023#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025static void bootcmds(void)
1026{
1027 int cmd;
1028
1029 cmd = inchar();
1030 if (cmd == 'r')
1031 ppc_md.restart(NULL);
1032 else if (cmd == 'h')
1033 ppc_md.halt();
1034 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001035 if (pm_power_off)
1036 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037}
1038
1039static int cpu_cmd(void)
1040{
1041#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001042 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
1045 if (!scanhex(&cpu)) {
1046 /* print cpus waiting or in xmon */
1047 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001048 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001049 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001050 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001051 if (cpu == last_cpu + 1) {
1052 last_cpu = cpu;
1053 } else {
1054 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001055 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001056 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001057 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 }
1060 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001061 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001062 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 printf("\n");
1064 return 0;
1065 }
1066 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001067 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 printf("cpu 0x%x isn't in xmon\n", cpu);
1069 return 0;
1070 }
1071 xmon_taken = 0;
1072 mb();
1073 xmon_owner = cpu;
1074 timeout = 10000000;
1075 while (!xmon_taken) {
1076 if (--timeout == 0) {
1077 if (test_and_set_bit(0, &xmon_taken))
1078 break;
1079 /* take control back */
1080 mb();
1081 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001082 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 return 0;
1084 }
1085 barrier();
1086 }
1087 return 1;
1088#else
1089 return 0;
1090#endif /* CONFIG_SMP */
1091}
1092
1093static unsigned short fcstab[256] = {
1094 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1095 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1096 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1097 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1098 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1099 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1100 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1101 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1102 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1103 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1104 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1105 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1106 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1107 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1108 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1109 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1110 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1111 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1112 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1113 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1114 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1115 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1116 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1117 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1118 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1119 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1120 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1121 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1122 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1123 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1124 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1125 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1126};
1127
1128#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1129
1130static void
1131csum(void)
1132{
1133 unsigned int i;
1134 unsigned short fcs;
1135 unsigned char v;
1136
1137 if (!scanhex(&adrs))
1138 return;
1139 if (!scanhex(&ncsum))
1140 return;
1141 fcs = 0xffff;
1142 for (i = 0; i < ncsum; ++i) {
1143 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001144 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 break;
1146 }
1147 fcs = FCS(fcs, v);
1148 }
1149 printf("%x\n", fcs);
1150}
1151
1152/*
1153 * Check if this is a suitable place to put a breakpoint.
1154 */
1155static long check_bp_loc(unsigned long addr)
1156{
1157 unsigned int instr;
1158
1159 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001160 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 printf("Breakpoints may only be placed at kernel addresses\n");
1162 return 0;
1163 }
1164 if (!mread(addr, &instr, sizeof(instr))) {
1165 printf("Can't read instruction at address %lx\n", addr);
1166 return 0;
1167 }
1168 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1169 printf("Breakpoints may not be placed on mtmsrd or rfid "
1170 "instructions\n");
1171 return 0;
1172 }
1173 return 1;
1174}
1175
Michael Ellermane3bc8042012-08-23 22:09:13 +00001176static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 "Breakpoint command usage:\n"
1178 "b show breakpoints\n"
1179 "b <addr> [cnt] set breakpoint at given instr addr\n"
1180 "bc clear all breakpoints\n"
1181 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301182 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 "bd <addr> [cnt] set hardware data breakpoint\n"
1184 "";
1185
1186static void
1187bpt_cmds(void)
1188{
1189 int cmd;
1190 unsigned long a;
1191 int mode, i;
1192 struct bpt *bp;
1193 const char badaddr[] = "Only kernel addresses are permitted "
1194 "for breakpoints\n";
1195
1196 cmd = inchar();
1197 switch (cmd) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001198#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 case 'd': /* bd - hardware data breakpoint */
1200 mode = 7;
1201 cmd = inchar();
1202 if (cmd == 'r')
1203 mode = 5;
1204 else if (cmd == 'w')
1205 mode = 6;
1206 else
1207 termch = cmd;
1208 dabr.address = 0;
1209 dabr.enabled = 0;
1210 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001211 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 printf(badaddr);
1213 break;
1214 }
Michael Neuling9422de32012-12-20 14:06:44 +00001215 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 dabr.enabled = mode | BP_DABR;
1217 }
1218 break;
1219
1220 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301221 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 printf("Hardware instruction breakpoint "
1223 "not supported on this cpu\n");
1224 break;
1225 }
1226 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001227 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 iabr = NULL;
1229 }
1230 if (!scanhex(&a))
1231 break;
1232 if (!check_bp_loc(a))
1233 break;
1234 bp = new_breakpoint(a);
1235 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001236 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 iabr = bp;
1238 }
1239 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001240#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
1242 case 'c':
1243 if (!scanhex(&a)) {
1244 /* clear all breakpoints */
1245 for (i = 0; i < NBPTS; ++i)
1246 bpts[i].enabled = 0;
1247 iabr = NULL;
1248 dabr.enabled = 0;
1249 printf("All breakpoints cleared\n");
1250 break;
1251 }
1252
1253 if (a <= NBPTS && a >= 1) {
1254 /* assume a breakpoint number */
1255 bp = &bpts[a-1]; /* bp nums are 1 based */
1256 } else {
1257 /* assume a breakpoint address */
1258 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001259 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001260 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 break;
1262 }
1263 }
1264
Michael Ellerman736256e2014-05-26 21:02:14 +10001265 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 xmon_print_symbol(bp->address, " ", ")\n");
1267 bp->enabled = 0;
1268 break;
1269
1270 default:
1271 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001272 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 if (cmd == '?') {
1274 printf(breakpoint_help_string);
1275 break;
1276 }
1277 termch = cmd;
1278 if (!scanhex(&a)) {
1279 /* print all breakpoints */
1280 printf(" type address\n");
1281 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001282 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 if (dabr.enabled & 1)
1284 printf("r");
1285 if (dabr.enabled & 2)
1286 printf("w");
1287 printf("]\n");
1288 }
1289 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1290 if (!bp->enabled)
1291 continue;
1292 printf("%2x %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001293 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 xmon_print_symbol(bp->address, " ", "\n");
1295 }
1296 break;
1297 }
1298
1299 if (!check_bp_loc(a))
1300 break;
1301 bp = new_breakpoint(a);
1302 if (bp != NULL)
1303 bp->enabled |= BP_TRAP;
1304 break;
1305 }
1306}
1307
1308/* Very cheap human name for vector lookup. */
1309static
1310const char *getvecname(unsigned long vec)
1311{
1312 char *ret;
1313
1314 switch (vec) {
1315 case 0x100: ret = "(System Reset)"; break;
1316 case 0x200: ret = "(Machine Check)"; break;
1317 case 0x300: ret = "(Data Access)"; break;
1318 case 0x380: ret = "(Data SLB Access)"; break;
1319 case 0x400: ret = "(Instruction Access)"; break;
1320 case 0x480: ret = "(Instruction SLB Access)"; break;
1321 case 0x500: ret = "(Hardware Interrupt)"; break;
1322 case 0x600: ret = "(Alignment)"; break;
1323 case 0x700: ret = "(Program Check)"; break;
1324 case 0x800: ret = "(FPU Unavailable)"; break;
1325 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001326 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1327 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 case 0xc00: ret = "(System Call)"; break;
1329 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001330 case 0xe40: ret = "(Emulation Assist)"; break;
1331 case 0xe60: ret = "(HMI)"; break;
1332 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 case 0xf00: ret = "(Performance Monitor)"; break;
1334 case 0xf20: ret = "(Altivec Unavailable)"; break;
1335 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001336 case 0x1500: ret = "(Denormalisation)"; break;
1337 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 default: ret = "";
1339 }
1340 return ret;
1341}
1342
1343static void get_function_bounds(unsigned long pc, unsigned long *startp,
1344 unsigned long *endp)
1345{
1346 unsigned long size, offset;
1347 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348
1349 *startp = *endp = 0;
1350 if (pc == 0)
1351 return;
1352 if (setjmp(bus_error_jmp) == 0) {
1353 catch_memory_errors = 1;
1354 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001355 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 if (name != NULL) {
1357 *startp = pc - offset;
1358 *endp = pc - offset + size;
1359 }
1360 sync();
1361 }
1362 catch_memory_errors = 0;
1363}
1364
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001365#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1366#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1367
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368static void xmon_show_stack(unsigned long sp, unsigned long lr,
1369 unsigned long pc)
1370{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001371 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 unsigned long ip;
1373 unsigned long newsp;
1374 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 struct pt_regs regs;
1376
Michael Ellerman0104cd62012-10-09 04:20:36 +00001377 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 if (sp < PAGE_OFFSET) {
1379 if (sp != 0)
1380 printf("SP (%lx) is in userspace\n", sp);
1381 break;
1382 }
1383
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001384 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 || !mread(sp, &newsp, sizeof(unsigned long))) {
1386 printf("Couldn't read stack frame at %lx\n", sp);
1387 break;
1388 }
1389
1390 /*
1391 * For the first stack frame, try to work out if
1392 * LR and/or the saved LR value in the bottommost
1393 * stack frame are valid.
1394 */
1395 if ((pc | lr) != 0) {
1396 unsigned long fnstart, fnend;
1397 unsigned long nextip;
1398 int printip = 1;
1399
1400 get_function_bounds(pc, &fnstart, &fnend);
1401 nextip = 0;
1402 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001403 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 sizeof(unsigned long));
1405 if (lr == ip) {
1406 if (lr < PAGE_OFFSET
1407 || (fnstart <= lr && lr < fnend))
1408 printip = 0;
1409 } else if (lr == nextip) {
1410 printip = 0;
1411 } else if (lr >= PAGE_OFFSET
1412 && !(fnstart <= lr && lr < fnend)) {
1413 printf("[link register ] ");
1414 xmon_print_symbol(lr, " ", "\n");
1415 }
1416 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001417 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 xmon_print_symbol(ip, " ", " (unreliable)\n");
1419 }
1420 pc = lr = 0;
1421
1422 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001423 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 xmon_print_symbol(ip, " ", "\n");
1425 }
1426
1427 /* Look for "regshere" marker to see if this is
1428 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001429 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001430 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001431 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 != sizeof(regs)) {
1433 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001434 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 break;
1436 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001437 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 getvecname(TRAP(&regs)));
1439 pc = regs.nip;
1440 lr = regs.link;
1441 xmon_print_symbol(pc, " ", "\n");
1442 }
1443
1444 if (newsp == 0)
1445 break;
1446
1447 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449}
1450
1451static void backtrace(struct pt_regs *excp)
1452{
1453 unsigned long sp;
1454
1455 if (scanhex(&sp))
1456 xmon_show_stack(sp, 0, 0);
1457 else
1458 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1459 scannl();
1460}
1461
1462static void print_bug_trap(struct pt_regs *regs)
1463{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001464#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001465 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 unsigned long addr;
1467
1468 if (regs->msr & MSR_PR)
1469 return; /* not in kernel */
1470 addr = regs->nip; /* address of trap instruction */
1471 if (addr < PAGE_OFFSET)
1472 return;
1473 bug = find_bug(regs->nip);
1474 if (bug == NULL)
1475 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001476 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 return;
1478
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001479#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001480 printf("kernel BUG at %s:%u!\n",
1481 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001482#else
1483 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1484#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001485#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486}
1487
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001488static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489{
1490 unsigned long trap;
1491
1492#ifdef CONFIG_SMP
1493 printf("cpu 0x%x: ", smp_processor_id());
1494#endif /* CONFIG_SMP */
1495
1496 trap = TRAP(fp);
1497 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1498 printf(" pc: ");
1499 xmon_print_symbol(fp->nip, ": ", "\n");
1500
1501 printf(" lr: ", fp->link);
1502 xmon_print_symbol(fp->link, ": ", "\n");
1503
1504 printf(" sp: %lx\n", fp->gpr[1]);
1505 printf(" msr: %lx\n", fp->msr);
1506
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001507 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 printf(" dar: %lx\n", fp->dar);
1509 if (trap != 0x380)
1510 printf(" dsisr: %lx\n", fp->dsisr);
1511 }
1512
1513 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001514#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001515 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1516 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001517#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 if (current) {
1519 printf(" pid = %ld, comm = %s\n",
1520 current->pid, current->comm);
1521 }
1522
1523 if (trap == 0x700)
1524 print_bug_trap(fp);
1525}
1526
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001527static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001529 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 unsigned long base;
1531 struct pt_regs regs;
1532
1533 if (scanhex(&base)) {
1534 if (setjmp(bus_error_jmp) == 0) {
1535 catch_memory_errors = 1;
1536 sync();
1537 regs = *(struct pt_regs *)base;
1538 sync();
1539 __delay(200);
1540 } else {
1541 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001542 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 base);
1544 return;
1545 }
1546 catch_memory_errors = 0;
1547 fp = &regs;
1548 }
1549
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001550#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 if (FULL_REGS(fp)) {
1552 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001553 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1555 } else {
1556 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001557 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1559 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001560#else
1561 for (n = 0; n < 32; ++n) {
1562 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1563 (n & 3) == 3? "\n": " ");
1564 if (n == 12 && !FULL_REGS(fp)) {
1565 printf("\n");
1566 break;
1567 }
1568 }
1569#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 printf("pc = ");
1571 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001572 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1573 printf("cfar= ");
1574 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 printf("lr = ");
1577 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001578 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1579 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001581 trap = TRAP(fp);
1582 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1583 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584}
1585
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001586static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587{
1588 int cmd;
1589 unsigned long nflush;
1590
1591 cmd = inchar();
1592 if (cmd != 'i')
1593 termch = cmd;
1594 scanhex((void *)&adrs);
1595 if (termch != '\n')
1596 termch = 0;
1597 nflush = 1;
1598 scanhex(&nflush);
1599 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1600 if (setjmp(bus_error_jmp) == 0) {
1601 catch_memory_errors = 1;
1602 sync();
1603
1604 if (cmd != 'i') {
1605 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1606 cflush((void *) adrs);
1607 } else {
1608 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1609 cinval((void *) adrs);
1610 }
1611 sync();
1612 /* wait a little while to see if we get a machine check */
1613 __delay(200);
1614 }
1615 catch_memory_errors = 0;
1616}
1617
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001618static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619read_spr(int n)
1620{
1621 unsigned int instrs[2];
1622 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001624#ifdef CONFIG_PPC64
1625 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 opd[0] = (unsigned long)instrs;
1628 opd[1] = 0;
1629 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001630 code = (unsigned long (*)(void)) opd;
1631#else
1632 code = (unsigned long (*)(void)) instrs;
1633#endif
1634
1635 /* mfspr r3,n; blr */
1636 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1637 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 store_inst(instrs);
1639 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
1641 if (setjmp(bus_error_jmp) == 0) {
1642 catch_memory_errors = 1;
1643 sync();
1644
1645 ret = code();
1646
1647 sync();
1648 /* wait a little while to see if we get a machine check */
1649 __delay(200);
1650 n = size;
1651 }
1652
1653 return ret;
1654}
1655
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001656static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657write_spr(int n, unsigned long val)
1658{
1659 unsigned int instrs[2];
1660 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001661#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 unsigned long opd[3];
1663
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 opd[0] = (unsigned long)instrs;
1665 opd[1] = 0;
1666 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001667 code = (unsigned long (*)(unsigned long)) opd;
1668#else
1669 code = (unsigned long (*)(unsigned long)) instrs;
1670#endif
1671
1672 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1673 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 store_inst(instrs);
1675 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676
1677 if (setjmp(bus_error_jmp) == 0) {
1678 catch_memory_errors = 1;
1679 sync();
1680
1681 code(val);
1682
1683 sync();
1684 /* wait a little while to see if we get a machine check */
1685 __delay(200);
1686 n = size;
1687 }
1688}
1689
1690static unsigned long regno;
1691extern char exc_prolog;
1692extern char dec_exc;
1693
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001694static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695{
1696 int cmd;
1697 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
1699 cmd = skipbl();
1700 if (cmd == '\n') {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001701 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 asm("mr %0,1" : "=r" (sp) :);
1703 asm("mr %0,2" : "=r" (toc) :);
1704
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001705 printf("msr = "REG" sprg0= "REG"\n",
1706 mfmsr(), mfspr(SPRN_SPRG0));
1707 printf("pvr = "REG" sprg1= "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001708 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001709 printf("dec = "REG" sprg2= "REG"\n",
1710 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1711 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1712 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
1714 return;
1715 }
1716
1717 scanhex(&regno);
1718 switch (cmd) {
1719 case 'w':
1720 val = read_spr(regno);
1721 scanhex(&val);
1722 write_spr(regno, val);
1723 /* fall through */
1724 case 'r':
1725 printf("spr %lx = %lx\n", regno, read_spr(regno));
1726 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 }
1728 scannl();
1729}
1730
1731/*
1732 * Stuff for reading and writing memory safely
1733 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001734static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735mread(unsigned long adrs, void *buf, int size)
1736{
1737 volatile int n;
1738 char *p, *q;
1739
1740 n = 0;
1741 if (setjmp(bus_error_jmp) == 0) {
1742 catch_memory_errors = 1;
1743 sync();
1744 p = (char *)adrs;
1745 q = (char *)buf;
1746 switch (size) {
1747 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001748 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 break;
1750 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001751 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 break;
1753 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001754 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 break;
1756 default:
1757 for( ; n < size; ++n) {
1758 *q++ = *p++;
1759 sync();
1760 }
1761 }
1762 sync();
1763 /* wait a little while to see if we get a machine check */
1764 __delay(200);
1765 n = size;
1766 }
1767 catch_memory_errors = 0;
1768 return n;
1769}
1770
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001771static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772mwrite(unsigned long adrs, void *buf, int size)
1773{
1774 volatile int n;
1775 char *p, *q;
1776
1777 n = 0;
1778 if (setjmp(bus_error_jmp) == 0) {
1779 catch_memory_errors = 1;
1780 sync();
1781 p = (char *) adrs;
1782 q = (char *) buf;
1783 switch (size) {
1784 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001785 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 break;
1787 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001788 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 break;
1790 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001791 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 break;
1793 default:
1794 for ( ; n < size; ++n) {
1795 *p++ = *q++;
1796 sync();
1797 }
1798 }
1799 sync();
1800 /* wait a little while to see if we get a machine check */
1801 __delay(200);
1802 n = size;
1803 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10001804 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 }
1806 catch_memory_errors = 0;
1807 return n;
1808}
1809
1810static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001811static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812static char *fault_chars[] = { "--", "**", "##" };
1813
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001814static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001816 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 switch (TRAP(regs)) {
1818 case 0x200:
1819 fault_type = 0;
1820 break;
1821 case 0x300:
1822 case 0x380:
1823 fault_type = 1;
1824 break;
1825 default:
1826 fault_type = 2;
1827 }
1828
1829 longjmp(bus_error_jmp, 1);
1830
1831 return 0;
1832}
1833
1834#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1835
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001836static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837byterev(unsigned char *val, int size)
1838{
1839 int t;
1840
1841 switch (size) {
1842 case 2:
1843 SWAP(val[0], val[1], t);
1844 break;
1845 case 4:
1846 SWAP(val[0], val[3], t);
1847 SWAP(val[1], val[2], t);
1848 break;
1849 case 8: /* is there really any use for this? */
1850 SWAP(val[0], val[7], t);
1851 SWAP(val[1], val[6], t);
1852 SWAP(val[2], val[5], t);
1853 SWAP(val[3], val[4], t);
1854 break;
1855 }
1856}
1857
1858static int brev;
1859static int mnoread;
1860
Michael Ellermane3bc8042012-08-23 22:09:13 +00001861static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 "Memory examine command usage:\n"
1863 "m [addr] [flags] examine/change memory\n"
1864 " addr is optional. will start where left off.\n"
1865 " flags may include chars from this set:\n"
1866 " b modify by bytes (default)\n"
1867 " w modify by words (2 byte)\n"
1868 " l modify by longs (4 byte)\n"
1869 " d modify by doubleword (8 byte)\n"
1870 " r toggle reverse byte order mode\n"
1871 " n do not read memory (for i/o spaces)\n"
1872 " . ok to read (default)\n"
1873 "NOTE: flags are saved as defaults\n"
1874 "";
1875
Michael Ellermane3bc8042012-08-23 22:09:13 +00001876static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 "Memory examine subcommands:\n"
1878 " hexval write this val to current location\n"
1879 " 'string' write chars from string to this location\n"
1880 " ' increment address\n"
1881 " ^ decrement address\n"
1882 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1883 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1884 " ` clear no-read flag\n"
1885 " ; stay at this addr\n"
1886 " v change to byte mode\n"
1887 " w change to word (2 byte) mode\n"
1888 " l change to long (4 byte) mode\n"
1889 " u change to doubleword (8 byte) mode\n"
1890 " m addr change current addr\n"
1891 " n toggle no-read flag\n"
1892 " r toggle byte reverse flag\n"
1893 " < count back up count bytes\n"
1894 " > count skip forward count bytes\n"
1895 " x exit this mode\n"
1896 "";
1897
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001898static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899memex(void)
1900{
1901 int cmd, inc, i, nslash;
1902 unsigned long n;
1903 unsigned char val[16];
1904
1905 scanhex((void *)&adrs);
1906 cmd = skipbl();
1907 if (cmd == '?') {
1908 printf(memex_help_string);
1909 return;
1910 } else {
1911 termch = cmd;
1912 }
1913 last_cmd = "m\n";
1914 while ((cmd = skipbl()) != '\n') {
1915 switch( cmd ){
1916 case 'b': size = 1; break;
1917 case 'w': size = 2; break;
1918 case 'l': size = 4; break;
1919 case 'd': size = 8; break;
1920 case 'r': brev = !brev; break;
1921 case 'n': mnoread = 1; break;
1922 case '.': mnoread = 0; break;
1923 }
1924 }
1925 if( size <= 0 )
1926 size = 1;
1927 else if( size > 8 )
1928 size = 8;
1929 for(;;){
1930 if (!mnoread)
1931 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001932 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 if (!mnoread) {
1934 if (brev)
1935 byterev(val, size);
1936 putchar(' ');
1937 for (i = 0; i < n; ++i)
1938 printf("%.2x", val[i]);
1939 for (; i < size; ++i)
1940 printf("%s", fault_chars[fault_type]);
1941 }
1942 putchar(' ');
1943 inc = size;
1944 nslash = 0;
1945 for(;;){
1946 if( scanhex(&n) ){
1947 for (i = 0; i < size; ++i)
1948 val[i] = n >> (i * 8);
1949 if (!brev)
1950 byterev(val, size);
1951 mwrite(adrs, val, size);
1952 inc = size;
1953 }
1954 cmd = skipbl();
1955 if (cmd == '\n')
1956 break;
1957 inc = 0;
1958 switch (cmd) {
1959 case '\'':
1960 for(;;){
1961 n = inchar();
1962 if( n == '\\' )
1963 n = bsesc();
1964 else if( n == '\'' )
1965 break;
1966 for (i = 0; i < size; ++i)
1967 val[i] = n >> (i * 8);
1968 if (!brev)
1969 byterev(val, size);
1970 mwrite(adrs, val, size);
1971 adrs += size;
1972 }
1973 adrs -= size;
1974 inc = size;
1975 break;
1976 case ',':
1977 adrs += size;
1978 break;
1979 case '.':
1980 mnoread = 0;
1981 break;
1982 case ';':
1983 break;
1984 case 'x':
1985 case EOF:
1986 scannl();
1987 return;
1988 case 'b':
1989 case 'v':
1990 size = 1;
1991 break;
1992 case 'w':
1993 size = 2;
1994 break;
1995 case 'l':
1996 size = 4;
1997 break;
1998 case 'u':
1999 size = 8;
2000 break;
2001 case '^':
2002 adrs -= size;
2003 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 case '/':
2005 if (nslash > 0)
2006 adrs -= 1 << nslash;
2007 else
2008 nslash = 0;
2009 nslash += 4;
2010 adrs += 1 << nslash;
2011 break;
2012 case '\\':
2013 if (nslash < 0)
2014 adrs += 1 << -nslash;
2015 else
2016 nslash = 0;
2017 nslash -= 4;
2018 adrs -= 1 << -nslash;
2019 break;
2020 case 'm':
2021 scanhex((void *)&adrs);
2022 break;
2023 case 'n':
2024 mnoread = 1;
2025 break;
2026 case 'r':
2027 brev = !brev;
2028 break;
2029 case '<':
2030 n = size;
2031 scanhex(&n);
2032 adrs -= n;
2033 break;
2034 case '>':
2035 n = size;
2036 scanhex(&n);
2037 adrs += n;
2038 break;
2039 case '?':
2040 printf(memex_subcmd_help_string);
2041 break;
2042 }
2043 }
2044 adrs += inc;
2045 }
2046}
2047
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002048static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049bsesc(void)
2050{
2051 int c;
2052
2053 c = inchar();
2054 switch( c ){
2055 case 'n': c = '\n'; break;
2056 case 'r': c = '\r'; break;
2057 case 'b': c = '\b'; break;
2058 case 't': c = '\t'; break;
2059 }
2060 return c;
2061}
2062
Olaf Hering7e5b5932006-03-08 20:40:28 +01002063static void xmon_rawdump (unsigned long adrs, long ndump)
2064{
2065 long n, m, r, nr;
2066 unsigned char temp[16];
2067
2068 for (n = ndump; n > 0;) {
2069 r = n < 16? n: 16;
2070 nr = mread(adrs, temp, r);
2071 adrs += nr;
2072 for (m = 0; m < r; ++m) {
2073 if (m < nr)
2074 printf("%.2x", temp[m]);
2075 else
2076 printf("%s", fault_chars[fault_type]);
2077 }
2078 n -= r;
2079 if (nr < r)
2080 break;
2081 }
2082 printf("\n");
2083}
2084
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002085#ifdef CONFIG_PPC64
2086static void dump_one_paca(int cpu)
2087{
2088 struct paca_struct *p;
2089
2090 if (setjmp(bus_error_jmp) != 0) {
2091 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2092 return;
2093 }
2094
2095 catch_memory_errors = 1;
2096 sync();
2097
2098 p = &paca[cpu];
2099
2100 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2101
2102 printf(" %-*s = %s\n", 16, "possible", cpu_possible(cpu) ? "yes" : "no");
2103 printf(" %-*s = %s\n", 16, "present", cpu_present(cpu) ? "yes" : "no");
2104 printf(" %-*s = %s\n", 16, "online", cpu_online(cpu) ? "yes" : "no");
2105
2106#define DUMP(paca, name, format) \
2107 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 16, #name, 18, paca->name, \
2108 offsetof(struct paca_struct, name));
2109
2110 DUMP(p, lock_token, "x");
2111 DUMP(p, paca_index, "x");
2112 DUMP(p, kernel_toc, "lx");
2113 DUMP(p, kernelbase, "lx");
2114 DUMP(p, kernel_msr, "lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002115 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302116#ifdef CONFIG_PPC_BOOK3S_64
2117 DUMP(p, mc_emergency_sp, "p");
2118 DUMP(p, in_mce, "x");
2119#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002120 DUMP(p, data_offset, "lx");
2121 DUMP(p, hw_cpu_id, "x");
2122 DUMP(p, cpu_start, "x");
2123 DUMP(p, kexec_state, "x");
2124 DUMP(p, __current, "p");
2125 DUMP(p, kstack, "lx");
2126 DUMP(p, stab_rr, "lx");
2127 DUMP(p, saved_r1, "lx");
2128 DUMP(p, trap_save, "x");
2129 DUMP(p, soft_enabled, "x");
2130 DUMP(p, irq_happened, "x");
2131 DUMP(p, io_sync, "x");
2132 DUMP(p, irq_work_pending, "x");
2133 DUMP(p, nap_state_lost, "x");
2134
2135#undef DUMP
2136
2137 catch_memory_errors = 0;
2138 sync();
2139}
2140
2141static void dump_all_pacas(void)
2142{
2143 int cpu;
2144
2145 if (num_possible_cpus() == 0) {
2146 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2147 return;
2148 }
2149
2150 for_each_possible_cpu(cpu)
2151 dump_one_paca(cpu);
2152}
2153
2154static void dump_pacas(void)
2155{
2156 unsigned long num;
2157 int c;
2158
2159 c = inchar();
2160 if (c == 'a') {
2161 dump_all_pacas();
2162 return;
2163 }
2164
2165 termch = c; /* Put c back, it wasn't 'a' */
2166
2167 if (scanhex(&num))
2168 dump_one_paca(num);
2169 else
2170 dump_one_paca(xmon_owner);
2171}
2172#endif
2173
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002174static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175dump(void)
2176{
2177 int c;
2178
2179 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002180
2181#ifdef CONFIG_PPC64
2182 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002183 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002184 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002185 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002186 return;
2187 }
2188#endif
2189
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2191 termch = c;
2192 scanhex((void *)&adrs);
2193 if (termch != '\n')
2194 termch = 0;
2195 if (c == 'i') {
2196 scanhex(&nidump);
2197 if (nidump == 0)
2198 nidump = 16;
2199 else if (nidump > MAX_DUMP)
2200 nidump = MAX_DUMP;
2201 adrs += ppc_inst_dump(adrs, nidump, 1);
2202 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002203 } else if (c == 'l') {
2204 dump_log_buf();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002205 } else if (c == 'r') {
2206 scanhex(&ndump);
2207 if (ndump == 0)
2208 ndump = 64;
2209 xmon_rawdump(adrs, ndump);
2210 adrs += ndump;
2211 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 } else {
2213 scanhex(&ndump);
2214 if (ndump == 0)
2215 ndump = 64;
2216 else if (ndump > MAX_DUMP)
2217 ndump = MAX_DUMP;
2218 prdump(adrs, ndump);
2219 adrs += ndump;
2220 last_cmd = "d\n";
2221 }
2222}
2223
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002224static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225prdump(unsigned long adrs, long ndump)
2226{
2227 long n, m, c, r, nr;
2228 unsigned char temp[16];
2229
2230 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002231 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 putchar(' ');
2233 r = n < 16? n: 16;
2234 nr = mread(adrs, temp, r);
2235 adrs += nr;
2236 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002237 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002238 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 if (m < nr)
2240 printf("%.2x", temp[m]);
2241 else
2242 printf("%s", fault_chars[fault_type]);
2243 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002244 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002245 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002246 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 printf(" |");
2250 for (m = 0; m < r; ++m) {
2251 if (m < nr) {
2252 c = temp[m];
2253 putchar(' ' <= c && c <= '~'? c: '.');
2254 } else
2255 putchar(' ');
2256 }
2257 n -= r;
2258 for (; m < 16; ++m)
2259 putchar(' ');
2260 printf("|\n");
2261 if (nr < r)
2262 break;
2263 }
2264}
2265
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002266typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2267
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002268static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002269generic_inst_dump(unsigned long adr, long count, int praddr,
2270 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271{
2272 int nr, dotted;
2273 unsigned long first_adr;
2274 unsigned long inst, last_inst = 0;
2275 unsigned char val[4];
2276
2277 dotted = 0;
2278 for (first_adr = adr; count > 0; --count, adr += 4) {
2279 nr = mread(adr, val, 4);
2280 if (nr == 0) {
2281 if (praddr) {
2282 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002283 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 }
2285 break;
2286 }
2287 inst = GETWORD(val);
2288 if (adr > first_adr && inst == last_inst) {
2289 if (!dotted) {
2290 printf(" ...\n");
2291 dotted = 1;
2292 }
2293 continue;
2294 }
2295 dotted = 0;
2296 last_inst = inst;
2297 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002298 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002300 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 printf("\n");
2302 }
2303 return adr - first_adr;
2304}
2305
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002306static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002307ppc_inst_dump(unsigned long adr, long count, int praddr)
2308{
2309 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2310}
2311
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312void
2313print_address(unsigned long addr)
2314{
2315 xmon_print_symbol(addr, "\t# ", "");
2316}
2317
Vinay Sridharf312deb2009-05-14 23:13:07 +00002318void
2319dump_log_buf(void)
2320{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002321 struct kmsg_dumper dumper = { .active = 1 };
2322 unsigned char buf[128];
2323 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002324
Michael Ellermane3bc8042012-08-23 22:09:13 +00002325 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002326 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002327 return;
2328 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002329
Michael Ellermane3bc8042012-08-23 22:09:13 +00002330 catch_memory_errors = 1;
2331 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002332
Michael Ellermanca5dd392012-08-23 22:09:12 +00002333 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002334 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002335 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2336 buf[len] = '\0';
2337 printf("%s", buf);
2338 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002339 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002340
Michael Ellermane3bc8042012-08-23 22:09:13 +00002341 sync();
2342 /* wait a little while to see if we get a machine check */
2343 __delay(200);
2344 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002345}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346
2347/*
2348 * Memory operations - move, set, print differences
2349 */
2350static unsigned long mdest; /* destination address */
2351static unsigned long msrc; /* source address */
2352static unsigned long mval; /* byte value to set memory to */
2353static unsigned long mcount; /* # bytes to affect */
2354static unsigned long mdiffs; /* max # differences to print */
2355
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002356static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357memops(int cmd)
2358{
2359 scanhex((void *)&mdest);
2360 if( termch != '\n' )
2361 termch = 0;
2362 scanhex((void *)(cmd == 's'? &mval: &msrc));
2363 if( termch != '\n' )
2364 termch = 0;
2365 scanhex((void *)&mcount);
2366 switch( cmd ){
2367 case 'm':
2368 memmove((void *)mdest, (void *)msrc, mcount);
2369 break;
2370 case 's':
2371 memset((void *)mdest, mval, mcount);
2372 break;
2373 case 'd':
2374 if( termch != '\n' )
2375 termch = 0;
2376 scanhex((void *)&mdiffs);
2377 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2378 break;
2379 }
2380}
2381
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002382static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2384{
2385 unsigned n, prt;
2386
2387 prt = 0;
2388 for( n = nb; n > 0; --n )
2389 if( *p1++ != *p2++ )
2390 if( ++prt <= maxpr )
2391 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2392 p1[-1], p2 - 1, p2[-1]);
2393 if( prt > maxpr )
2394 printf("Total of %d differences\n", prt);
2395}
2396
2397static unsigned mend;
2398static unsigned mask;
2399
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002400static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401memlocate(void)
2402{
2403 unsigned a, n;
2404 unsigned char val[4];
2405
2406 last_cmd = "ml";
2407 scanhex((void *)&mdest);
2408 if (termch != '\n') {
2409 termch = 0;
2410 scanhex((void *)&mend);
2411 if (termch != '\n') {
2412 termch = 0;
2413 scanhex((void *)&mval);
2414 mask = ~0;
2415 if (termch != '\n') termch = 0;
2416 scanhex((void *)&mask);
2417 }
2418 }
2419 n = 0;
2420 for (a = mdest; a < mend; a += 4) {
2421 if (mread(a, val, 4) == 4
2422 && ((GETWORD(val) ^ mval) & mask) == 0) {
2423 printf("%.16x: %.16x\n", a, GETWORD(val));
2424 if (++n >= 10)
2425 break;
2426 }
2427 }
2428}
2429
2430static unsigned long mskip = 0x1000;
2431static unsigned long mlim = 0xffffffff;
2432
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002433static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434memzcan(void)
2435{
2436 unsigned char v;
2437 unsigned a;
2438 int ok, ook;
2439
2440 scanhex(&mdest);
2441 if (termch != '\n') termch = 0;
2442 scanhex(&mskip);
2443 if (termch != '\n') termch = 0;
2444 scanhex(&mlim);
2445 ook = 0;
2446 for (a = mdest; a < mlim; a += mskip) {
2447 ok = mread(a, &v, 1);
2448 if (ok && !ook) {
2449 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 } else if (!ok && ook)
2451 printf("%.8x\n", a - mskip);
2452 ook = ok;
2453 if (a + mskip < a)
2454 break;
2455 }
2456 if (ook)
2457 printf("%.8x\n", a - mskip);
2458}
2459
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002460static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002461{
2462 unsigned long args[8];
2463 unsigned long ret;
2464 int i;
2465 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2466 unsigned long, unsigned long, unsigned long,
2467 unsigned long, unsigned long, unsigned long);
2468 callfunc_t func;
2469
2470 if (!scanhex(&adrs))
2471 return;
2472 if (termch != '\n')
2473 termch = 0;
2474 for (i = 0; i < 8; ++i)
2475 args[i] = 0;
2476 for (i = 0; i < 8; ++i) {
2477 if (!scanhex(&args[i]) || termch == '\n')
2478 break;
2479 termch = 0;
2480 }
2481 func = (callfunc_t) adrs;
2482 ret = 0;
2483 if (setjmp(bus_error_jmp) == 0) {
2484 catch_memory_errors = 1;
2485 sync();
2486 ret = func(args[0], args[1], args[2], args[3],
2487 args[4], args[5], args[6], args[7]);
2488 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10002489 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002490 } else {
2491 printf("*** %x exception occurred\n", fault_except);
2492 }
2493 catch_memory_errors = 0;
2494}
2495
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496/* Input scanning routines */
2497int
2498skipbl(void)
2499{
2500 int c;
2501
2502 if( termch != 0 ){
2503 c = termch;
2504 termch = 0;
2505 } else
2506 c = inchar();
2507 while( c == ' ' || c == '\t' )
2508 c = inchar();
2509 return c;
2510}
2511
2512#define N_PTREGS 44
2513static char *regnames[N_PTREGS] = {
2514 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2515 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2516 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2517 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002518 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2519#ifdef CONFIG_PPC64
2520 "softe",
2521#else
2522 "mq",
2523#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 "trap", "dar", "dsisr", "res"
2525};
2526
2527int
2528scanhex(unsigned long *vp)
2529{
2530 int c, d;
2531 unsigned long v;
2532
2533 c = skipbl();
2534 if (c == '%') {
2535 /* parse register name */
2536 char regname[8];
2537 int i;
2538
2539 for (i = 0; i < sizeof(regname) - 1; ++i) {
2540 c = inchar();
2541 if (!isalnum(c)) {
2542 termch = c;
2543 break;
2544 }
2545 regname[i] = c;
2546 }
2547 regname[i] = 0;
2548 for (i = 0; i < N_PTREGS; ++i) {
2549 if (strcmp(regnames[i], regname) == 0) {
2550 if (xmon_regs == NULL) {
2551 printf("regs not available\n");
2552 return 0;
2553 }
2554 *vp = ((unsigned long *)xmon_regs)[i];
2555 return 1;
2556 }
2557 }
2558 printf("invalid register name '%%%s'\n", regname);
2559 return 0;
2560 }
2561
2562 /* skip leading "0x" if any */
2563
2564 if (c == '0') {
2565 c = inchar();
2566 if (c == 'x') {
2567 c = inchar();
2568 } else {
2569 d = hexdigit(c);
2570 if (d == EOF) {
2571 termch = c;
2572 *vp = 0;
2573 return 1;
2574 }
2575 }
2576 } else if (c == '$') {
2577 int i;
2578 for (i=0; i<63; i++) {
2579 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02002580 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 termch = c;
2582 break;
2583 }
2584 tmpstr[i] = c;
2585 }
2586 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002587 *vp = 0;
2588 if (setjmp(bus_error_jmp) == 0) {
2589 catch_memory_errors = 1;
2590 sync();
2591 *vp = kallsyms_lookup_name(tmpstr);
2592 sync();
2593 }
2594 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 if (!(*vp)) {
2596 printf("unknown symbol '%s'\n", tmpstr);
2597 return 0;
2598 }
2599 return 1;
2600 }
2601
2602 d = hexdigit(c);
2603 if (d == EOF) {
2604 termch = c;
2605 return 0;
2606 }
2607 v = 0;
2608 do {
2609 v = (v << 4) + d;
2610 c = inchar();
2611 d = hexdigit(c);
2612 } while (d != EOF);
2613 termch = c;
2614 *vp = v;
2615 return 1;
2616}
2617
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002618static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619scannl(void)
2620{
2621 int c;
2622
2623 c = termch;
2624 termch = 0;
2625 while( c != '\n' )
2626 c = inchar();
2627}
2628
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002629static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630{
2631 if( '0' <= c && c <= '9' )
2632 return c - '0';
2633 if( 'A' <= c && c <= 'F' )
2634 return c - ('A' - 10);
2635 if( 'a' <= c && c <= 'f' )
2636 return c - ('a' - 10);
2637 return EOF;
2638}
2639
2640void
2641getstring(char *s, int size)
2642{
2643 int c;
2644
2645 c = skipbl();
2646 do {
2647 if( size > 1 ){
2648 *s++ = c;
2649 --size;
2650 }
2651 c = inchar();
2652 } while( c != ' ' && c != '\t' && c != '\n' );
2653 termch = c;
2654 *s = 0;
2655}
2656
2657static char line[256];
2658static char *lineptr;
2659
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002660static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661flush_input(void)
2662{
2663 lineptr = NULL;
2664}
2665
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002666static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667inchar(void)
2668{
2669 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002670 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 lineptr = NULL;
2672 return EOF;
2673 }
2674 lineptr = line;
2675 }
2676 return *lineptr++;
2677}
2678
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002679static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680take_input(char *str)
2681{
2682 lineptr = str;
2683}
2684
2685
2686static void
2687symbol_lookup(void)
2688{
2689 int type = inchar();
2690 unsigned long addr;
2691 static char tmp[64];
2692
2693 switch (type) {
2694 case 'a':
2695 if (scanhex(&addr))
2696 xmon_print_symbol(addr, ": ", "\n");
2697 termch = 0;
2698 break;
2699 case 's':
2700 getstring(tmp, 64);
2701 if (setjmp(bus_error_jmp) == 0) {
2702 catch_memory_errors = 1;
2703 sync();
2704 addr = kallsyms_lookup_name(tmp);
2705 if (addr)
2706 printf("%s: %lx\n", tmp, addr);
2707 else
2708 printf("Symbol '%s' not found.\n", tmp);
2709 sync();
2710 }
2711 catch_memory_errors = 0;
2712 termch = 0;
2713 break;
2714 }
2715}
2716
2717
2718/* Print an address in numeric and symbolic form (if possible) */
2719static void xmon_print_symbol(unsigned long address, const char *mid,
2720 const char *after)
2721{
2722 char *modname;
2723 const char *name = NULL;
2724 unsigned long offset, size;
2725
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002726 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 if (setjmp(bus_error_jmp) == 0) {
2728 catch_memory_errors = 1;
2729 sync();
2730 name = kallsyms_lookup(address, &size, &offset, &modname,
2731 tmpstr);
2732 sync();
2733 /* wait a little while to see if we get a machine check */
2734 __delay(200);
2735 }
2736
2737 catch_memory_errors = 0;
2738
2739 if (name) {
2740 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2741 if (modname)
2742 printf(" [%s]", modname);
2743 }
2744 printf("%s", after);
2745}
2746
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002747#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10002748void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749{
2750 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05302751 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11002752 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
Michael Ellerman736256e2014-05-26 21:02:14 +10002754 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755
Michael Neuling584f8b72007-12-06 17:24:48 +11002756 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002757 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2758 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Anshuman Khandual8218a302015-07-29 12:40:04 +05302759 if (esid || vsid) {
will schmidtb3b95952007-12-07 08:22:23 +11002760 printf("%02d %016lx %016lx", i, esid, vsid);
Anshuman Khandual8218a302015-07-29 12:40:04 +05302761 if (esid & SLB_ESID_V) {
will schmidtb3b95952007-12-07 08:22:23 +11002762 llp = vsid & SLB_VSID_LLP;
2763 if (vsid & SLB_VSID_B_1T) {
2764 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2765 GET_ESID_1T(esid),
2766 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2767 llp);
2768 } else {
2769 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2770 GET_ESID(esid),
2771 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2772 llp);
2773 }
2774 } else
2775 printf("\n");
2776 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 }
2778}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002779#endif
2780
2781#ifdef CONFIG_PPC_STD_MMU_32
2782void dump_segments(void)
2783{
2784 int i;
2785
2786 printf("sr0-15 =");
2787 for (i = 0; i < 16; ++i)
2788 printf(" %x", mfsrin(i));
2789 printf("\n");
2790}
2791#endif
2792
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002793#ifdef CONFIG_44x
2794static void dump_tlb_44x(void)
2795{
2796 int i;
2797
2798 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2799 unsigned long w0,w1,w2;
2800 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2801 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2802 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2803 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2804 if (w0 & PPC44x_TLB_VALID) {
2805 printf("V %08x -> %01x%08x %c%c%c%c%c",
2806 w0 & PPC44x_TLB_EPN_MASK,
2807 w1 & PPC44x_TLB_ERPN_MASK,
2808 w1 & PPC44x_TLB_RPN_MASK,
2809 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2810 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2811 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2812 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2813 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2814 }
2815 printf("\n");
2816 }
2817}
2818#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002819
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002820#ifdef CONFIG_PPC_BOOK3E
2821static void dump_tlb_book3e(void)
2822{
2823 u32 mmucfg, pidmask, lpidmask;
2824 u64 ramask;
2825 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2826 int mmu_version;
2827 static const char *pgsz_names[] = {
2828 " 1K",
2829 " 2K",
2830 " 4K",
2831 " 8K",
2832 " 16K",
2833 " 32K",
2834 " 64K",
2835 "128K",
2836 "256K",
2837 "512K",
2838 " 1M",
2839 " 2M",
2840 " 4M",
2841 " 8M",
2842 " 16M",
2843 " 32M",
2844 " 64M",
2845 "128M",
2846 "256M",
2847 "512M",
2848 " 1G",
2849 " 2G",
2850 " 4G",
2851 " 8G",
2852 " 16G",
2853 " 32G",
2854 " 64G",
2855 "128G",
2856 "256G",
2857 "512G",
2858 " 1T",
2859 " 2T",
2860 };
2861
2862 /* Gather some infos about the MMU */
2863 mmucfg = mfspr(SPRN_MMUCFG);
2864 mmu_version = (mmucfg & 3) + 1;
2865 ntlbs = ((mmucfg >> 2) & 3) + 1;
2866 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2867 lpidsz = (mmucfg >> 24) & 0xf;
2868 rasz = (mmucfg >> 16) & 0x7f;
2869 if ((mmu_version > 1) && (mmucfg & 0x10000))
2870 lrat = 1;
2871 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2872 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2873 pidmask = (1ul << pidsz) - 1;
2874 lpidmask = (1ul << lpidsz) - 1;
2875 ramask = (1ull << rasz) - 1;
2876
2877 for (tlb = 0; tlb < ntlbs; tlb++) {
2878 u32 tlbcfg;
2879 int nent, assoc, new_cc = 1;
2880 printf("TLB %d:\n------\n", tlb);
2881 switch(tlb) {
2882 case 0:
2883 tlbcfg = mfspr(SPRN_TLB0CFG);
2884 break;
2885 case 1:
2886 tlbcfg = mfspr(SPRN_TLB1CFG);
2887 break;
2888 case 2:
2889 tlbcfg = mfspr(SPRN_TLB2CFG);
2890 break;
2891 case 3:
2892 tlbcfg = mfspr(SPRN_TLB3CFG);
2893 break;
2894 default:
2895 printf("Unsupported TLB number !\n");
2896 continue;
2897 }
2898 nent = tlbcfg & 0xfff;
2899 assoc = (tlbcfg >> 24) & 0xff;
2900 for (i = 0; i < nent; i++) {
2901 u32 mas0 = MAS0_TLBSEL(tlb);
2902 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
2903 u64 mas2 = 0;
2904 u64 mas7_mas3;
2905 int esel = i, cc = i;
2906
2907 if (assoc != 0) {
2908 cc = i / assoc;
2909 esel = i % assoc;
2910 mas2 = cc * 0x1000;
2911 }
2912
2913 mas0 |= MAS0_ESEL(esel);
2914 mtspr(SPRN_MAS0, mas0);
2915 mtspr(SPRN_MAS1, mas1);
2916 mtspr(SPRN_MAS2, mas2);
2917 asm volatile("tlbre 0,0,0" : : : "memory");
2918 mas1 = mfspr(SPRN_MAS1);
2919 mas2 = mfspr(SPRN_MAS2);
2920 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
2921 if (assoc && (i % assoc) == 0)
2922 new_cc = 1;
2923 if (!(mas1 & MAS1_VALID))
2924 continue;
2925 if (assoc == 0)
2926 printf("%04x- ", i);
2927 else if (new_cc)
2928 printf("%04x-%c", cc, 'A' + esel);
2929 else
2930 printf(" |%c", 'A' + esel);
2931 new_cc = 0;
2932 printf(" %016llx %04x %s %c%c AS%c",
2933 mas2 & ~0x3ffull,
2934 (mas1 >> 16) & 0x3fff,
2935 pgsz_names[(mas1 >> 7) & 0x1f],
2936 mas1 & MAS1_IND ? 'I' : ' ',
2937 mas1 & MAS1_IPROT ? 'P' : ' ',
2938 mas1 & MAS1_TS ? '1' : '0');
2939 printf(" %c%c%c%c%c%c%c",
2940 mas2 & MAS2_X0 ? 'a' : ' ',
2941 mas2 & MAS2_X1 ? 'v' : ' ',
2942 mas2 & MAS2_W ? 'w' : ' ',
2943 mas2 & MAS2_I ? 'i' : ' ',
2944 mas2 & MAS2_M ? 'm' : ' ',
2945 mas2 & MAS2_G ? 'g' : ' ',
2946 mas2 & MAS2_E ? 'e' : ' ');
2947 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
2948 if (mas1 & MAS1_IND)
2949 printf(" %s\n",
2950 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
2951 else
2952 printf(" U%c%c%c S%c%c%c\n",
2953 mas7_mas3 & MAS3_UX ? 'x' : ' ',
2954 mas7_mas3 & MAS3_UW ? 'w' : ' ',
2955 mas7_mas3 & MAS3_UR ? 'r' : ' ',
2956 mas7_mas3 & MAS3_SX ? 'x' : ' ',
2957 mas7_mas3 & MAS3_SW ? 'w' : ' ',
2958 mas7_mas3 & MAS3_SR ? 'r' : ' ');
2959 }
2960 }
2961}
2962#endif /* CONFIG_PPC_BOOK3E */
2963
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002964static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965{
Olaf Heringb13cfd172005-08-04 19:26:42 +02002966 if (enable) {
2967 __debugger = xmon;
2968 __debugger_ipi = xmon_ipi;
2969 __debugger_bpt = xmon_bpt;
2970 __debugger_sstep = xmon_sstep;
2971 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00002972 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002973 __debugger_fault_handler = xmon_fault_handler;
2974 } else {
2975 __debugger = NULL;
2976 __debugger_ipi = NULL;
2977 __debugger_bpt = NULL;
2978 __debugger_sstep = NULL;
2979 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00002980 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002981 __debugger_fault_handler = NULL;
2982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002984
2985#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002986static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002987{
2988 /* ensure xmon is enabled */
2989 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002990 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002991}
2992
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002993static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002994 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07002995 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002996 .action_msg = "Entering xmon",
2997};
2998
2999static int __init setup_xmon_sysrq(void)
3000{
3001 register_sysrq_key('x', &sysrq_xmon_op);
3002 return 0;
3003}
3004__initcall(setup_xmon_sysrq);
3005#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003006
Olaf Heringf5e6a282007-06-24 16:57:08 +10003007static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10003008
3009static int __init early_parse_xmon(char *p)
3010{
3011 if (!p || strncmp(p, "early", 5) == 0) {
3012 /* just "xmon" is equivalent to "xmon=early" */
3013 xmon_init(1);
3014 xmon_early = 1;
3015 } else if (strncmp(p, "on", 2) == 0)
3016 xmon_init(1);
3017 else if (strncmp(p, "off", 3) == 0)
3018 xmon_off = 1;
3019 else if (strncmp(p, "nobt", 4) == 0)
3020 xmon_no_auto_backtrace = 1;
3021 else
3022 return 1;
3023
3024 return 0;
3025}
3026early_param("xmon", early_parse_xmon);
3027
3028void __init xmon_setup(void)
3029{
3030#ifdef CONFIG_XMON_DEFAULT
3031 if (!xmon_off)
3032 xmon_init(1);
3033#endif
3034 if (xmon_early)
3035 debugger(NULL);
3036}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003037
Arnd Bergmanne0555952006-11-27 19:18:55 +01003038#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003039
3040struct spu_info {
3041 struct spu *spu;
3042 u64 saved_mfc_sr1_RW;
3043 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003044 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003045 u8 stopped_ok;
3046};
3047
3048#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3049
3050static struct spu_info spu_info[XMON_NUM_SPUS];
3051
3052void xmon_register_spus(struct list_head *list)
3053{
3054 struct spu *spu;
3055
3056 list_for_each_entry(spu, list, full_list) {
3057 if (spu->number >= XMON_NUM_SPUS) {
3058 WARN_ON(1);
3059 continue;
3060 }
3061
3062 spu_info[spu->number].spu = spu;
3063 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003064 spu_info[spu->number].dump_addr = (unsigned long)
3065 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003066 }
3067}
3068
3069static void stop_spus(void)
3070{
3071 struct spu *spu;
3072 int i;
3073 u64 tmp;
3074
3075 for (i = 0; i < XMON_NUM_SPUS; i++) {
3076 if (!spu_info[i].spu)
3077 continue;
3078
3079 if (setjmp(bus_error_jmp) == 0) {
3080 catch_memory_errors = 1;
3081 sync();
3082
3083 spu = spu_info[i].spu;
3084
3085 spu_info[i].saved_spu_runcntl_RW =
3086 in_be32(&spu->problem->spu_runcntl_RW);
3087
3088 tmp = spu_mfc_sr1_get(spu);
3089 spu_info[i].saved_mfc_sr1_RW = tmp;
3090
3091 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3092 spu_mfc_sr1_set(spu, tmp);
3093
3094 sync();
3095 __delay(200);
3096
3097 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003098
3099 printf("Stopped spu %.2d (was %s)\n", i,
3100 spu_info[i].saved_spu_runcntl_RW ?
3101 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003102 } else {
3103 catch_memory_errors = 0;
3104 printf("*** Error stopping spu %.2d\n", i);
3105 }
3106 catch_memory_errors = 0;
3107 }
3108}
3109
3110static void restart_spus(void)
3111{
3112 struct spu *spu;
3113 int i;
3114
3115 for (i = 0; i < XMON_NUM_SPUS; i++) {
3116 if (!spu_info[i].spu)
3117 continue;
3118
3119 if (!spu_info[i].stopped_ok) {
3120 printf("*** Error, spu %d was not successfully stopped"
3121 ", not restarting\n", i);
3122 continue;
3123 }
3124
3125 if (setjmp(bus_error_jmp) == 0) {
3126 catch_memory_errors = 1;
3127 sync();
3128
3129 spu = spu_info[i].spu;
3130 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3131 out_be32(&spu->problem->spu_runcntl_RW,
3132 spu_info[i].saved_spu_runcntl_RW);
3133
3134 sync();
3135 __delay(200);
3136
3137 printf("Restarted spu %.2d\n", i);
3138 } else {
3139 catch_memory_errors = 0;
3140 printf("*** Error restarting spu %.2d\n", i);
3141 }
3142 catch_memory_errors = 0;
3143 }
3144}
3145
Michael Ellermana8984972006-10-24 18:31:28 +02003146#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003147#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003148do { \
3149 if (setjmp(bus_error_jmp) == 0) { \
3150 catch_memory_errors = 1; \
3151 sync(); \
3152 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003153 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003154 sync(); \
3155 __delay(200); \
3156 } else { \
3157 catch_memory_errors = 0; \
3158 printf(" %-*s = *** Error reading field.\n", \
3159 DUMP_WIDTH, #field); \
3160 } \
3161 catch_memory_errors = 0; \
3162} while (0)
3163
Michael Ellerman437a0702006-11-23 00:46:39 +01003164#define DUMP_FIELD(obj, format, field) \
3165 DUMP_VALUE(format, field, obj->field)
3166
Michael Ellermana8984972006-10-24 18:31:28 +02003167static void dump_spu_fields(struct spu *spu)
3168{
3169 printf("Dumping spu fields at address %p:\n", spu);
3170
3171 DUMP_FIELD(spu, "0x%x", number);
3172 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003173 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3174 DUMP_FIELD(spu, "0x%p", local_store);
3175 DUMP_FIELD(spu, "0x%lx", ls_size);
3176 DUMP_FIELD(spu, "0x%x", node);
3177 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003178 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003179 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003180 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3181 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003182 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3183 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3184 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3185 DUMP_FIELD(spu, "0x%x", slb_replace);
3186 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003187 DUMP_FIELD(spu, "0x%p", mm);
3188 DUMP_FIELD(spu, "0x%p", ctx);
3189 DUMP_FIELD(spu, "0x%p", rq);
3190 DUMP_FIELD(spu, "0x%p", timestamp);
3191 DUMP_FIELD(spu, "0x%lx", problem_phys);
3192 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003193 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3194 in_be32(&spu->problem->spu_runcntl_RW));
3195 DUMP_VALUE("0x%x", problem->spu_status_R,
3196 in_be32(&spu->problem->spu_status_R));
3197 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3198 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003199 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003200 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003201}
3202
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003203int
3204spu_inst_dump(unsigned long adr, long count, int praddr)
3205{
3206 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3207}
3208
3209static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003210{
3211 unsigned long offset, addr, ls_addr;
3212
3213 if (setjmp(bus_error_jmp) == 0) {
3214 catch_memory_errors = 1;
3215 sync();
3216 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3217 sync();
3218 __delay(200);
3219 } else {
3220 catch_memory_errors = 0;
3221 printf("*** Error: accessing spu info for spu %d\n", num);
3222 return;
3223 }
3224 catch_memory_errors = 0;
3225
3226 if (scanhex(&offset))
3227 addr = ls_addr + offset;
3228 else
3229 addr = spu_info[num].dump_addr;
3230
3231 if (addr >= ls_addr + LS_SIZE) {
3232 printf("*** Error: address outside of local store\n");
3233 return;
3234 }
3235
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003236 switch (subcmd) {
3237 case 'i':
3238 addr += spu_inst_dump(addr, 16, 1);
3239 last_cmd = "sdi\n";
3240 break;
3241 default:
3242 prdump(addr, 64);
3243 addr += 64;
3244 last_cmd = "sd\n";
3245 break;
3246 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003247
3248 spu_info[num].dump_addr = addr;
3249}
3250
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003251static int do_spu_cmd(void)
3252{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003253 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003254 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003255
3256 cmd = inchar();
3257 switch (cmd) {
3258 case 's':
3259 stop_spus();
3260 break;
3261 case 'r':
3262 restart_spus();
3263 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003264 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003265 subcmd = inchar();
3266 if (isxdigit(subcmd) || subcmd == '\n')
3267 termch = subcmd;
3268 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003269 scanhex(&num);
3270 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003271 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003272 return 0;
3273 }
3274
3275 switch (cmd) {
3276 case 'f':
3277 dump_spu_fields(spu_info[num].spu);
3278 break;
3279 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003280 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003281 break;
3282 }
3283
Michael Ellermana8984972006-10-24 18:31:28 +02003284 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003285 default:
3286 return -1;
3287 }
3288
3289 return 0;
3290}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003291#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003292static int do_spu_cmd(void)
3293{
3294 return -1;
3295}
3296#endif