blob: 47e195d66a9aad43273bc56369263750ee646833 [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
Andrew Donnellanfde93a02016-02-09 18:17:49 +110050#include <asm/opal.h>
51#include <asm/firmware.h>
52
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100053#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100055#include <asm/paca.h>
56#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Anshuman Khandual1ad7d702014-11-28 10:06:42 +053058#if defined(CONFIG_PPC_SPLPAR)
59#include <asm/plpar_wrappers.h>
60#else
61static inline long plapr_set_ciabr(unsigned long ciabr) {return 0; };
62#endif
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010065#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100068static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069static unsigned long xmon_taken = 1;
70static int xmon_owner;
71static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000072#else
73#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#endif /* CONFIG_SMP */
75
Anton Blanchard5be34922010-01-12 00:50:14 +000076static unsigned long in_xmon __read_mostly = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78static unsigned long adrs;
79static int size = 1;
80#define MAX_DUMP (128 * 1024)
81static unsigned long ndump = 64;
82static unsigned long nidump = 16;
83static unsigned long ncsum = 4096;
84static int termch;
85static char tmpstr[128];
86
Linus Torvalds1da177e2005-04-16 15:20:36 -070087static long bus_error_jmp[JMP_BUF_LEN];
88static int catch_memory_errors;
89static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
91/* Breakpoint stuff */
92struct bpt {
93 unsigned long address;
94 unsigned int instr[2];
95 atomic_t ref_count;
96 int enabled;
97 unsigned long pad;
98};
99
100/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100101#define BP_CIABR 1
102#define BP_TRAP 2
103#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105#define NBPTS 256
106static struct bpt bpts[NBPTS];
107static struct bpt dabr;
108static struct bpt *iabr;
109static unsigned bpinstr = 0x7fe00008; /* trap */
110
111#define BP_NUM(bp) ((bp) - bpts + 1)
112
113/* Prototypes */
114static int cmds(struct pt_regs *);
115static int mread(unsigned long, void *, int);
116static int mwrite(unsigned long, void *, int);
117static int handle_fault(struct pt_regs *);
118static void byterev(unsigned char *, int);
119static void memex(void);
120static int bsesc(void);
121static void dump(void);
122static void prdump(unsigned long, long);
123static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000124static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100125
126#ifdef CONFIG_PPC_POWERNV
127static void dump_opal_msglog(void);
128#else
129static inline void dump_opal_msglog(void)
130{
131 printf("Machine is not running OPAL firmware.\n");
132}
133#endif
134
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135static void backtrace(struct pt_regs *);
136static void excprint(struct pt_regs *);
137static void prregs(struct pt_regs *);
138static void memops(int);
139static void memlocate(void);
140static void memzcan(void);
141static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
142int skipbl(void);
143int scanhex(unsigned long *valp);
144static void scannl(void);
145static int hexdigit(int);
146void getstring(char *, int);
147static void flush_input(void);
148static int inchar(void);
149static void take_input(char *);
150static unsigned long read_spr(int);
151static void write_spr(int, unsigned long);
152static void super_regs(void);
153static void remove_bpts(void);
154static void insert_bpts(void);
155static void remove_cpu_bpts(void);
156static void insert_cpu_bpts(void);
157static struct bpt *at_breakpoint(unsigned long pc);
158static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
159static int do_step(struct pt_regs *);
160static void bpt_cmds(void);
161static void cacheflush(void);
162static int cpu_cmd(void);
163static void csum(void);
164static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000165static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166void dump_segments(void);
167static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200168static void xmon_show_stack(unsigned long sp, unsigned long lr,
169 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170static void xmon_print_symbol(unsigned long address, const char *mid,
171 const char *after);
172static const char *getvecname(unsigned long vec);
173
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200174static int do_spu_cmd(void);
175
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100176#ifdef CONFIG_44x
177static void dump_tlb_44x(void);
178#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000179#ifdef CONFIG_PPC_BOOK3E
180static void dump_tlb_book3e(void);
181#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100182
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000183static int xmon_no_auto_backtrace;
Olaf Hering26c8af52006-09-08 16:29:21 +0200184
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000185extern void xmon_enter(void);
186extern void xmon_leave(void);
187
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000188#ifdef CONFIG_PPC64
189#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000190#else
191#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000192#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100194#ifdef __LITTLE_ENDIAN__
195#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
196#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100198#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200static char *help_string = "\
201Commands:\n\
202 b show breakpoints\n\
203 bd set data breakpoint\n\
204 bi set instruction breakpoint\n\
205 bc clear breakpoint\n"
206#ifdef CONFIG_SMP
207 "\
208 c print cpus stopped in xmon\n\
209 c# try to switch to cpu number h (in hex)\n"
210#endif
211 "\
212 C checksum\n\
213 d dump bytes\n\
214 di dump instructions\n\
215 df dump float values\n\
216 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000217 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100218#ifdef CONFIG_PPC_POWERNV
219 "\
220 do dump the OPAL message log\n"
221#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000222#ifdef CONFIG_PPC64
223 "\
224 dp[#] dump paca for current cpu, or cpu #\n\
225 dpa dump paca for all possible cpus\n"
226#endif
227 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100228 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 e print exception information\n\
230 f flush cache\n\
231 la lookup symbol+offset of specified address\n\
232 ls lookup address of specified symbol\n\
233 m examine/change memory\n\
234 mm move a block of memory\n\
235 ms set a block of memory\n\
236 md compare two blocks of memory\n\
237 ml locate a block of memory\n\
238 mz zero a block of memory\n\
239 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000240 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200242 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100243#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200244" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200245 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100246 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900247 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100248 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200249#endif
250" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100253 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000254#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000255" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000256#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000257" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000258#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100259" u dump TLB\n"
260#endif
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000261" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100262" # n limit output to n lines per page (for dp, dpa, dl)\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000263" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 zh halt\n"
265;
266
267static struct pt_regs *xmon_regs;
268
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000269static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270{
271 asm volatile("sync; isync");
272}
273
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000274static inline void store_inst(void *p)
275{
276 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
277}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000279static inline void cflush(void *p)
280{
281 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
282}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000284static inline void cinval(void *p)
285{
286 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
287}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530289/**
290 * write_ciabr() - write the CIABR SPR
291 * @ciabr: The value to write.
292 *
293 * This function writes a value to the CIARB register either directly
294 * through mtspr instruction if the kernel is in HV privilege mode or
295 * call a hypervisor function to achieve the same in case the kernel
296 * is in supervisor privilege mode.
297 */
298static void write_ciabr(unsigned long ciabr)
299{
300 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
301 return;
302
303 if (cpu_has_feature(CPU_FTR_HVMODE)) {
304 mtspr(SPRN_CIABR, ciabr);
305 return;
306 }
307 plapr_set_ciabr(ciabr);
308}
309
310/**
311 * set_ciabr() - set the CIABR
312 * @addr: The value to set.
313 *
314 * This function sets the correct privilege value into the the HW
315 * breakpoint address before writing it up in the CIABR register.
316 */
317static void set_ciabr(unsigned long addr)
318{
319 addr &= ~CIABR_PRIV;
320
321 if (cpu_has_feature(CPU_FTR_HVMODE))
322 addr |= CIABR_PRIV_HYPER;
323 else
324 addr |= CIABR_PRIV_SUPER;
325 write_ciabr(addr);
326}
327
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328/*
329 * Disable surveillance (the service processor watchdog function)
330 * while we are in xmon.
331 * XXX we should re-enable it when we leave. :)
332 */
333#define SURVEILLANCE_TOKEN 9000
334
335static inline void disable_surveillance(void)
336{
337#ifdef CONFIG_PPC_PSERIES
338 /* Since this can't be a module, args should end up below 4GB. */
339 static struct rtas_args args;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100340 int token;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
342 /*
343 * At this point we have got all the cpus we can into
344 * xmon, so there is hopefully no other cpu calling RTAS
345 * at the moment, even though we don't take rtas.lock.
346 * If we did try to take rtas.lock there would be a
347 * real possibility of deadlock.
348 */
Michael Ellerman08eb1052015-11-24 22:26:09 +1100349 token = rtas_token("set-indicator");
350 if (token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100352
353 rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0);
354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355#endif /* CONFIG_PPC_PSERIES */
356}
357
358#ifdef CONFIG_SMP
359static int xmon_speaker;
360
361static void get_output_lock(void)
362{
363 int me = smp_processor_id() + 0x100;
364 int last_speaker = 0, prev;
365 long timeout;
366
367 if (xmon_speaker == me)
368 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100371 last_speaker = cmpxchg(&xmon_speaker, 0, me);
372 if (last_speaker == 0)
373 return;
374
Michael Ellerman15075892013-12-23 23:46:05 +1100375 /*
376 * Wait a full second for the lock, we might be on a slow
377 * console, but check every 100us.
378 */
379 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100381 if (--timeout > 0) {
382 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100384 }
385
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 /* hostile takeover */
387 prev = cmpxchg(&xmon_speaker, last_speaker, me);
388 if (prev == last_speaker)
389 return;
390 break;
391 }
392 }
393}
394
395static void release_output_lock(void)
396{
397 xmon_speaker = 0;
398}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000399
400int cpus_are_in_xmon(void)
401{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000402 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000403}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404#endif
405
Josh Boyerdaf8f402009-09-23 03:51:04 +0000406static inline int unrecoverable_excp(struct pt_regs *regs)
407{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000408#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000409 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000410 return 0;
411#else
412 return ((regs->msr & MSR_RI) == 0);
413#endif
414}
415
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000416static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417{
418 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 struct bpt *bp;
420 long recurse_jmp[JMP_BUF_LEN];
421 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100422 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423#ifdef CONFIG_SMP
424 int cpu;
425 int secondary;
426 unsigned long timeout;
427#endif
428
Anton Blanchardf13659e2007-03-21 01:48:34 +1100429 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000430 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
432 bp = in_breakpoint_table(regs->nip, &offset);
433 if (bp != NULL) {
434 regs->nip = bp->address + offset;
435 atomic_dec(&bp->ref_count);
436 }
437
438 remove_cpu_bpts();
439
440#ifdef CONFIG_SMP
441 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000442 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 get_output_lock();
444 excprint(regs);
445 printf("cpu 0x%x: Exception %lx %s in xmon, "
446 "returning to main loop\n",
447 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000448 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 longjmp(xmon_fault_jmp[cpu], 1);
450 }
451
452 if (setjmp(recurse_jmp) != 0) {
453 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000454 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 printf("xmon: WARNING: bad recursive fault "
456 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000457 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 goto waiting;
459 }
460 secondary = !(xmon_taken && cpu == xmon_owner);
461 goto cmdloop;
462 }
463
464 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
466 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000467 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000469 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 fromipi = 0;
471
472 if (!fromipi) {
473 get_output_lock();
474 excprint(regs);
475 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000476 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 cpu, BP_NUM(bp));
478 xmon_print_symbol(regs->nip, " ", ")\n");
479 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000480 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 printf("WARNING: exception is not recoverable, "
482 "can't continue\n");
483 release_output_lock();
484 }
485
Michael Ellermand2b496e2013-12-23 23:46:06 +1100486 cpumask_set_cpu(cpu, &cpus_in_xmon);
487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 waiting:
489 secondary = 1;
490 while (secondary && !xmon_gate) {
491 if (in_xmon == 0) {
492 if (fromipi)
493 goto leave;
494 secondary = test_and_set_bit(0, &in_xmon);
495 }
496 barrier();
497 }
498
499 if (!secondary && !xmon_gate) {
500 /* we are the first cpu to come in */
501 /* interrupt other cpu(s) */
502 int ncpus = num_online_cpus();
503
504 xmon_owner = cpu;
505 mb();
506 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000507 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 /* wait for other cpus to come in */
509 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000510 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 break;
512 barrier();
513 }
514 }
515 remove_bpts();
516 disable_surveillance();
517 /* for breakpoint or single step, print the current instr. */
518 if (bp || TRAP(regs) == 0xd00)
519 ppc_inst_dump(regs->nip, 1, 0);
520 printf("enter ? for help\n");
521 mb();
522 xmon_gate = 1;
523 barrier();
524 }
525
526 cmdloop:
527 while (in_xmon) {
528 if (secondary) {
529 if (cpu == xmon_owner) {
530 if (!test_and_set_bit(0, &xmon_taken)) {
531 secondary = 0;
532 continue;
533 }
534 /* missed it */
535 while (cpu == xmon_owner)
536 barrier();
537 }
538 barrier();
539 } else {
540 cmd = cmds(regs);
541 if (cmd != 0) {
542 /* exiting xmon */
543 insert_bpts();
544 xmon_gate = 0;
545 wmb();
546 in_xmon = 0;
547 break;
548 }
549 /* have switched to some other cpu */
550 secondary = 1;
551 }
552 }
553 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000554 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556#else
557 /* UP is simple... */
558 if (in_xmon) {
559 printf("Exception %lx %s in xmon, returning to main loop\n",
560 regs->trap, getvecname(TRAP(regs)));
561 longjmp(xmon_fault_jmp[0], 1);
562 }
563 if (setjmp(recurse_jmp) == 0) {
564 xmon_fault_jmp[0] = recurse_jmp;
565 in_xmon = 1;
566
567 excprint(regs);
568 bp = at_breakpoint(regs->nip);
569 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000570 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 xmon_print_symbol(regs->nip, " ", ")\n");
572 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000573 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 printf("WARNING: exception is not recoverable, "
575 "can't continue\n");
576 remove_bpts();
577 disable_surveillance();
578 /* for breakpoint or single step, print the current instr. */
579 if (bp || TRAP(regs) == 0xd00)
580 ppc_inst_dump(regs->nip, 1, 0);
581 printf("enter ? for help\n");
582 }
583
584 cmd = cmds(regs);
585
586 insert_bpts();
587 in_xmon = 0;
588#endif
589
Josh Boyercdd39042009-10-05 04:46:05 +0000590#ifdef CONFIG_BOOKE
591 if (regs->msr & MSR_DE) {
592 bp = at_breakpoint(regs->nip);
593 if (bp != NULL) {
594 regs->nip = (unsigned long) &bp->instr[0];
595 atomic_inc(&bp->ref_count);
596 }
597 }
598#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000599 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 bp = at_breakpoint(regs->nip);
601 if (bp != NULL) {
602 int stepped = emulate_step(regs, bp->instr[0]);
603 if (stepped == 0) {
604 regs->nip = (unsigned long) &bp->instr[0];
605 atomic_inc(&bp->ref_count);
606 } else if (stepped < 0) {
607 printf("Couldn't single-step %s instruction\n",
608 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
609 }
610 }
611 }
Josh Boyercdd39042009-10-05 04:46:05 +0000612#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 insert_cpu_bpts();
614
Anton Blancharda71d64b2014-08-05 14:55:00 +1000615 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100616 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000618 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619}
620
621int xmon(struct pt_regs *excp)
622{
623 struct pt_regs regs;
624
625 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000626 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 excp = &regs;
628 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200629
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 return xmon_core(excp, 0);
631}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000632EXPORT_SYMBOL(xmon);
633
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000634irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000635{
636 unsigned long flags;
637 local_irq_save(flags);
638 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000639 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000640 local_irq_restore(flags);
641 return IRQ_HANDLED;
642}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000644static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{
646 struct bpt *bp;
647 unsigned long offset;
648
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000649 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 return 0;
651
652 /* Are we at the trap at bp->instr[1] for some bp? */
653 bp = in_breakpoint_table(regs->nip, &offset);
654 if (bp != NULL && offset == 4) {
655 regs->nip = bp->address + 4;
656 atomic_dec(&bp->ref_count);
657 return 1;
658 }
659
660 /* Are we at a breakpoint? */
661 bp = at_breakpoint(regs->nip);
662 if (!bp)
663 return 0;
664
665 xmon_core(regs, 0);
666
667 return 1;
668}
669
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000670static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671{
672 if (user_mode(regs))
673 return 0;
674 xmon_core(regs, 0);
675 return 1;
676}
677
Michael Neuling9422de32012-12-20 14:06:44 +0000678static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000680 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000682 if (dabr.enabled == 0)
683 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 xmon_core(regs, 0);
685 return 1;
686}
687
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000688static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000690 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000692 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return 0;
694 xmon_core(regs, 0);
695 return 1;
696}
697
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000698static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699{
700#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000701 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 xmon_core(regs, 1);
703#endif
704 return 0;
705}
706
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000707static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
709 struct bpt *bp;
710 unsigned long offset;
711
712 if (in_xmon && catch_memory_errors)
713 handle_fault(regs); /* doesn't return */
714
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000715 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 bp = in_breakpoint_table(regs->nip, &offset);
717 if (bp != NULL) {
718 regs->nip = bp->address + offset;
719 atomic_dec(&bp->ref_count);
720 }
721 }
722
723 return 0;
724}
725
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726static struct bpt *at_breakpoint(unsigned long pc)
727{
728 int i;
729 struct bpt *bp;
730
731 bp = bpts;
732 for (i = 0; i < NBPTS; ++i, ++bp)
733 if (bp->enabled && pc == bp->address)
734 return bp;
735 return NULL;
736}
737
738static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
739{
740 unsigned long off;
741
742 off = nip - (unsigned long) bpts;
743 if (off >= sizeof(bpts))
744 return NULL;
745 off %= sizeof(struct bpt);
746 if (off != offsetof(struct bpt, instr[0])
747 && off != offsetof(struct bpt, instr[1]))
748 return NULL;
749 *offp = off - offsetof(struct bpt, instr[0]);
750 return (struct bpt *) (nip - off);
751}
752
753static struct bpt *new_breakpoint(unsigned long a)
754{
755 struct bpt *bp;
756
757 a &= ~3UL;
758 bp = at_breakpoint(a);
759 if (bp)
760 return bp;
761
762 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
763 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
764 bp->address = a;
765 bp->instr[1] = bpinstr;
766 store_inst(&bp->instr[1]);
767 return bp;
768 }
769 }
770
771 printf("Sorry, no free breakpoints. Please clear one first.\n");
772 return NULL;
773}
774
775static void insert_bpts(void)
776{
777 int i;
778 struct bpt *bp;
779
780 bp = bpts;
781 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100782 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 continue;
784 if (mread(bp->address, &bp->instr[0], 4) != 4) {
785 printf("Couldn't read instruction at %lx, "
786 "disabling breakpoint there\n", bp->address);
787 bp->enabled = 0;
788 continue;
789 }
790 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
791 printf("Breakpoint at %lx is on an mtmsrd or rfid "
792 "instruction, disabling it\n", bp->address);
793 bp->enabled = 0;
794 continue;
795 }
796 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100797 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 continue;
799 if (mwrite(bp->address, &bpinstr, 4) != 4) {
800 printf("Couldn't write instruction at %lx, "
801 "disabling breakpoint there\n", bp->address);
802 bp->enabled &= ~BP_TRAP;
803 continue;
804 }
805 store_inst((void *)bp->address);
806 }
807}
808
809static void insert_cpu_bpts(void)
810{
Michael Neuling9422de32012-12-20 14:06:44 +0000811 struct arch_hw_breakpoint brk;
812
813 if (dabr.enabled) {
814 brk.address = dabr.address;
815 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
816 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400817 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000818 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530819
820 if (iabr)
821 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822}
823
824static void remove_bpts(void)
825{
826 int i;
827 struct bpt *bp;
828 unsigned instr;
829
830 bp = bpts;
831 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100832 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 continue;
834 if (mread(bp->address, &instr, 4) == 4
835 && instr == bpinstr
836 && mwrite(bp->address, &bp->instr, 4) != 4)
837 printf("Couldn't remove breakpoint at %lx\n",
838 bp->address);
839 else
840 store_inst((void *)bp->address);
841 }
842}
843
844static void remove_cpu_bpts(void)
845{
Michael Neuling9422de32012-12-20 14:06:44 +0000846 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530847 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848}
849
Sam bobroff958b7c82015-10-08 11:50:23 +1100850static void set_lpp_cmd(void)
851{
852 unsigned long lpp;
853
854 if (!scanhex(&lpp)) {
855 printf("Invalid number.\n");
856 lpp = 0;
857 }
858 xmon_set_pagination_lpp(lpp);
859}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860/* Command interpreting routine */
861static char *last_cmd;
862
863static int
864cmds(struct pt_regs *excp)
865{
866 int cmd = 0;
867
868 last_cmd = NULL;
869 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200870
871 if (!xmon_no_auto_backtrace) {
872 xmon_no_auto_backtrace = 1;
873 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
874 }
875
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 for(;;) {
877#ifdef CONFIG_SMP
878 printf("%x:", smp_processor_id());
879#endif /* CONFIG_SMP */
880 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 flush_input();
882 termch = 0;
883 cmd = skipbl();
884 if( cmd == '\n' ) {
885 if (last_cmd == NULL)
886 continue;
887 take_input(last_cmd);
888 last_cmd = NULL;
889 cmd = inchar();
890 }
891 switch (cmd) {
892 case 'm':
893 cmd = inchar();
894 switch (cmd) {
895 case 'm':
896 case 's':
897 case 'd':
898 memops(cmd);
899 break;
900 case 'l':
901 memlocate();
902 break;
903 case 'z':
904 memzcan();
905 break;
906 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700907 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 break;
909 default:
910 termch = cmd;
911 memex();
912 }
913 break;
914 case 'd':
915 dump();
916 break;
917 case 'l':
918 symbol_lookup();
919 break;
920 case 'r':
921 prregs(excp); /* print regs */
922 break;
923 case 'e':
924 excprint(excp);
925 break;
926 case 'S':
927 super_regs();
928 break;
929 case 't':
930 backtrace(excp);
931 break;
932 case 'f':
933 cacheflush();
934 break;
935 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200936 if (do_spu_cmd() == 0)
937 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 if (do_step(excp))
939 return cmd;
940 break;
941 case 'x':
942 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100943 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100945 printf(" <no input ...>\n");
946 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 return cmd;
948 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000949 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 break;
Sam bobroff958b7c82015-10-08 11:50:23 +1100951 case '#':
952 set_lpp_cmd();
953 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 case 'b':
955 bpt_cmds();
956 break;
957 case 'C':
958 csum();
959 break;
960 case 'c':
961 if (cpu_cmd())
962 return 0;
963 break;
964 case 'z':
965 bootcmds();
966 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000967 case 'p':
968 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000970#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 case 'u':
972 dump_segments();
973 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +1100974#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100975 case 'u':
976 dump_tlb_44x();
977 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000978#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000979 case 'u':
980 dump_tlb_book3e();
981 break;
982#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 default:
984 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000985 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 if (' ' < cmd && cmd <= '~')
987 putchar(cmd);
988 else
989 printf("\\x%x", cmd);
990 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +0000991 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 printf(" (type ? for help)\n");
993 break;
994 }
995 }
996}
997
Josh Boyercdd39042009-10-05 04:46:05 +0000998#ifdef CONFIG_BOOKE
999static int do_step(struct pt_regs *regs)
1000{
1001 regs->msr |= MSR_DE;
1002 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1003 return 1;
1004}
1005#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006/*
1007 * Step a single instruction.
1008 * Some instructions we emulate, others we execute with MSR_SE set.
1009 */
1010static int do_step(struct pt_regs *regs)
1011{
1012 unsigned int instr;
1013 int stepped;
1014
1015 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001016 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (mread(regs->nip, &instr, 4) == 4) {
1018 stepped = emulate_step(regs, instr);
1019 if (stepped < 0) {
1020 printf("Couldn't single-step %s instruction\n",
1021 (IS_RFID(instr)? "rfid": "mtmsrd"));
1022 return 0;
1023 }
1024 if (stepped > 0) {
1025 regs->trap = 0xd00 | (regs->trap & 1);
1026 printf("stepped to ");
1027 xmon_print_symbol(regs->nip, " ", "\n");
1028 ppc_inst_dump(regs->nip, 1, 0);
1029 return 0;
1030 }
1031 }
1032 }
1033 regs->msr |= MSR_SE;
1034 return 1;
1035}
Josh Boyercdd39042009-10-05 04:46:05 +00001036#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
1038static void bootcmds(void)
1039{
1040 int cmd;
1041
1042 cmd = inchar();
1043 if (cmd == 'r')
1044 ppc_md.restart(NULL);
1045 else if (cmd == 'h')
1046 ppc_md.halt();
1047 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001048 if (pm_power_off)
1049 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050}
1051
1052static int cpu_cmd(void)
1053{
1054#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001055 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
1058 if (!scanhex(&cpu)) {
1059 /* print cpus waiting or in xmon */
1060 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001061 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001062 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001063 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001064 if (cpu == last_cpu + 1) {
1065 last_cpu = cpu;
1066 } else {
1067 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001068 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001069 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001070 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 }
1073 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001074 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001075 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 printf("\n");
1077 return 0;
1078 }
1079 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001080 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 printf("cpu 0x%x isn't in xmon\n", cpu);
1082 return 0;
1083 }
1084 xmon_taken = 0;
1085 mb();
1086 xmon_owner = cpu;
1087 timeout = 10000000;
1088 while (!xmon_taken) {
1089 if (--timeout == 0) {
1090 if (test_and_set_bit(0, &xmon_taken))
1091 break;
1092 /* take control back */
1093 mb();
1094 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001095 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 return 0;
1097 }
1098 barrier();
1099 }
1100 return 1;
1101#else
1102 return 0;
1103#endif /* CONFIG_SMP */
1104}
1105
1106static unsigned short fcstab[256] = {
1107 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1108 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1109 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1110 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1111 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1112 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1113 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1114 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1115 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1116 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1117 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1118 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1119 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1120 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1121 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1122 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1123 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1124 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1125 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1126 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1127 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1128 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1129 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1130 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1131 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1132 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1133 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1134 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1135 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1136 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1137 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1138 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1139};
1140
1141#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1142
1143static void
1144csum(void)
1145{
1146 unsigned int i;
1147 unsigned short fcs;
1148 unsigned char v;
1149
1150 if (!scanhex(&adrs))
1151 return;
1152 if (!scanhex(&ncsum))
1153 return;
1154 fcs = 0xffff;
1155 for (i = 0; i < ncsum; ++i) {
1156 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001157 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 break;
1159 }
1160 fcs = FCS(fcs, v);
1161 }
1162 printf("%x\n", fcs);
1163}
1164
1165/*
1166 * Check if this is a suitable place to put a breakpoint.
1167 */
1168static long check_bp_loc(unsigned long addr)
1169{
1170 unsigned int instr;
1171
1172 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001173 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 printf("Breakpoints may only be placed at kernel addresses\n");
1175 return 0;
1176 }
1177 if (!mread(addr, &instr, sizeof(instr))) {
1178 printf("Can't read instruction at address %lx\n", addr);
1179 return 0;
1180 }
1181 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1182 printf("Breakpoints may not be placed on mtmsrd or rfid "
1183 "instructions\n");
1184 return 0;
1185 }
1186 return 1;
1187}
1188
Michael Ellermane3bc8042012-08-23 22:09:13 +00001189static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 "Breakpoint command usage:\n"
1191 "b show breakpoints\n"
1192 "b <addr> [cnt] set breakpoint at given instr addr\n"
1193 "bc clear all breakpoints\n"
1194 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301195 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 "bd <addr> [cnt] set hardware data breakpoint\n"
1197 "";
1198
1199static void
1200bpt_cmds(void)
1201{
1202 int cmd;
1203 unsigned long a;
1204 int mode, i;
1205 struct bpt *bp;
1206 const char badaddr[] = "Only kernel addresses are permitted "
1207 "for breakpoints\n";
1208
1209 cmd = inchar();
1210 switch (cmd) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001211#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 case 'd': /* bd - hardware data breakpoint */
1213 mode = 7;
1214 cmd = inchar();
1215 if (cmd == 'r')
1216 mode = 5;
1217 else if (cmd == 'w')
1218 mode = 6;
1219 else
1220 termch = cmd;
1221 dabr.address = 0;
1222 dabr.enabled = 0;
1223 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001224 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 printf(badaddr);
1226 break;
1227 }
Michael Neuling9422de32012-12-20 14:06:44 +00001228 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 dabr.enabled = mode | BP_DABR;
1230 }
1231 break;
1232
1233 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301234 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 printf("Hardware instruction breakpoint "
1236 "not supported on this cpu\n");
1237 break;
1238 }
1239 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001240 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 iabr = NULL;
1242 }
1243 if (!scanhex(&a))
1244 break;
1245 if (!check_bp_loc(a))
1246 break;
1247 bp = new_breakpoint(a);
1248 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001249 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 iabr = bp;
1251 }
1252 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001253#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254
1255 case 'c':
1256 if (!scanhex(&a)) {
1257 /* clear all breakpoints */
1258 for (i = 0; i < NBPTS; ++i)
1259 bpts[i].enabled = 0;
1260 iabr = NULL;
1261 dabr.enabled = 0;
1262 printf("All breakpoints cleared\n");
1263 break;
1264 }
1265
1266 if (a <= NBPTS && a >= 1) {
1267 /* assume a breakpoint number */
1268 bp = &bpts[a-1]; /* bp nums are 1 based */
1269 } else {
1270 /* assume a breakpoint address */
1271 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001272 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001273 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 break;
1275 }
1276 }
1277
Michael Ellerman736256e2014-05-26 21:02:14 +10001278 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 xmon_print_symbol(bp->address, " ", ")\n");
1280 bp->enabled = 0;
1281 break;
1282
1283 default:
1284 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001285 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 if (cmd == '?') {
1287 printf(breakpoint_help_string);
1288 break;
1289 }
1290 termch = cmd;
1291 if (!scanhex(&a)) {
1292 /* print all breakpoints */
1293 printf(" type address\n");
1294 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001295 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 if (dabr.enabled & 1)
1297 printf("r");
1298 if (dabr.enabled & 2)
1299 printf("w");
1300 printf("]\n");
1301 }
1302 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1303 if (!bp->enabled)
1304 continue;
1305 printf("%2x %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001306 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 xmon_print_symbol(bp->address, " ", "\n");
1308 }
1309 break;
1310 }
1311
1312 if (!check_bp_loc(a))
1313 break;
1314 bp = new_breakpoint(a);
1315 if (bp != NULL)
1316 bp->enabled |= BP_TRAP;
1317 break;
1318 }
1319}
1320
1321/* Very cheap human name for vector lookup. */
1322static
1323const char *getvecname(unsigned long vec)
1324{
1325 char *ret;
1326
1327 switch (vec) {
1328 case 0x100: ret = "(System Reset)"; break;
1329 case 0x200: ret = "(Machine Check)"; break;
1330 case 0x300: ret = "(Data Access)"; break;
1331 case 0x380: ret = "(Data SLB Access)"; break;
1332 case 0x400: ret = "(Instruction Access)"; break;
1333 case 0x480: ret = "(Instruction SLB Access)"; break;
1334 case 0x500: ret = "(Hardware Interrupt)"; break;
1335 case 0x600: ret = "(Alignment)"; break;
1336 case 0x700: ret = "(Program Check)"; break;
1337 case 0x800: ret = "(FPU Unavailable)"; break;
1338 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001339 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1340 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 case 0xc00: ret = "(System Call)"; break;
1342 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001343 case 0xe40: ret = "(Emulation Assist)"; break;
1344 case 0xe60: ret = "(HMI)"; break;
1345 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 case 0xf00: ret = "(Performance Monitor)"; break;
1347 case 0xf20: ret = "(Altivec Unavailable)"; break;
1348 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001349 case 0x1500: ret = "(Denormalisation)"; break;
1350 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 default: ret = "";
1352 }
1353 return ret;
1354}
1355
1356static void get_function_bounds(unsigned long pc, unsigned long *startp,
1357 unsigned long *endp)
1358{
1359 unsigned long size, offset;
1360 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
1362 *startp = *endp = 0;
1363 if (pc == 0)
1364 return;
1365 if (setjmp(bus_error_jmp) == 0) {
1366 catch_memory_errors = 1;
1367 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001368 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 if (name != NULL) {
1370 *startp = pc - offset;
1371 *endp = pc - offset + size;
1372 }
1373 sync();
1374 }
1375 catch_memory_errors = 0;
1376}
1377
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001378#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1379#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1380
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381static void xmon_show_stack(unsigned long sp, unsigned long lr,
1382 unsigned long pc)
1383{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001384 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 unsigned long ip;
1386 unsigned long newsp;
1387 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 struct pt_regs regs;
1389
Michael Ellerman0104cd62012-10-09 04:20:36 +00001390 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 if (sp < PAGE_OFFSET) {
1392 if (sp != 0)
1393 printf("SP (%lx) is in userspace\n", sp);
1394 break;
1395 }
1396
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001397 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 || !mread(sp, &newsp, sizeof(unsigned long))) {
1399 printf("Couldn't read stack frame at %lx\n", sp);
1400 break;
1401 }
1402
1403 /*
1404 * For the first stack frame, try to work out if
1405 * LR and/or the saved LR value in the bottommost
1406 * stack frame are valid.
1407 */
1408 if ((pc | lr) != 0) {
1409 unsigned long fnstart, fnend;
1410 unsigned long nextip;
1411 int printip = 1;
1412
1413 get_function_bounds(pc, &fnstart, &fnend);
1414 nextip = 0;
1415 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001416 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 sizeof(unsigned long));
1418 if (lr == ip) {
1419 if (lr < PAGE_OFFSET
1420 || (fnstart <= lr && lr < fnend))
1421 printip = 0;
1422 } else if (lr == nextip) {
1423 printip = 0;
1424 } else if (lr >= PAGE_OFFSET
1425 && !(fnstart <= lr && lr < fnend)) {
1426 printf("[link register ] ");
1427 xmon_print_symbol(lr, " ", "\n");
1428 }
1429 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001430 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 xmon_print_symbol(ip, " ", " (unreliable)\n");
1432 }
1433 pc = lr = 0;
1434
1435 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001436 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 xmon_print_symbol(ip, " ", "\n");
1438 }
1439
1440 /* Look for "regshere" marker to see if this is
1441 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001442 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001443 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001444 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 != sizeof(regs)) {
1446 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001447 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 break;
1449 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001450 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 getvecname(TRAP(&regs)));
1452 pc = regs.nip;
1453 lr = regs.link;
1454 xmon_print_symbol(pc, " ", "\n");
1455 }
1456
1457 if (newsp == 0)
1458 break;
1459
1460 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001461 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462}
1463
1464static void backtrace(struct pt_regs *excp)
1465{
1466 unsigned long sp;
1467
1468 if (scanhex(&sp))
1469 xmon_show_stack(sp, 0, 0);
1470 else
1471 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1472 scannl();
1473}
1474
1475static void print_bug_trap(struct pt_regs *regs)
1476{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001477#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001478 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 unsigned long addr;
1480
1481 if (regs->msr & MSR_PR)
1482 return; /* not in kernel */
1483 addr = regs->nip; /* address of trap instruction */
1484 if (addr < PAGE_OFFSET)
1485 return;
1486 bug = find_bug(regs->nip);
1487 if (bug == NULL)
1488 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001489 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 return;
1491
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001492#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001493 printf("kernel BUG at %s:%u!\n",
1494 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001495#else
1496 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1497#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001498#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499}
1500
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001501static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502{
1503 unsigned long trap;
1504
1505#ifdef CONFIG_SMP
1506 printf("cpu 0x%x: ", smp_processor_id());
1507#endif /* CONFIG_SMP */
1508
1509 trap = TRAP(fp);
1510 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1511 printf(" pc: ");
1512 xmon_print_symbol(fp->nip, ": ", "\n");
1513
1514 printf(" lr: ", fp->link);
1515 xmon_print_symbol(fp->link, ": ", "\n");
1516
1517 printf(" sp: %lx\n", fp->gpr[1]);
1518 printf(" msr: %lx\n", fp->msr);
1519
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001520 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 printf(" dar: %lx\n", fp->dar);
1522 if (trap != 0x380)
1523 printf(" dsisr: %lx\n", fp->dsisr);
1524 }
1525
1526 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001527#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001528 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1529 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001530#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 if (current) {
1532 printf(" pid = %ld, comm = %s\n",
1533 current->pid, current->comm);
1534 }
1535
1536 if (trap == 0x700)
1537 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001538
1539 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540}
1541
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001542static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001544 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 unsigned long base;
1546 struct pt_regs regs;
1547
1548 if (scanhex(&base)) {
1549 if (setjmp(bus_error_jmp) == 0) {
1550 catch_memory_errors = 1;
1551 sync();
1552 regs = *(struct pt_regs *)base;
1553 sync();
1554 __delay(200);
1555 } else {
1556 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001557 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 base);
1559 return;
1560 }
1561 catch_memory_errors = 0;
1562 fp = &regs;
1563 }
1564
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001565#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 if (FULL_REGS(fp)) {
1567 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001568 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1570 } else {
1571 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001572 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1574 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001575#else
1576 for (n = 0; n < 32; ++n) {
1577 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1578 (n & 3) == 3? "\n": " ");
1579 if (n == 12 && !FULL_REGS(fp)) {
1580 printf("\n");
1581 break;
1582 }
1583 }
1584#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 printf("pc = ");
1586 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001587 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1588 printf("cfar= ");
1589 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1590 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 printf("lr = ");
1592 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001593 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1594 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001596 trap = TRAP(fp);
1597 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1598 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599}
1600
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001601static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602{
1603 int cmd;
1604 unsigned long nflush;
1605
1606 cmd = inchar();
1607 if (cmd != 'i')
1608 termch = cmd;
1609 scanhex((void *)&adrs);
1610 if (termch != '\n')
1611 termch = 0;
1612 nflush = 1;
1613 scanhex(&nflush);
1614 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1615 if (setjmp(bus_error_jmp) == 0) {
1616 catch_memory_errors = 1;
1617 sync();
1618
1619 if (cmd != 'i') {
1620 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1621 cflush((void *) adrs);
1622 } else {
1623 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1624 cinval((void *) adrs);
1625 }
1626 sync();
1627 /* wait a little while to see if we get a machine check */
1628 __delay(200);
1629 }
1630 catch_memory_errors = 0;
1631}
1632
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001633static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634read_spr(int n)
1635{
1636 unsigned int instrs[2];
1637 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001639#ifdef CONFIG_PPC64
1640 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 opd[0] = (unsigned long)instrs;
1643 opd[1] = 0;
1644 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001645 code = (unsigned long (*)(void)) opd;
1646#else
1647 code = (unsigned long (*)(void)) instrs;
1648#endif
1649
1650 /* mfspr r3,n; blr */
1651 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1652 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 store_inst(instrs);
1654 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
1656 if (setjmp(bus_error_jmp) == 0) {
1657 catch_memory_errors = 1;
1658 sync();
1659
1660 ret = code();
1661
1662 sync();
1663 /* wait a little while to see if we get a machine check */
1664 __delay(200);
1665 n = size;
1666 }
1667
1668 return ret;
1669}
1670
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001671static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672write_spr(int n, unsigned long val)
1673{
1674 unsigned int instrs[2];
1675 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001676#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 unsigned long opd[3];
1678
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 opd[0] = (unsigned long)instrs;
1680 opd[1] = 0;
1681 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001682 code = (unsigned long (*)(unsigned long)) opd;
1683#else
1684 code = (unsigned long (*)(unsigned long)) instrs;
1685#endif
1686
1687 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1688 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 store_inst(instrs);
1690 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
1692 if (setjmp(bus_error_jmp) == 0) {
1693 catch_memory_errors = 1;
1694 sync();
1695
1696 code(val);
1697
1698 sync();
1699 /* wait a little while to see if we get a machine check */
1700 __delay(200);
1701 n = size;
1702 }
1703}
1704
1705static unsigned long regno;
1706extern char exc_prolog;
1707extern char dec_exc;
1708
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001709static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710{
1711 int cmd;
1712 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
1714 cmd = skipbl();
1715 if (cmd == '\n') {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001716 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 asm("mr %0,1" : "=r" (sp) :);
1718 asm("mr %0,2" : "=r" (toc) :);
1719
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001720 printf("msr = "REG" sprg0= "REG"\n",
1721 mfmsr(), mfspr(SPRN_SPRG0));
1722 printf("pvr = "REG" sprg1= "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001723 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001724 printf("dec = "REG" sprg2= "REG"\n",
1725 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1726 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1727 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728
1729 return;
1730 }
1731
1732 scanhex(&regno);
1733 switch (cmd) {
1734 case 'w':
1735 val = read_spr(regno);
1736 scanhex(&val);
1737 write_spr(regno, val);
1738 /* fall through */
1739 case 'r':
1740 printf("spr %lx = %lx\n", regno, read_spr(regno));
1741 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 }
1743 scannl();
1744}
1745
1746/*
1747 * Stuff for reading and writing memory safely
1748 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001749static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750mread(unsigned long adrs, void *buf, int size)
1751{
1752 volatile int n;
1753 char *p, *q;
1754
1755 n = 0;
1756 if (setjmp(bus_error_jmp) == 0) {
1757 catch_memory_errors = 1;
1758 sync();
1759 p = (char *)adrs;
1760 q = (char *)buf;
1761 switch (size) {
1762 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001763 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 break;
1765 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001766 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 break;
1768 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001769 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 break;
1771 default:
1772 for( ; n < size; ++n) {
1773 *q++ = *p++;
1774 sync();
1775 }
1776 }
1777 sync();
1778 /* wait a little while to see if we get a machine check */
1779 __delay(200);
1780 n = size;
1781 }
1782 catch_memory_errors = 0;
1783 return n;
1784}
1785
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001786static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787mwrite(unsigned long adrs, void *buf, int size)
1788{
1789 volatile int n;
1790 char *p, *q;
1791
1792 n = 0;
1793 if (setjmp(bus_error_jmp) == 0) {
1794 catch_memory_errors = 1;
1795 sync();
1796 p = (char *) adrs;
1797 q = (char *) buf;
1798 switch (size) {
1799 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001800 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 break;
1802 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001803 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 break;
1805 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001806 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 break;
1808 default:
1809 for ( ; n < size; ++n) {
1810 *p++ = *q++;
1811 sync();
1812 }
1813 }
1814 sync();
1815 /* wait a little while to see if we get a machine check */
1816 __delay(200);
1817 n = size;
1818 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10001819 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 }
1821 catch_memory_errors = 0;
1822 return n;
1823}
1824
1825static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001826static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827static char *fault_chars[] = { "--", "**", "##" };
1828
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001829static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001831 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 switch (TRAP(regs)) {
1833 case 0x200:
1834 fault_type = 0;
1835 break;
1836 case 0x300:
1837 case 0x380:
1838 fault_type = 1;
1839 break;
1840 default:
1841 fault_type = 2;
1842 }
1843
1844 longjmp(bus_error_jmp, 1);
1845
1846 return 0;
1847}
1848
1849#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1850
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001851static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852byterev(unsigned char *val, int size)
1853{
1854 int t;
1855
1856 switch (size) {
1857 case 2:
1858 SWAP(val[0], val[1], t);
1859 break;
1860 case 4:
1861 SWAP(val[0], val[3], t);
1862 SWAP(val[1], val[2], t);
1863 break;
1864 case 8: /* is there really any use for this? */
1865 SWAP(val[0], val[7], t);
1866 SWAP(val[1], val[6], t);
1867 SWAP(val[2], val[5], t);
1868 SWAP(val[3], val[4], t);
1869 break;
1870 }
1871}
1872
1873static int brev;
1874static int mnoread;
1875
Michael Ellermane3bc8042012-08-23 22:09:13 +00001876static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 "Memory examine command usage:\n"
1878 "m [addr] [flags] examine/change memory\n"
1879 " addr is optional. will start where left off.\n"
1880 " flags may include chars from this set:\n"
1881 " b modify by bytes (default)\n"
1882 " w modify by words (2 byte)\n"
1883 " l modify by longs (4 byte)\n"
1884 " d modify by doubleword (8 byte)\n"
1885 " r toggle reverse byte order mode\n"
1886 " n do not read memory (for i/o spaces)\n"
1887 " . ok to read (default)\n"
1888 "NOTE: flags are saved as defaults\n"
1889 "";
1890
Michael Ellermane3bc8042012-08-23 22:09:13 +00001891static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 "Memory examine subcommands:\n"
1893 " hexval write this val to current location\n"
1894 " 'string' write chars from string to this location\n"
1895 " ' increment address\n"
1896 " ^ decrement address\n"
1897 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1898 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1899 " ` clear no-read flag\n"
1900 " ; stay at this addr\n"
1901 " v change to byte mode\n"
1902 " w change to word (2 byte) mode\n"
1903 " l change to long (4 byte) mode\n"
1904 " u change to doubleword (8 byte) mode\n"
1905 " m addr change current addr\n"
1906 " n toggle no-read flag\n"
1907 " r toggle byte reverse flag\n"
1908 " < count back up count bytes\n"
1909 " > count skip forward count bytes\n"
1910 " x exit this mode\n"
1911 "";
1912
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001913static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914memex(void)
1915{
1916 int cmd, inc, i, nslash;
1917 unsigned long n;
1918 unsigned char val[16];
1919
1920 scanhex((void *)&adrs);
1921 cmd = skipbl();
1922 if (cmd == '?') {
1923 printf(memex_help_string);
1924 return;
1925 } else {
1926 termch = cmd;
1927 }
1928 last_cmd = "m\n";
1929 while ((cmd = skipbl()) != '\n') {
1930 switch( cmd ){
1931 case 'b': size = 1; break;
1932 case 'w': size = 2; break;
1933 case 'l': size = 4; break;
1934 case 'd': size = 8; break;
1935 case 'r': brev = !brev; break;
1936 case 'n': mnoread = 1; break;
1937 case '.': mnoread = 0; break;
1938 }
1939 }
1940 if( size <= 0 )
1941 size = 1;
1942 else if( size > 8 )
1943 size = 8;
1944 for(;;){
1945 if (!mnoread)
1946 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001947 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 if (!mnoread) {
1949 if (brev)
1950 byterev(val, size);
1951 putchar(' ');
1952 for (i = 0; i < n; ++i)
1953 printf("%.2x", val[i]);
1954 for (; i < size; ++i)
1955 printf("%s", fault_chars[fault_type]);
1956 }
1957 putchar(' ');
1958 inc = size;
1959 nslash = 0;
1960 for(;;){
1961 if( scanhex(&n) ){
1962 for (i = 0; i < size; ++i)
1963 val[i] = n >> (i * 8);
1964 if (!brev)
1965 byterev(val, size);
1966 mwrite(adrs, val, size);
1967 inc = size;
1968 }
1969 cmd = skipbl();
1970 if (cmd == '\n')
1971 break;
1972 inc = 0;
1973 switch (cmd) {
1974 case '\'':
1975 for(;;){
1976 n = inchar();
1977 if( n == '\\' )
1978 n = bsesc();
1979 else if( n == '\'' )
1980 break;
1981 for (i = 0; i < size; ++i)
1982 val[i] = n >> (i * 8);
1983 if (!brev)
1984 byterev(val, size);
1985 mwrite(adrs, val, size);
1986 adrs += size;
1987 }
1988 adrs -= size;
1989 inc = size;
1990 break;
1991 case ',':
1992 adrs += size;
1993 break;
1994 case '.':
1995 mnoread = 0;
1996 break;
1997 case ';':
1998 break;
1999 case 'x':
2000 case EOF:
2001 scannl();
2002 return;
2003 case 'b':
2004 case 'v':
2005 size = 1;
2006 break;
2007 case 'w':
2008 size = 2;
2009 break;
2010 case 'l':
2011 size = 4;
2012 break;
2013 case 'u':
2014 size = 8;
2015 break;
2016 case '^':
2017 adrs -= size;
2018 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 case '/':
2020 if (nslash > 0)
2021 adrs -= 1 << nslash;
2022 else
2023 nslash = 0;
2024 nslash += 4;
2025 adrs += 1 << nslash;
2026 break;
2027 case '\\':
2028 if (nslash < 0)
2029 adrs += 1 << -nslash;
2030 else
2031 nslash = 0;
2032 nslash -= 4;
2033 adrs -= 1 << -nslash;
2034 break;
2035 case 'm':
2036 scanhex((void *)&adrs);
2037 break;
2038 case 'n':
2039 mnoread = 1;
2040 break;
2041 case 'r':
2042 brev = !brev;
2043 break;
2044 case '<':
2045 n = size;
2046 scanhex(&n);
2047 adrs -= n;
2048 break;
2049 case '>':
2050 n = size;
2051 scanhex(&n);
2052 adrs += n;
2053 break;
2054 case '?':
2055 printf(memex_subcmd_help_string);
2056 break;
2057 }
2058 }
2059 adrs += inc;
2060 }
2061}
2062
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002063static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064bsesc(void)
2065{
2066 int c;
2067
2068 c = inchar();
2069 switch( c ){
2070 case 'n': c = '\n'; break;
2071 case 'r': c = '\r'; break;
2072 case 'b': c = '\b'; break;
2073 case 't': c = '\t'; break;
2074 }
2075 return c;
2076}
2077
Olaf Hering7e5b5932006-03-08 20:40:28 +01002078static void xmon_rawdump (unsigned long adrs, long ndump)
2079{
2080 long n, m, r, nr;
2081 unsigned char temp[16];
2082
2083 for (n = ndump; n > 0;) {
2084 r = n < 16? n: 16;
2085 nr = mread(adrs, temp, r);
2086 adrs += nr;
2087 for (m = 0; m < r; ++m) {
2088 if (m < nr)
2089 printf("%.2x", temp[m]);
2090 else
2091 printf("%s", fault_chars[fault_type]);
2092 }
2093 n -= r;
2094 if (nr < r)
2095 break;
2096 }
2097 printf("\n");
2098}
2099
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002100#ifdef CONFIG_PPC64
2101static void dump_one_paca(int cpu)
2102{
2103 struct paca_struct *p;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002104#ifdef CONFIG_PPC_STD_MMU_64
2105 int i = 0;
2106#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002107
2108 if (setjmp(bus_error_jmp) != 0) {
2109 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2110 return;
2111 }
2112
2113 catch_memory_errors = 1;
2114 sync();
2115
2116 p = &paca[cpu];
2117
2118 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2119
Michael Ellermanad987fc2015-10-14 16:58:36 +11002120 printf(" %-*s = %s\n", 20, "possible", cpu_possible(cpu) ? "yes" : "no");
2121 printf(" %-*s = %s\n", 20, "present", cpu_present(cpu) ? "yes" : "no");
2122 printf(" %-*s = %s\n", 20, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002123
2124#define DUMP(paca, name, format) \
Michael Ellermanad987fc2015-10-14 16:58:36 +11002125 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 20, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002126 offsetof(struct paca_struct, name));
2127
2128 DUMP(p, lock_token, "x");
2129 DUMP(p, paca_index, "x");
2130 DUMP(p, kernel_toc, "lx");
2131 DUMP(p, kernelbase, "lx");
2132 DUMP(p, kernel_msr, "lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002133 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302134#ifdef CONFIG_PPC_BOOK3S_64
2135 DUMP(p, mc_emergency_sp, "p");
2136 DUMP(p, in_mce, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002137 DUMP(p, hmi_event_available, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302138#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002139 DUMP(p, data_offset, "lx");
2140 DUMP(p, hw_cpu_id, "x");
2141 DUMP(p, cpu_start, "x");
2142 DUMP(p, kexec_state, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002143#ifdef CONFIG_PPC_STD_MMU_64
2144 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2145 u64 esid, vsid;
2146
2147 if (!p->slb_shadow_ptr)
2148 continue;
2149
2150 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2151 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
2152
2153 if (esid || vsid) {
2154 printf(" slb_shadow[%d]: = 0x%016lx 0x%016lx\n",
2155 i, esid, vsid);
2156 }
2157 }
2158 DUMP(p, vmalloc_sllp, "x");
2159 DUMP(p, slb_cache_ptr, "x");
2160 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2161 printf(" slb_cache[%d]: = 0x%016lx\n", i, p->slb_cache[i]);
2162#endif
2163 DUMP(p, dscr_default, "llx");
2164#ifdef CONFIG_PPC_BOOK3E
2165 DUMP(p, pgd, "p");
2166 DUMP(p, kernel_pgd, "p");
2167 DUMP(p, tcd_ptr, "p");
2168 DUMP(p, mc_kstack, "p");
2169 DUMP(p, crit_kstack, "p");
2170 DUMP(p, dbg_kstack, "p");
2171#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002172 DUMP(p, __current, "p");
2173 DUMP(p, kstack, "lx");
2174 DUMP(p, stab_rr, "lx");
2175 DUMP(p, saved_r1, "lx");
2176 DUMP(p, trap_save, "x");
2177 DUMP(p, soft_enabled, "x");
2178 DUMP(p, irq_happened, "x");
2179 DUMP(p, io_sync, "x");
2180 DUMP(p, irq_work_pending, "x");
2181 DUMP(p, nap_state_lost, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002182 DUMP(p, sprg_vdso, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002183
Michael Ellermanad987fc2015-10-14 16:58:36 +11002184#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
2185 DUMP(p, tm_scratch, "llx");
2186#endif
2187
2188#ifdef CONFIG_PPC_POWERNV
2189 DUMP(p, core_idle_state_ptr, "p");
2190 DUMP(p, thread_idle_state, "x");
2191 DUMP(p, thread_mask, "x");
2192 DUMP(p, subcore_sibling_mask, "x");
2193#endif
2194
2195 DUMP(p, user_time, "llx");
2196 DUMP(p, system_time, "llx");
2197 DUMP(p, user_time_scaled, "llx");
2198 DUMP(p, starttime, "llx");
2199 DUMP(p, starttime_user, "llx");
2200 DUMP(p, startspurr, "llx");
2201 DUMP(p, utime_sspurr, "llx");
2202 DUMP(p, stolen_time, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002203#undef DUMP
2204
2205 catch_memory_errors = 0;
2206 sync();
2207}
2208
2209static void dump_all_pacas(void)
2210{
2211 int cpu;
2212
2213 if (num_possible_cpus() == 0) {
2214 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2215 return;
2216 }
2217
2218 for_each_possible_cpu(cpu)
2219 dump_one_paca(cpu);
2220}
2221
2222static void dump_pacas(void)
2223{
2224 unsigned long num;
2225 int c;
2226
2227 c = inchar();
2228 if (c == 'a') {
2229 dump_all_pacas();
2230 return;
2231 }
2232
2233 termch = c; /* Put c back, it wasn't 'a' */
2234
2235 if (scanhex(&num))
2236 dump_one_paca(num);
2237 else
2238 dump_one_paca(xmon_owner);
2239}
2240#endif
2241
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002242static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243dump(void)
2244{
2245 int c;
2246
2247 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002248
2249#ifdef CONFIG_PPC64
2250 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002251 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002252 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002253 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002254 return;
2255 }
2256#endif
2257
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2259 termch = c;
2260 scanhex((void *)&adrs);
2261 if (termch != '\n')
2262 termch = 0;
2263 if (c == 'i') {
2264 scanhex(&nidump);
2265 if (nidump == 0)
2266 nidump = 16;
2267 else if (nidump > MAX_DUMP)
2268 nidump = MAX_DUMP;
2269 adrs += ppc_inst_dump(adrs, nidump, 1);
2270 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002271 } else if (c == 'l') {
2272 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002273 } else if (c == 'o') {
2274 dump_opal_msglog();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002275 } else if (c == 'r') {
2276 scanhex(&ndump);
2277 if (ndump == 0)
2278 ndump = 64;
2279 xmon_rawdump(adrs, ndump);
2280 adrs += ndump;
2281 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 } else {
2283 scanhex(&ndump);
2284 if (ndump == 0)
2285 ndump = 64;
2286 else if (ndump > MAX_DUMP)
2287 ndump = MAX_DUMP;
2288 prdump(adrs, ndump);
2289 adrs += ndump;
2290 last_cmd = "d\n";
2291 }
2292}
2293
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002294static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295prdump(unsigned long adrs, long ndump)
2296{
2297 long n, m, c, r, nr;
2298 unsigned char temp[16];
2299
2300 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002301 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 putchar(' ');
2303 r = n < 16? n: 16;
2304 nr = mread(adrs, temp, r);
2305 adrs += nr;
2306 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002307 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002308 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 if (m < nr)
2310 printf("%.2x", temp[m]);
2311 else
2312 printf("%s", fault_chars[fault_type]);
2313 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002314 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002315 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002316 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 printf(" |");
2320 for (m = 0; m < r; ++m) {
2321 if (m < nr) {
2322 c = temp[m];
2323 putchar(' ' <= c && c <= '~'? c: '.');
2324 } else
2325 putchar(' ');
2326 }
2327 n -= r;
2328 for (; m < 16; ++m)
2329 putchar(' ');
2330 printf("|\n");
2331 if (nr < r)
2332 break;
2333 }
2334}
2335
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002336typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2337
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002338static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002339generic_inst_dump(unsigned long adr, long count, int praddr,
2340 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341{
2342 int nr, dotted;
2343 unsigned long first_adr;
2344 unsigned long inst, last_inst = 0;
2345 unsigned char val[4];
2346
2347 dotted = 0;
2348 for (first_adr = adr; count > 0; --count, adr += 4) {
2349 nr = mread(adr, val, 4);
2350 if (nr == 0) {
2351 if (praddr) {
2352 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002353 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 }
2355 break;
2356 }
2357 inst = GETWORD(val);
2358 if (adr > first_adr && inst == last_inst) {
2359 if (!dotted) {
2360 printf(" ...\n");
2361 dotted = 1;
2362 }
2363 continue;
2364 }
2365 dotted = 0;
2366 last_inst = inst;
2367 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002368 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002370 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 printf("\n");
2372 }
2373 return adr - first_adr;
2374}
2375
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002376static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002377ppc_inst_dump(unsigned long adr, long count, int praddr)
2378{
2379 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2380}
2381
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382void
2383print_address(unsigned long addr)
2384{
2385 xmon_print_symbol(addr, "\t# ", "");
2386}
2387
Vinay Sridharf312deb2009-05-14 23:13:07 +00002388void
2389dump_log_buf(void)
2390{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002391 struct kmsg_dumper dumper = { .active = 1 };
2392 unsigned char buf[128];
2393 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002394
Michael Ellermane3bc8042012-08-23 22:09:13 +00002395 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002396 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002397 return;
2398 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002399
Michael Ellermane3bc8042012-08-23 22:09:13 +00002400 catch_memory_errors = 1;
2401 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002402
Michael Ellermanca5dd392012-08-23 22:09:12 +00002403 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002404 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002405 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2406 buf[len] = '\0';
2407 printf("%s", buf);
2408 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002409 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002410
Michael Ellermane3bc8042012-08-23 22:09:13 +00002411 sync();
2412 /* wait a little while to see if we get a machine check */
2413 __delay(200);
2414 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002415}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002417#ifdef CONFIG_PPC_POWERNV
2418static void dump_opal_msglog(void)
2419{
2420 unsigned char buf[128];
2421 ssize_t res;
2422 loff_t pos = 0;
2423
2424 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2425 printf("Machine is not running OPAL firmware.\n");
2426 return;
2427 }
2428
2429 if (setjmp(bus_error_jmp) != 0) {
2430 printf("Error dumping OPAL msglog!\n");
2431 return;
2432 }
2433
2434 catch_memory_errors = 1;
2435 sync();
2436
2437 xmon_start_pagination();
2438 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2439 if (res < 0) {
2440 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2441 break;
2442 }
2443 buf[res] = '\0';
2444 printf("%s", buf);
2445 pos += res;
2446 }
2447 xmon_end_pagination();
2448
2449 sync();
2450 /* wait a little while to see if we get a machine check */
2451 __delay(200);
2452 catch_memory_errors = 0;
2453}
2454#endif
2455
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456/*
2457 * Memory operations - move, set, print differences
2458 */
2459static unsigned long mdest; /* destination address */
2460static unsigned long msrc; /* source address */
2461static unsigned long mval; /* byte value to set memory to */
2462static unsigned long mcount; /* # bytes to affect */
2463static unsigned long mdiffs; /* max # differences to print */
2464
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002465static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466memops(int cmd)
2467{
2468 scanhex((void *)&mdest);
2469 if( termch != '\n' )
2470 termch = 0;
2471 scanhex((void *)(cmd == 's'? &mval: &msrc));
2472 if( termch != '\n' )
2473 termch = 0;
2474 scanhex((void *)&mcount);
2475 switch( cmd ){
2476 case 'm':
2477 memmove((void *)mdest, (void *)msrc, mcount);
2478 break;
2479 case 's':
2480 memset((void *)mdest, mval, mcount);
2481 break;
2482 case 'd':
2483 if( termch != '\n' )
2484 termch = 0;
2485 scanhex((void *)&mdiffs);
2486 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2487 break;
2488 }
2489}
2490
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002491static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2493{
2494 unsigned n, prt;
2495
2496 prt = 0;
2497 for( n = nb; n > 0; --n )
2498 if( *p1++ != *p2++ )
2499 if( ++prt <= maxpr )
2500 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2501 p1[-1], p2 - 1, p2[-1]);
2502 if( prt > maxpr )
2503 printf("Total of %d differences\n", prt);
2504}
2505
2506static unsigned mend;
2507static unsigned mask;
2508
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002509static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510memlocate(void)
2511{
2512 unsigned a, n;
2513 unsigned char val[4];
2514
2515 last_cmd = "ml";
2516 scanhex((void *)&mdest);
2517 if (termch != '\n') {
2518 termch = 0;
2519 scanhex((void *)&mend);
2520 if (termch != '\n') {
2521 termch = 0;
2522 scanhex((void *)&mval);
2523 mask = ~0;
2524 if (termch != '\n') termch = 0;
2525 scanhex((void *)&mask);
2526 }
2527 }
2528 n = 0;
2529 for (a = mdest; a < mend; a += 4) {
2530 if (mread(a, val, 4) == 4
2531 && ((GETWORD(val) ^ mval) & mask) == 0) {
2532 printf("%.16x: %.16x\n", a, GETWORD(val));
2533 if (++n >= 10)
2534 break;
2535 }
2536 }
2537}
2538
2539static unsigned long mskip = 0x1000;
2540static unsigned long mlim = 0xffffffff;
2541
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002542static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543memzcan(void)
2544{
2545 unsigned char v;
2546 unsigned a;
2547 int ok, ook;
2548
2549 scanhex(&mdest);
2550 if (termch != '\n') termch = 0;
2551 scanhex(&mskip);
2552 if (termch != '\n') termch = 0;
2553 scanhex(&mlim);
2554 ook = 0;
2555 for (a = mdest; a < mlim; a += mskip) {
2556 ok = mread(a, &v, 1);
2557 if (ok && !ook) {
2558 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 } else if (!ok && ook)
2560 printf("%.8x\n", a - mskip);
2561 ook = ok;
2562 if (a + mskip < a)
2563 break;
2564 }
2565 if (ook)
2566 printf("%.8x\n", a - mskip);
2567}
2568
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002569static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002570{
2571 unsigned long args[8];
2572 unsigned long ret;
2573 int i;
2574 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2575 unsigned long, unsigned long, unsigned long,
2576 unsigned long, unsigned long, unsigned long);
2577 callfunc_t func;
2578
2579 if (!scanhex(&adrs))
2580 return;
2581 if (termch != '\n')
2582 termch = 0;
2583 for (i = 0; i < 8; ++i)
2584 args[i] = 0;
2585 for (i = 0; i < 8; ++i) {
2586 if (!scanhex(&args[i]) || termch == '\n')
2587 break;
2588 termch = 0;
2589 }
2590 func = (callfunc_t) adrs;
2591 ret = 0;
2592 if (setjmp(bus_error_jmp) == 0) {
2593 catch_memory_errors = 1;
2594 sync();
2595 ret = func(args[0], args[1], args[2], args[3],
2596 args[4], args[5], args[6], args[7]);
2597 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10002598 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002599 } else {
2600 printf("*** %x exception occurred\n", fault_except);
2601 }
2602 catch_memory_errors = 0;
2603}
2604
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605/* Input scanning routines */
2606int
2607skipbl(void)
2608{
2609 int c;
2610
2611 if( termch != 0 ){
2612 c = termch;
2613 termch = 0;
2614 } else
2615 c = inchar();
2616 while( c == ' ' || c == '\t' )
2617 c = inchar();
2618 return c;
2619}
2620
2621#define N_PTREGS 44
2622static char *regnames[N_PTREGS] = {
2623 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2624 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2625 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2626 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002627 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2628#ifdef CONFIG_PPC64
2629 "softe",
2630#else
2631 "mq",
2632#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 "trap", "dar", "dsisr", "res"
2634};
2635
2636int
2637scanhex(unsigned long *vp)
2638{
2639 int c, d;
2640 unsigned long v;
2641
2642 c = skipbl();
2643 if (c == '%') {
2644 /* parse register name */
2645 char regname[8];
2646 int i;
2647
2648 for (i = 0; i < sizeof(regname) - 1; ++i) {
2649 c = inchar();
2650 if (!isalnum(c)) {
2651 termch = c;
2652 break;
2653 }
2654 regname[i] = c;
2655 }
2656 regname[i] = 0;
2657 for (i = 0; i < N_PTREGS; ++i) {
2658 if (strcmp(regnames[i], regname) == 0) {
2659 if (xmon_regs == NULL) {
2660 printf("regs not available\n");
2661 return 0;
2662 }
2663 *vp = ((unsigned long *)xmon_regs)[i];
2664 return 1;
2665 }
2666 }
2667 printf("invalid register name '%%%s'\n", regname);
2668 return 0;
2669 }
2670
2671 /* skip leading "0x" if any */
2672
2673 if (c == '0') {
2674 c = inchar();
2675 if (c == 'x') {
2676 c = inchar();
2677 } else {
2678 d = hexdigit(c);
2679 if (d == EOF) {
2680 termch = c;
2681 *vp = 0;
2682 return 1;
2683 }
2684 }
2685 } else if (c == '$') {
2686 int i;
2687 for (i=0; i<63; i++) {
2688 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02002689 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 termch = c;
2691 break;
2692 }
2693 tmpstr[i] = c;
2694 }
2695 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002696 *vp = 0;
2697 if (setjmp(bus_error_jmp) == 0) {
2698 catch_memory_errors = 1;
2699 sync();
2700 *vp = kallsyms_lookup_name(tmpstr);
2701 sync();
2702 }
2703 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 if (!(*vp)) {
2705 printf("unknown symbol '%s'\n", tmpstr);
2706 return 0;
2707 }
2708 return 1;
2709 }
2710
2711 d = hexdigit(c);
2712 if (d == EOF) {
2713 termch = c;
2714 return 0;
2715 }
2716 v = 0;
2717 do {
2718 v = (v << 4) + d;
2719 c = inchar();
2720 d = hexdigit(c);
2721 } while (d != EOF);
2722 termch = c;
2723 *vp = v;
2724 return 1;
2725}
2726
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002727static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728scannl(void)
2729{
2730 int c;
2731
2732 c = termch;
2733 termch = 0;
2734 while( c != '\n' )
2735 c = inchar();
2736}
2737
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002738static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739{
2740 if( '0' <= c && c <= '9' )
2741 return c - '0';
2742 if( 'A' <= c && c <= 'F' )
2743 return c - ('A' - 10);
2744 if( 'a' <= c && c <= 'f' )
2745 return c - ('a' - 10);
2746 return EOF;
2747}
2748
2749void
2750getstring(char *s, int size)
2751{
2752 int c;
2753
2754 c = skipbl();
2755 do {
2756 if( size > 1 ){
2757 *s++ = c;
2758 --size;
2759 }
2760 c = inchar();
2761 } while( c != ' ' && c != '\t' && c != '\n' );
2762 termch = c;
2763 *s = 0;
2764}
2765
2766static char line[256];
2767static char *lineptr;
2768
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002769static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770flush_input(void)
2771{
2772 lineptr = NULL;
2773}
2774
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002775static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776inchar(void)
2777{
2778 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002779 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 lineptr = NULL;
2781 return EOF;
2782 }
2783 lineptr = line;
2784 }
2785 return *lineptr++;
2786}
2787
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002788static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789take_input(char *str)
2790{
2791 lineptr = str;
2792}
2793
2794
2795static void
2796symbol_lookup(void)
2797{
2798 int type = inchar();
2799 unsigned long addr;
2800 static char tmp[64];
2801
2802 switch (type) {
2803 case 'a':
2804 if (scanhex(&addr))
2805 xmon_print_symbol(addr, ": ", "\n");
2806 termch = 0;
2807 break;
2808 case 's':
2809 getstring(tmp, 64);
2810 if (setjmp(bus_error_jmp) == 0) {
2811 catch_memory_errors = 1;
2812 sync();
2813 addr = kallsyms_lookup_name(tmp);
2814 if (addr)
2815 printf("%s: %lx\n", tmp, addr);
2816 else
2817 printf("Symbol '%s' not found.\n", tmp);
2818 sync();
2819 }
2820 catch_memory_errors = 0;
2821 termch = 0;
2822 break;
2823 }
2824}
2825
2826
2827/* Print an address in numeric and symbolic form (if possible) */
2828static void xmon_print_symbol(unsigned long address, const char *mid,
2829 const char *after)
2830{
2831 char *modname;
2832 const char *name = NULL;
2833 unsigned long offset, size;
2834
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002835 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 if (setjmp(bus_error_jmp) == 0) {
2837 catch_memory_errors = 1;
2838 sync();
2839 name = kallsyms_lookup(address, &size, &offset, &modname,
2840 tmpstr);
2841 sync();
2842 /* wait a little while to see if we get a machine check */
2843 __delay(200);
2844 }
2845
2846 catch_memory_errors = 0;
2847
2848 if (name) {
2849 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2850 if (modname)
2851 printf(" [%s]", modname);
2852 }
2853 printf("%s", after);
2854}
2855
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002856#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10002857void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858{
2859 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05302860 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11002861 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862
Michael Ellerman736256e2014-05-26 21:02:14 +10002863 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864
Michael Neuling584f8b72007-12-06 17:24:48 +11002865 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002866 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2867 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Anshuman Khandual8218a302015-07-29 12:40:04 +05302868 if (esid || vsid) {
will schmidtb3b95952007-12-07 08:22:23 +11002869 printf("%02d %016lx %016lx", i, esid, vsid);
Anshuman Khandual8218a302015-07-29 12:40:04 +05302870 if (esid & SLB_ESID_V) {
will schmidtb3b95952007-12-07 08:22:23 +11002871 llp = vsid & SLB_VSID_LLP;
2872 if (vsid & SLB_VSID_B_1T) {
2873 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2874 GET_ESID_1T(esid),
2875 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2876 llp);
2877 } else {
2878 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2879 GET_ESID(esid),
2880 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2881 llp);
2882 }
2883 } else
2884 printf("\n");
2885 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 }
2887}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002888#endif
2889
2890#ifdef CONFIG_PPC_STD_MMU_32
2891void dump_segments(void)
2892{
2893 int i;
2894
2895 printf("sr0-15 =");
2896 for (i = 0; i < 16; ++i)
2897 printf(" %x", mfsrin(i));
2898 printf("\n");
2899}
2900#endif
2901
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002902#ifdef CONFIG_44x
2903static void dump_tlb_44x(void)
2904{
2905 int i;
2906
2907 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2908 unsigned long w0,w1,w2;
2909 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2910 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2911 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2912 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2913 if (w0 & PPC44x_TLB_VALID) {
2914 printf("V %08x -> %01x%08x %c%c%c%c%c",
2915 w0 & PPC44x_TLB_EPN_MASK,
2916 w1 & PPC44x_TLB_ERPN_MASK,
2917 w1 & PPC44x_TLB_RPN_MASK,
2918 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2919 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2920 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2921 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2922 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2923 }
2924 printf("\n");
2925 }
2926}
2927#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002928
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002929#ifdef CONFIG_PPC_BOOK3E
2930static void dump_tlb_book3e(void)
2931{
2932 u32 mmucfg, pidmask, lpidmask;
2933 u64 ramask;
2934 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2935 int mmu_version;
2936 static const char *pgsz_names[] = {
2937 " 1K",
2938 " 2K",
2939 " 4K",
2940 " 8K",
2941 " 16K",
2942 " 32K",
2943 " 64K",
2944 "128K",
2945 "256K",
2946 "512K",
2947 " 1M",
2948 " 2M",
2949 " 4M",
2950 " 8M",
2951 " 16M",
2952 " 32M",
2953 " 64M",
2954 "128M",
2955 "256M",
2956 "512M",
2957 " 1G",
2958 " 2G",
2959 " 4G",
2960 " 8G",
2961 " 16G",
2962 " 32G",
2963 " 64G",
2964 "128G",
2965 "256G",
2966 "512G",
2967 " 1T",
2968 " 2T",
2969 };
2970
2971 /* Gather some infos about the MMU */
2972 mmucfg = mfspr(SPRN_MMUCFG);
2973 mmu_version = (mmucfg & 3) + 1;
2974 ntlbs = ((mmucfg >> 2) & 3) + 1;
2975 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2976 lpidsz = (mmucfg >> 24) & 0xf;
2977 rasz = (mmucfg >> 16) & 0x7f;
2978 if ((mmu_version > 1) && (mmucfg & 0x10000))
2979 lrat = 1;
2980 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2981 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2982 pidmask = (1ul << pidsz) - 1;
2983 lpidmask = (1ul << lpidsz) - 1;
2984 ramask = (1ull << rasz) - 1;
2985
2986 for (tlb = 0; tlb < ntlbs; tlb++) {
2987 u32 tlbcfg;
2988 int nent, assoc, new_cc = 1;
2989 printf("TLB %d:\n------\n", tlb);
2990 switch(tlb) {
2991 case 0:
2992 tlbcfg = mfspr(SPRN_TLB0CFG);
2993 break;
2994 case 1:
2995 tlbcfg = mfspr(SPRN_TLB1CFG);
2996 break;
2997 case 2:
2998 tlbcfg = mfspr(SPRN_TLB2CFG);
2999 break;
3000 case 3:
3001 tlbcfg = mfspr(SPRN_TLB3CFG);
3002 break;
3003 default:
3004 printf("Unsupported TLB number !\n");
3005 continue;
3006 }
3007 nent = tlbcfg & 0xfff;
3008 assoc = (tlbcfg >> 24) & 0xff;
3009 for (i = 0; i < nent; i++) {
3010 u32 mas0 = MAS0_TLBSEL(tlb);
3011 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3012 u64 mas2 = 0;
3013 u64 mas7_mas3;
3014 int esel = i, cc = i;
3015
3016 if (assoc != 0) {
3017 cc = i / assoc;
3018 esel = i % assoc;
3019 mas2 = cc * 0x1000;
3020 }
3021
3022 mas0 |= MAS0_ESEL(esel);
3023 mtspr(SPRN_MAS0, mas0);
3024 mtspr(SPRN_MAS1, mas1);
3025 mtspr(SPRN_MAS2, mas2);
3026 asm volatile("tlbre 0,0,0" : : : "memory");
3027 mas1 = mfspr(SPRN_MAS1);
3028 mas2 = mfspr(SPRN_MAS2);
3029 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3030 if (assoc && (i % assoc) == 0)
3031 new_cc = 1;
3032 if (!(mas1 & MAS1_VALID))
3033 continue;
3034 if (assoc == 0)
3035 printf("%04x- ", i);
3036 else if (new_cc)
3037 printf("%04x-%c", cc, 'A' + esel);
3038 else
3039 printf(" |%c", 'A' + esel);
3040 new_cc = 0;
3041 printf(" %016llx %04x %s %c%c AS%c",
3042 mas2 & ~0x3ffull,
3043 (mas1 >> 16) & 0x3fff,
3044 pgsz_names[(mas1 >> 7) & 0x1f],
3045 mas1 & MAS1_IND ? 'I' : ' ',
3046 mas1 & MAS1_IPROT ? 'P' : ' ',
3047 mas1 & MAS1_TS ? '1' : '0');
3048 printf(" %c%c%c%c%c%c%c",
3049 mas2 & MAS2_X0 ? 'a' : ' ',
3050 mas2 & MAS2_X1 ? 'v' : ' ',
3051 mas2 & MAS2_W ? 'w' : ' ',
3052 mas2 & MAS2_I ? 'i' : ' ',
3053 mas2 & MAS2_M ? 'm' : ' ',
3054 mas2 & MAS2_G ? 'g' : ' ',
3055 mas2 & MAS2_E ? 'e' : ' ');
3056 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3057 if (mas1 & MAS1_IND)
3058 printf(" %s\n",
3059 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3060 else
3061 printf(" U%c%c%c S%c%c%c\n",
3062 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3063 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3064 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3065 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3066 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3067 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3068 }
3069 }
3070}
3071#endif /* CONFIG_PPC_BOOK3E */
3072
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003073static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003075 if (enable) {
3076 __debugger = xmon;
3077 __debugger_ipi = xmon_ipi;
3078 __debugger_bpt = xmon_bpt;
3079 __debugger_sstep = xmon_sstep;
3080 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003081 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003082 __debugger_fault_handler = xmon_fault_handler;
3083 } else {
3084 __debugger = NULL;
3085 __debugger_ipi = NULL;
3086 __debugger_bpt = NULL;
3087 __debugger_sstep = NULL;
3088 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003089 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003090 __debugger_fault_handler = NULL;
3091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003093
3094#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003095static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003096{
3097 /* ensure xmon is enabled */
3098 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003099 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003100}
3101
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003102static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003103 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003104 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003105 .action_msg = "Entering xmon",
3106};
3107
3108static int __init setup_xmon_sysrq(void)
3109{
3110 register_sysrq_key('x', &sysrq_xmon_op);
3111 return 0;
3112}
3113__initcall(setup_xmon_sysrq);
3114#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003115
Olaf Heringf5e6a282007-06-24 16:57:08 +10003116static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10003117
3118static int __init early_parse_xmon(char *p)
3119{
3120 if (!p || strncmp(p, "early", 5) == 0) {
3121 /* just "xmon" is equivalent to "xmon=early" */
3122 xmon_init(1);
3123 xmon_early = 1;
3124 } else if (strncmp(p, "on", 2) == 0)
3125 xmon_init(1);
3126 else if (strncmp(p, "off", 3) == 0)
3127 xmon_off = 1;
3128 else if (strncmp(p, "nobt", 4) == 0)
3129 xmon_no_auto_backtrace = 1;
3130 else
3131 return 1;
3132
3133 return 0;
3134}
3135early_param("xmon", early_parse_xmon);
3136
3137void __init xmon_setup(void)
3138{
3139#ifdef CONFIG_XMON_DEFAULT
3140 if (!xmon_off)
3141 xmon_init(1);
3142#endif
3143 if (xmon_early)
3144 debugger(NULL);
3145}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003146
Arnd Bergmanne0555952006-11-27 19:18:55 +01003147#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003148
3149struct spu_info {
3150 struct spu *spu;
3151 u64 saved_mfc_sr1_RW;
3152 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003153 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003154 u8 stopped_ok;
3155};
3156
3157#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3158
3159static struct spu_info spu_info[XMON_NUM_SPUS];
3160
3161void xmon_register_spus(struct list_head *list)
3162{
3163 struct spu *spu;
3164
3165 list_for_each_entry(spu, list, full_list) {
3166 if (spu->number >= XMON_NUM_SPUS) {
3167 WARN_ON(1);
3168 continue;
3169 }
3170
3171 spu_info[spu->number].spu = spu;
3172 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003173 spu_info[spu->number].dump_addr = (unsigned long)
3174 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003175 }
3176}
3177
3178static void stop_spus(void)
3179{
3180 struct spu *spu;
3181 int i;
3182 u64 tmp;
3183
3184 for (i = 0; i < XMON_NUM_SPUS; i++) {
3185 if (!spu_info[i].spu)
3186 continue;
3187
3188 if (setjmp(bus_error_jmp) == 0) {
3189 catch_memory_errors = 1;
3190 sync();
3191
3192 spu = spu_info[i].spu;
3193
3194 spu_info[i].saved_spu_runcntl_RW =
3195 in_be32(&spu->problem->spu_runcntl_RW);
3196
3197 tmp = spu_mfc_sr1_get(spu);
3198 spu_info[i].saved_mfc_sr1_RW = tmp;
3199
3200 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3201 spu_mfc_sr1_set(spu, tmp);
3202
3203 sync();
3204 __delay(200);
3205
3206 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003207
3208 printf("Stopped spu %.2d (was %s)\n", i,
3209 spu_info[i].saved_spu_runcntl_RW ?
3210 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003211 } else {
3212 catch_memory_errors = 0;
3213 printf("*** Error stopping spu %.2d\n", i);
3214 }
3215 catch_memory_errors = 0;
3216 }
3217}
3218
3219static void restart_spus(void)
3220{
3221 struct spu *spu;
3222 int i;
3223
3224 for (i = 0; i < XMON_NUM_SPUS; i++) {
3225 if (!spu_info[i].spu)
3226 continue;
3227
3228 if (!spu_info[i].stopped_ok) {
3229 printf("*** Error, spu %d was not successfully stopped"
3230 ", not restarting\n", i);
3231 continue;
3232 }
3233
3234 if (setjmp(bus_error_jmp) == 0) {
3235 catch_memory_errors = 1;
3236 sync();
3237
3238 spu = spu_info[i].spu;
3239 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3240 out_be32(&spu->problem->spu_runcntl_RW,
3241 spu_info[i].saved_spu_runcntl_RW);
3242
3243 sync();
3244 __delay(200);
3245
3246 printf("Restarted spu %.2d\n", i);
3247 } else {
3248 catch_memory_errors = 0;
3249 printf("*** Error restarting spu %.2d\n", i);
3250 }
3251 catch_memory_errors = 0;
3252 }
3253}
3254
Michael Ellermana8984972006-10-24 18:31:28 +02003255#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003256#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003257do { \
3258 if (setjmp(bus_error_jmp) == 0) { \
3259 catch_memory_errors = 1; \
3260 sync(); \
3261 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003262 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003263 sync(); \
3264 __delay(200); \
3265 } else { \
3266 catch_memory_errors = 0; \
3267 printf(" %-*s = *** Error reading field.\n", \
3268 DUMP_WIDTH, #field); \
3269 } \
3270 catch_memory_errors = 0; \
3271} while (0)
3272
Michael Ellerman437a0702006-11-23 00:46:39 +01003273#define DUMP_FIELD(obj, format, field) \
3274 DUMP_VALUE(format, field, obj->field)
3275
Michael Ellermana8984972006-10-24 18:31:28 +02003276static void dump_spu_fields(struct spu *spu)
3277{
3278 printf("Dumping spu fields at address %p:\n", spu);
3279
3280 DUMP_FIELD(spu, "0x%x", number);
3281 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003282 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3283 DUMP_FIELD(spu, "0x%p", local_store);
3284 DUMP_FIELD(spu, "0x%lx", ls_size);
3285 DUMP_FIELD(spu, "0x%x", node);
3286 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003287 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003288 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003289 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3290 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003291 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3292 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3293 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3294 DUMP_FIELD(spu, "0x%x", slb_replace);
3295 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003296 DUMP_FIELD(spu, "0x%p", mm);
3297 DUMP_FIELD(spu, "0x%p", ctx);
3298 DUMP_FIELD(spu, "0x%p", rq);
3299 DUMP_FIELD(spu, "0x%p", timestamp);
3300 DUMP_FIELD(spu, "0x%lx", problem_phys);
3301 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003302 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3303 in_be32(&spu->problem->spu_runcntl_RW));
3304 DUMP_VALUE("0x%x", problem->spu_status_R,
3305 in_be32(&spu->problem->spu_status_R));
3306 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3307 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003308 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003309 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003310}
3311
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003312int
3313spu_inst_dump(unsigned long adr, long count, int praddr)
3314{
3315 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3316}
3317
3318static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003319{
3320 unsigned long offset, addr, ls_addr;
3321
3322 if (setjmp(bus_error_jmp) == 0) {
3323 catch_memory_errors = 1;
3324 sync();
3325 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3326 sync();
3327 __delay(200);
3328 } else {
3329 catch_memory_errors = 0;
3330 printf("*** Error: accessing spu info for spu %d\n", num);
3331 return;
3332 }
3333 catch_memory_errors = 0;
3334
3335 if (scanhex(&offset))
3336 addr = ls_addr + offset;
3337 else
3338 addr = spu_info[num].dump_addr;
3339
3340 if (addr >= ls_addr + LS_SIZE) {
3341 printf("*** Error: address outside of local store\n");
3342 return;
3343 }
3344
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003345 switch (subcmd) {
3346 case 'i':
3347 addr += spu_inst_dump(addr, 16, 1);
3348 last_cmd = "sdi\n";
3349 break;
3350 default:
3351 prdump(addr, 64);
3352 addr += 64;
3353 last_cmd = "sd\n";
3354 break;
3355 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003356
3357 spu_info[num].dump_addr = addr;
3358}
3359
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003360static int do_spu_cmd(void)
3361{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003362 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003363 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003364
3365 cmd = inchar();
3366 switch (cmd) {
3367 case 's':
3368 stop_spus();
3369 break;
3370 case 'r':
3371 restart_spus();
3372 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003373 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003374 subcmd = inchar();
3375 if (isxdigit(subcmd) || subcmd == '\n')
3376 termch = subcmd;
3377 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003378 scanhex(&num);
3379 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003380 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003381 return 0;
3382 }
3383
3384 switch (cmd) {
3385 case 'f':
3386 dump_spu_fields(spu_info[num].spu);
3387 break;
3388 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003389 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003390 break;
3391 }
3392
Michael Ellermana8984972006-10-24 18:31:28 +02003393 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003394 default:
3395 return -1;
3396 }
3397
3398 return 0;
3399}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003400#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003401static int do_spu_cmd(void)
3402{
3403 return -1;
3404}
3405#endif