blob: 760545519a0bc3b7a8988824a9a677ad416286fe [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Routines providing a simple monitor for use on the PowerMac.
3 *
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004 * Copyright (C) 1996-2005 Paul Mackerras.
Michael Ellerman476792832006-10-03 14:12:08 +10005 * Copyright (C) 2001 PPC64 Team, IBM Corp
6 * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/smp.h>
16#include <linux/mm.h>
17#include <linux/reboot.h>
18#include <linux/delay.h>
19#include <linux/kallsyms.h>
Michael Ellermanca5dd392012-08-23 22:09:12 +000020#include <linux/kmsg_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040022#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110023#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080024#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010025#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080026#include <linux/bug.h>
Anton Blancharda71d64b2014-08-05 14:55:00 +100027#include <linux/nmi.h>
Vincent Bernat05b981f2014-07-15 13:43:47 +020028#include <linux/ctype.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <asm/ptrace.h>
31#include <asm/string.h>
32#include <asm/prom.h>
33#include <asm/machdep.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100034#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/processor.h>
36#include <asm/pgtable.h>
37#include <asm/mmu.h>
38#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/cputable.h>
40#include <asm/rtas.h>
41#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100042#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020043#include <asm/spu.h>
44#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110045#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000046#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010047#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000048#include <asm/hw_breakpoint.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100049
Andrew Donnellanfde93a02016-02-09 18:17:49 +110050#include <asm/opal.h>
51#include <asm/firmware.h>
52
Paul Mackerrasf78541d2005-10-28 22:53:37 +100053#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-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;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +100089static int catch_spr_faults;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92/* Breakpoint stuff */
93struct bpt {
94 unsigned long address;
95 unsigned int instr[2];
96 atomic_t ref_count;
97 int enabled;
98 unsigned long pad;
99};
100
101/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100102#define BP_CIABR 1
103#define BP_TRAP 2
104#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
106#define NBPTS 256
107static struct bpt bpts[NBPTS];
108static struct bpt dabr;
109static struct bpt *iabr;
110static unsigned bpinstr = 0x7fe00008; /* trap */
111
112#define BP_NUM(bp) ((bp) - bpts + 1)
113
114/* Prototypes */
115static int cmds(struct pt_regs *);
116static int mread(unsigned long, void *, int);
117static int mwrite(unsigned long, void *, int);
118static int handle_fault(struct pt_regs *);
119static void byterev(unsigned char *, int);
120static void memex(void);
121static int bsesc(void);
122static void dump(void);
123static void prdump(unsigned long, long);
124static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000125static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100126
127#ifdef CONFIG_PPC_POWERNV
128static void dump_opal_msglog(void);
129#else
130static inline void dump_opal_msglog(void)
131{
132 printf("Machine is not running OPAL firmware.\n");
133}
134#endif
135
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136static void backtrace(struct pt_regs *);
137static void excprint(struct pt_regs *);
138static void prregs(struct pt_regs *);
139static void memops(int);
140static void memlocate(void);
141static void memzcan(void);
142static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
143int skipbl(void);
144int scanhex(unsigned long *valp);
145static void scannl(void);
146static int hexdigit(int);
147void getstring(char *, int);
148static void flush_input(void);
149static int inchar(void);
150static void take_input(char *);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000151static int read_spr(int, unsigned long *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static void write_spr(int, unsigned long);
153static void super_regs(void);
154static void remove_bpts(void);
155static void insert_bpts(void);
156static void remove_cpu_bpts(void);
157static void insert_cpu_bpts(void);
158static struct bpt *at_breakpoint(unsigned long pc);
159static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
160static int do_step(struct pt_regs *);
161static void bpt_cmds(void);
162static void cacheflush(void);
163static int cpu_cmd(void);
164static void csum(void);
165static void bootcmds(void);
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000166static void proccall(void);
Douglas Miller6dfb5402015-11-23 09:01:15 -0600167static void show_tasks(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168void dump_segments(void);
169static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200170static void xmon_show_stack(unsigned long sp, unsigned long lr,
171 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static void xmon_print_symbol(unsigned long address, const char *mid,
173 const char *after);
174static const char *getvecname(unsigned long vec);
175
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200176static int do_spu_cmd(void);
177
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100178#ifdef CONFIG_44x
179static void dump_tlb_44x(void);
180#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000181#ifdef CONFIG_PPC_BOOK3E
182static void dump_tlb_book3e(void);
183#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100184
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000185static int xmon_no_auto_backtrace;
Olaf Hering26c8af52006-09-08 16:29:21 +0200186
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000187#ifdef CONFIG_PPC64
188#define REG "%.16lx"
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000189#else
190#define REG "%.8lx"
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000191#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100193#ifdef __LITTLE_ENDIAN__
194#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
195#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100197#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199static char *help_string = "\
200Commands:\n\
201 b show breakpoints\n\
202 bd set data breakpoint\n\
203 bi set instruction breakpoint\n\
204 bc clear breakpoint\n"
205#ifdef CONFIG_SMP
206 "\
207 c print cpus stopped in xmon\n\
208 c# try to switch to cpu number h (in hex)\n"
209#endif
210 "\
211 C checksum\n\
212 d dump bytes\n\
213 di dump instructions\n\
214 df dump float values\n\
215 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000216 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100217#ifdef CONFIG_PPC_POWERNV
218 "\
219 do dump the OPAL message log\n"
220#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000221#ifdef CONFIG_PPC64
222 "\
223 dp[#] dump paca for current cpu, or cpu #\n\
224 dpa dump paca for all possible cpus\n"
225#endif
226 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100227 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 e print exception information\n\
229 f flush cache\n\
230 la lookup symbol+offset of specified address\n\
231 ls lookup address of specified symbol\n\
232 m examine/change memory\n\
233 mm move a block of memory\n\
234 ms set a block of memory\n\
235 md compare two blocks of memory\n\
236 ml locate a block of memory\n\
237 mz zero a block of memory\n\
238 mi show information about memory allocation\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000239 p call a procedure\n\
Douglas Miller6dfb5402015-11-23 09:01:15 -0600240 P list processes/tasks\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\
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000251 Sa print all SPRs\n\
252 Sr # read SPR #\n\
253 Sw #v write v to SPR #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100256 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000257#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000258" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000259#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000260" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000261#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100262" u dump TLB\n"
263#endif
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000264" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100265" # n limit output to n lines per page (for dp, dpa, dl)\n"
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000266" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 zh halt\n"
268;
269
270static struct pt_regs *xmon_regs;
271
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000272static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273{
274 asm volatile("sync; isync");
275}
276
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000277static inline void store_inst(void *p)
278{
279 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
280}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000282static inline void cflush(void *p)
283{
284 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
285}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000287static inline void cinval(void *p)
288{
289 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
290}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530292/**
293 * write_ciabr() - write the CIABR SPR
294 * @ciabr: The value to write.
295 *
296 * This function writes a value to the CIARB register either directly
297 * through mtspr instruction if the kernel is in HV privilege mode or
298 * call a hypervisor function to achieve the same in case the kernel
299 * is in supervisor privilege mode.
300 */
301static void write_ciabr(unsigned long ciabr)
302{
303 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
304 return;
305
306 if (cpu_has_feature(CPU_FTR_HVMODE)) {
307 mtspr(SPRN_CIABR, ciabr);
308 return;
309 }
310 plapr_set_ciabr(ciabr);
311}
312
313/**
314 * set_ciabr() - set the CIABR
315 * @addr: The value to set.
316 *
317 * This function sets the correct privilege value into the the HW
318 * breakpoint address before writing it up in the CIABR register.
319 */
320static void set_ciabr(unsigned long addr)
321{
322 addr &= ~CIABR_PRIV;
323
324 if (cpu_has_feature(CPU_FTR_HVMODE))
325 addr |= CIABR_PRIV_HYPER;
326 else
327 addr |= CIABR_PRIV_SUPER;
328 write_ciabr(addr);
329}
330
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331/*
332 * Disable surveillance (the service processor watchdog function)
333 * while we are in xmon.
334 * XXX we should re-enable it when we leave. :)
335 */
336#define SURVEILLANCE_TOKEN 9000
337
338static inline void disable_surveillance(void)
339{
340#ifdef CONFIG_PPC_PSERIES
341 /* Since this can't be a module, args should end up below 4GB. */
342 static struct rtas_args args;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100343 int token;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 /*
346 * At this point we have got all the cpus we can into
347 * xmon, so there is hopefully no other cpu calling RTAS
348 * at the moment, even though we don't take rtas.lock.
349 * If we did try to take rtas.lock there would be a
350 * real possibility of deadlock.
351 */
Michael Ellerman08eb1052015-11-24 22:26:09 +1100352 token = rtas_token("set-indicator");
353 if (token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100355
356 rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0);
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358#endif /* CONFIG_PPC_PSERIES */
359}
360
361#ifdef CONFIG_SMP
362static int xmon_speaker;
363
364static void get_output_lock(void)
365{
366 int me = smp_processor_id() + 0x100;
367 int last_speaker = 0, prev;
368 long timeout;
369
370 if (xmon_speaker == me)
371 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100372
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100374 last_speaker = cmpxchg(&xmon_speaker, 0, me);
375 if (last_speaker == 0)
376 return;
377
Michael Ellerman15075892013-12-23 23:46:05 +1100378 /*
379 * Wait a full second for the lock, we might be on a slow
380 * console, but check every 100us.
381 */
382 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100384 if (--timeout > 0) {
385 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100387 }
388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 /* hostile takeover */
390 prev = cmpxchg(&xmon_speaker, last_speaker, me);
391 if (prev == last_speaker)
392 return;
393 break;
394 }
395 }
396}
397
398static void release_output_lock(void)
399{
400 xmon_speaker = 0;
401}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000402
403int cpus_are_in_xmon(void)
404{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000405 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000406}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407#endif
408
Josh Boyerdaf8f402009-09-23 03:51:04 +0000409static inline int unrecoverable_excp(struct pt_regs *regs)
410{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000411#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000412 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000413 return 0;
414#else
415 return ((regs->msr & MSR_RI) == 0);
416#endif
417}
418
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000419static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420{
421 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 struct bpt *bp;
423 long recurse_jmp[JMP_BUF_LEN];
424 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100425 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426#ifdef CONFIG_SMP
427 int cpu;
428 int secondary;
429 unsigned long timeout;
430#endif
431
Anton Blanchardf13659e2007-03-21 01:48:34 +1100432 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000433 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
435 bp = in_breakpoint_table(regs->nip, &offset);
436 if (bp != NULL) {
437 regs->nip = bp->address + offset;
438 atomic_dec(&bp->ref_count);
439 }
440
441 remove_cpu_bpts();
442
443#ifdef CONFIG_SMP
444 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000445 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000446 /*
447 * We catch SPR read/write faults here because the 0x700, 0xf60
448 * etc. handlers don't call debugger_fault_handler().
449 */
450 if (catch_spr_faults)
451 longjmp(bus_error_jmp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 get_output_lock();
453 excprint(regs);
454 printf("cpu 0x%x: Exception %lx %s in xmon, "
455 "returning to main loop\n",
456 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000457 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 longjmp(xmon_fault_jmp[cpu], 1);
459 }
460
461 if (setjmp(recurse_jmp) != 0) {
462 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000463 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 printf("xmon: WARNING: bad recursive fault "
465 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000466 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 goto waiting;
468 }
469 secondary = !(xmon_taken && cpu == xmon_owner);
470 goto cmdloop;
471 }
472
473 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
475 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000476 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000478 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 fromipi = 0;
480
481 if (!fromipi) {
482 get_output_lock();
483 excprint(regs);
484 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000485 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 cpu, BP_NUM(bp));
487 xmon_print_symbol(regs->nip, " ", ")\n");
488 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000489 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 printf("WARNING: exception is not recoverable, "
491 "can't continue\n");
492 release_output_lock();
493 }
494
Michael Ellermand2b496e2013-12-23 23:46:06 +1100495 cpumask_set_cpu(cpu, &cpus_in_xmon);
496
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 waiting:
498 secondary = 1;
499 while (secondary && !xmon_gate) {
500 if (in_xmon == 0) {
501 if (fromipi)
502 goto leave;
503 secondary = test_and_set_bit(0, &in_xmon);
504 }
505 barrier();
506 }
507
508 if (!secondary && !xmon_gate) {
509 /* we are the first cpu to come in */
510 /* interrupt other cpu(s) */
511 int ncpus = num_online_cpus();
512
513 xmon_owner = cpu;
514 mb();
515 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000516 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 /* wait for other cpus to come in */
518 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000519 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 break;
521 barrier();
522 }
523 }
524 remove_bpts();
525 disable_surveillance();
526 /* for breakpoint or single step, print the current instr. */
527 if (bp || TRAP(regs) == 0xd00)
528 ppc_inst_dump(regs->nip, 1, 0);
529 printf("enter ? for help\n");
530 mb();
531 xmon_gate = 1;
532 barrier();
533 }
534
535 cmdloop:
536 while (in_xmon) {
537 if (secondary) {
538 if (cpu == xmon_owner) {
539 if (!test_and_set_bit(0, &xmon_taken)) {
540 secondary = 0;
541 continue;
542 }
543 /* missed it */
544 while (cpu == xmon_owner)
545 barrier();
546 }
547 barrier();
548 } else {
549 cmd = cmds(regs);
550 if (cmd != 0) {
551 /* exiting xmon */
552 insert_bpts();
553 xmon_gate = 0;
554 wmb();
555 in_xmon = 0;
556 break;
557 }
558 /* have switched to some other cpu */
559 secondary = 1;
560 }
561 }
562 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000563 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565#else
566 /* UP is simple... */
567 if (in_xmon) {
568 printf("Exception %lx %s in xmon, returning to main loop\n",
569 regs->trap, getvecname(TRAP(regs)));
570 longjmp(xmon_fault_jmp[0], 1);
571 }
572 if (setjmp(recurse_jmp) == 0) {
573 xmon_fault_jmp[0] = recurse_jmp;
574 in_xmon = 1;
575
576 excprint(regs);
577 bp = at_breakpoint(regs->nip);
578 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000579 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 xmon_print_symbol(regs->nip, " ", ")\n");
581 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000582 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 printf("WARNING: exception is not recoverable, "
584 "can't continue\n");
585 remove_bpts();
586 disable_surveillance();
587 /* for breakpoint or single step, print the current instr. */
588 if (bp || TRAP(regs) == 0xd00)
589 ppc_inst_dump(regs->nip, 1, 0);
590 printf("enter ? for help\n");
591 }
592
593 cmd = cmds(regs);
594
595 insert_bpts();
596 in_xmon = 0;
597#endif
598
Josh Boyercdd39042009-10-05 04:46:05 +0000599#ifdef CONFIG_BOOKE
600 if (regs->msr & MSR_DE) {
601 bp = at_breakpoint(regs->nip);
602 if (bp != NULL) {
603 regs->nip = (unsigned long) &bp->instr[0];
604 atomic_inc(&bp->ref_count);
605 }
606 }
607#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000608 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 bp = at_breakpoint(regs->nip);
610 if (bp != NULL) {
611 int stepped = emulate_step(regs, bp->instr[0]);
612 if (stepped == 0) {
613 regs->nip = (unsigned long) &bp->instr[0];
614 atomic_inc(&bp->ref_count);
615 } else if (stepped < 0) {
616 printf("Couldn't single-step %s instruction\n",
617 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
618 }
619 }
620 }
Josh Boyercdd39042009-10-05 04:46:05 +0000621#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 insert_cpu_bpts();
623
Anton Blancharda71d64b2014-08-05 14:55:00 +1000624 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100625 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000627 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628}
629
630int xmon(struct pt_regs *excp)
631{
632 struct pt_regs regs;
633
634 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000635 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 excp = &regs;
637 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200638
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 return xmon_core(excp, 0);
640}
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000641EXPORT_SYMBOL(xmon);
642
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000643irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000644{
645 unsigned long flags;
646 local_irq_save(flags);
647 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000648 xmon(get_irq_regs());
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000649 local_irq_restore(flags);
650 return IRQ_HANDLED;
651}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000653static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654{
655 struct bpt *bp;
656 unsigned long offset;
657
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000658 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 return 0;
660
661 /* Are we at the trap at bp->instr[1] for some bp? */
662 bp = in_breakpoint_table(regs->nip, &offset);
663 if (bp != NULL && offset == 4) {
664 regs->nip = bp->address + 4;
665 atomic_dec(&bp->ref_count);
666 return 1;
667 }
668
669 /* Are we at a breakpoint? */
670 bp = at_breakpoint(regs->nip);
671 if (!bp)
672 return 0;
673
674 xmon_core(regs, 0);
675
676 return 1;
677}
678
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000679static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
681 if (user_mode(regs))
682 return 0;
683 xmon_core(regs, 0);
684 return 1;
685}
686
Michael Neuling9422de32012-12-20 14:06:44 +0000687static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000689 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000691 if (dabr.enabled == 0)
692 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 xmon_core(regs, 0);
694 return 1;
695}
696
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000697static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000699 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000701 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 return 0;
703 xmon_core(regs, 0);
704 return 1;
705}
706
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000707static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
709#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000710 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 xmon_core(regs, 1);
712#endif
713 return 0;
714}
715
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000716static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717{
718 struct bpt *bp;
719 unsigned long offset;
720
721 if (in_xmon && catch_memory_errors)
722 handle_fault(regs); /* doesn't return */
723
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000724 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 bp = in_breakpoint_table(regs->nip, &offset);
726 if (bp != NULL) {
727 regs->nip = bp->address + offset;
728 atomic_dec(&bp->ref_count);
729 }
730 }
731
732 return 0;
733}
734
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735static struct bpt *at_breakpoint(unsigned long pc)
736{
737 int i;
738 struct bpt *bp;
739
740 bp = bpts;
741 for (i = 0; i < NBPTS; ++i, ++bp)
742 if (bp->enabled && pc == bp->address)
743 return bp;
744 return NULL;
745}
746
747static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
748{
749 unsigned long off;
750
751 off = nip - (unsigned long) bpts;
752 if (off >= sizeof(bpts))
753 return NULL;
754 off %= sizeof(struct bpt);
755 if (off != offsetof(struct bpt, instr[0])
756 && off != offsetof(struct bpt, instr[1]))
757 return NULL;
758 *offp = off - offsetof(struct bpt, instr[0]);
759 return (struct bpt *) (nip - off);
760}
761
762static struct bpt *new_breakpoint(unsigned long a)
763{
764 struct bpt *bp;
765
766 a &= ~3UL;
767 bp = at_breakpoint(a);
768 if (bp)
769 return bp;
770
771 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
772 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
773 bp->address = a;
774 bp->instr[1] = bpinstr;
775 store_inst(&bp->instr[1]);
776 return bp;
777 }
778 }
779
780 printf("Sorry, no free breakpoints. Please clear one first.\n");
781 return NULL;
782}
783
784static void insert_bpts(void)
785{
786 int i;
787 struct bpt *bp;
788
789 bp = bpts;
790 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100791 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 continue;
793 if (mread(bp->address, &bp->instr[0], 4) != 4) {
794 printf("Couldn't read instruction at %lx, "
795 "disabling breakpoint there\n", bp->address);
796 bp->enabled = 0;
797 continue;
798 }
799 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
800 printf("Breakpoint at %lx is on an mtmsrd or rfid "
801 "instruction, disabling it\n", bp->address);
802 bp->enabled = 0;
803 continue;
804 }
805 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100806 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 continue;
808 if (mwrite(bp->address, &bpinstr, 4) != 4) {
809 printf("Couldn't write instruction at %lx, "
810 "disabling breakpoint there\n", bp->address);
811 bp->enabled &= ~BP_TRAP;
812 continue;
813 }
814 store_inst((void *)bp->address);
815 }
816}
817
818static void insert_cpu_bpts(void)
819{
Michael Neuling9422de32012-12-20 14:06:44 +0000820 struct arch_hw_breakpoint brk;
821
822 if (dabr.enabled) {
823 brk.address = dabr.address;
824 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
825 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400826 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000827 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530828
829 if (iabr)
830 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831}
832
833static void remove_bpts(void)
834{
835 int i;
836 struct bpt *bp;
837 unsigned instr;
838
839 bp = bpts;
840 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100841 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 continue;
843 if (mread(bp->address, &instr, 4) == 4
844 && instr == bpinstr
845 && mwrite(bp->address, &bp->instr, 4) != 4)
846 printf("Couldn't remove breakpoint at %lx\n",
847 bp->address);
848 else
849 store_inst((void *)bp->address);
850 }
851}
852
853static void remove_cpu_bpts(void)
854{
Michael Neuling9422de32012-12-20 14:06:44 +0000855 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530856 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857}
858
Sam bobroff958b7c82015-10-08 11:50:23 +1100859static void set_lpp_cmd(void)
860{
861 unsigned long lpp;
862
863 if (!scanhex(&lpp)) {
864 printf("Invalid number.\n");
865 lpp = 0;
866 }
867 xmon_set_pagination_lpp(lpp);
868}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869/* Command interpreting routine */
870static char *last_cmd;
871
872static int
873cmds(struct pt_regs *excp)
874{
875 int cmd = 0;
876
877 last_cmd = NULL;
878 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200879
880 if (!xmon_no_auto_backtrace) {
881 xmon_no_auto_backtrace = 1;
882 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
883 }
884
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 for(;;) {
886#ifdef CONFIG_SMP
887 printf("%x:", smp_processor_id());
888#endif /* CONFIG_SMP */
889 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 flush_input();
891 termch = 0;
892 cmd = skipbl();
893 if( cmd == '\n' ) {
894 if (last_cmd == NULL)
895 continue;
896 take_input(last_cmd);
897 last_cmd = NULL;
898 cmd = inchar();
899 }
900 switch (cmd) {
901 case 'm':
902 cmd = inchar();
903 switch (cmd) {
904 case 'm':
905 case 's':
906 case 'd':
907 memops(cmd);
908 break;
909 case 'l':
910 memlocate();
911 break;
912 case 'z':
913 memzcan();
914 break;
915 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700916 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 break;
918 default:
919 termch = cmd;
920 memex();
921 }
922 break;
923 case 'd':
924 dump();
925 break;
926 case 'l':
927 symbol_lookup();
928 break;
929 case 'r':
930 prregs(excp); /* print regs */
931 break;
932 case 'e':
933 excprint(excp);
934 break;
935 case 'S':
936 super_regs();
937 break;
938 case 't':
939 backtrace(excp);
940 break;
941 case 'f':
942 cacheflush();
943 break;
944 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200945 if (do_spu_cmd() == 0)
946 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 if (do_step(excp))
948 return cmd;
949 break;
950 case 'x':
951 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100952 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100954 printf(" <no input ...>\n");
955 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 return cmd;
957 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000958 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 break;
Sam bobroff958b7c82015-10-08 11:50:23 +1100960 case '#':
961 set_lpp_cmd();
962 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 case 'b':
964 bpt_cmds();
965 break;
966 case 'C':
967 csum();
968 break;
969 case 'c':
970 if (cpu_cmd())
971 return 0;
972 break;
973 case 'z':
974 bootcmds();
975 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000976 case 'p':
977 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -0600979 case 'P':
980 show_tasks();
981 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000982#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 case 'u':
984 dump_segments();
985 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +1100986#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100987 case 'u':
988 dump_tlb_44x();
989 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000990#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000991 case 'u':
992 dump_tlb_book3e();
993 break;
994#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 default:
996 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000997 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 if (' ' < cmd && cmd <= '~')
999 putchar(cmd);
1000 else
1001 printf("\\x%x", cmd);
1002 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +00001003 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 printf(" (type ? for help)\n");
1005 break;
1006 }
1007 }
1008}
1009
Josh Boyercdd39042009-10-05 04:46:05 +00001010#ifdef CONFIG_BOOKE
1011static int do_step(struct pt_regs *regs)
1012{
1013 regs->msr |= MSR_DE;
1014 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1015 return 1;
1016}
1017#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018/*
1019 * Step a single instruction.
1020 * Some instructions we emulate, others we execute with MSR_SE set.
1021 */
1022static int do_step(struct pt_regs *regs)
1023{
1024 unsigned int instr;
1025 int stepped;
1026
1027 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001028 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 if (mread(regs->nip, &instr, 4) == 4) {
1030 stepped = emulate_step(regs, instr);
1031 if (stepped < 0) {
1032 printf("Couldn't single-step %s instruction\n",
1033 (IS_RFID(instr)? "rfid": "mtmsrd"));
1034 return 0;
1035 }
1036 if (stepped > 0) {
1037 regs->trap = 0xd00 | (regs->trap & 1);
1038 printf("stepped to ");
1039 xmon_print_symbol(regs->nip, " ", "\n");
1040 ppc_inst_dump(regs->nip, 1, 0);
1041 return 0;
1042 }
1043 }
1044 }
1045 regs->msr |= MSR_SE;
1046 return 1;
1047}
Josh Boyercdd39042009-10-05 04:46:05 +00001048#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
1050static void bootcmds(void)
1051{
1052 int cmd;
1053
1054 cmd = inchar();
1055 if (cmd == 'r')
1056 ppc_md.restart(NULL);
1057 else if (cmd == 'h')
1058 ppc_md.halt();
1059 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001060 if (pm_power_off)
1061 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062}
1063
1064static int cpu_cmd(void)
1065{
1066#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001067 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
1070 if (!scanhex(&cpu)) {
1071 /* print cpus waiting or in xmon */
1072 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001073 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001074 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001075 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001076 if (cpu == last_cpu + 1) {
1077 last_cpu = cpu;
1078 } else {
1079 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001080 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001081 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001082 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 }
1085 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001086 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001087 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 printf("\n");
1089 return 0;
1090 }
1091 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001092 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 printf("cpu 0x%x isn't in xmon\n", cpu);
1094 return 0;
1095 }
1096 xmon_taken = 0;
1097 mb();
1098 xmon_owner = cpu;
1099 timeout = 10000000;
1100 while (!xmon_taken) {
1101 if (--timeout == 0) {
1102 if (test_and_set_bit(0, &xmon_taken))
1103 break;
1104 /* take control back */
1105 mb();
1106 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001107 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 return 0;
1109 }
1110 barrier();
1111 }
1112 return 1;
1113#else
1114 return 0;
1115#endif /* CONFIG_SMP */
1116}
1117
1118static unsigned short fcstab[256] = {
1119 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1120 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1121 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1122 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1123 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1124 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1125 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1126 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1127 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1128 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1129 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1130 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1131 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1132 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1133 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1134 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1135 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1136 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1137 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1138 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1139 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1140 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1141 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1142 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1143 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1144 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1145 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1146 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1147 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1148 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1149 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1150 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1151};
1152
1153#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1154
1155static void
1156csum(void)
1157{
1158 unsigned int i;
1159 unsigned short fcs;
1160 unsigned char v;
1161
1162 if (!scanhex(&adrs))
1163 return;
1164 if (!scanhex(&ncsum))
1165 return;
1166 fcs = 0xffff;
1167 for (i = 0; i < ncsum; ++i) {
1168 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001169 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 break;
1171 }
1172 fcs = FCS(fcs, v);
1173 }
1174 printf("%x\n", fcs);
1175}
1176
1177/*
1178 * Check if this is a suitable place to put a breakpoint.
1179 */
1180static long check_bp_loc(unsigned long addr)
1181{
1182 unsigned int instr;
1183
1184 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001185 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 printf("Breakpoints may only be placed at kernel addresses\n");
1187 return 0;
1188 }
1189 if (!mread(addr, &instr, sizeof(instr))) {
1190 printf("Can't read instruction at address %lx\n", addr);
1191 return 0;
1192 }
1193 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1194 printf("Breakpoints may not be placed on mtmsrd or rfid "
1195 "instructions\n");
1196 return 0;
1197 }
1198 return 1;
1199}
1200
Michael Ellermane3bc8042012-08-23 22:09:13 +00001201static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 "Breakpoint command usage:\n"
1203 "b show breakpoints\n"
1204 "b <addr> [cnt] set breakpoint at given instr addr\n"
1205 "bc clear all breakpoints\n"
1206 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301207 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 "bd <addr> [cnt] set hardware data breakpoint\n"
1209 "";
1210
1211static void
1212bpt_cmds(void)
1213{
1214 int cmd;
1215 unsigned long a;
1216 int mode, i;
1217 struct bpt *bp;
1218 const char badaddr[] = "Only kernel addresses are permitted "
1219 "for breakpoints\n";
1220
1221 cmd = inchar();
1222 switch (cmd) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001223#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 case 'd': /* bd - hardware data breakpoint */
1225 mode = 7;
1226 cmd = inchar();
1227 if (cmd == 'r')
1228 mode = 5;
1229 else if (cmd == 'w')
1230 mode = 6;
1231 else
1232 termch = cmd;
1233 dabr.address = 0;
1234 dabr.enabled = 0;
1235 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001236 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 printf(badaddr);
1238 break;
1239 }
Michael Neuling9422de32012-12-20 14:06:44 +00001240 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 dabr.enabled = mode | BP_DABR;
1242 }
1243 break;
1244
1245 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301246 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 printf("Hardware instruction breakpoint "
1248 "not supported on this cpu\n");
1249 break;
1250 }
1251 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001252 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 iabr = NULL;
1254 }
1255 if (!scanhex(&a))
1256 break;
1257 if (!check_bp_loc(a))
1258 break;
1259 bp = new_breakpoint(a);
1260 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001261 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 iabr = bp;
1263 }
1264 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001265#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266
1267 case 'c':
1268 if (!scanhex(&a)) {
1269 /* clear all breakpoints */
1270 for (i = 0; i < NBPTS; ++i)
1271 bpts[i].enabled = 0;
1272 iabr = NULL;
1273 dabr.enabled = 0;
1274 printf("All breakpoints cleared\n");
1275 break;
1276 }
1277
1278 if (a <= NBPTS && a >= 1) {
1279 /* assume a breakpoint number */
1280 bp = &bpts[a-1]; /* bp nums are 1 based */
1281 } else {
1282 /* assume a breakpoint address */
1283 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001284 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001285 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 break;
1287 }
1288 }
1289
Michael Ellerman736256e2014-05-26 21:02:14 +10001290 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 xmon_print_symbol(bp->address, " ", ")\n");
1292 bp->enabled = 0;
1293 break;
1294
1295 default:
1296 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001297 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 if (cmd == '?') {
1299 printf(breakpoint_help_string);
1300 break;
1301 }
1302 termch = cmd;
1303 if (!scanhex(&a)) {
1304 /* print all breakpoints */
1305 printf(" type address\n");
1306 if (dabr.enabled) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001307 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 if (dabr.enabled & 1)
1309 printf("r");
1310 if (dabr.enabled & 2)
1311 printf("w");
1312 printf("]\n");
1313 }
1314 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1315 if (!bp->enabled)
1316 continue;
1317 printf("%2x %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001318 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 xmon_print_symbol(bp->address, " ", "\n");
1320 }
1321 break;
1322 }
1323
1324 if (!check_bp_loc(a))
1325 break;
1326 bp = new_breakpoint(a);
1327 if (bp != NULL)
1328 bp->enabled |= BP_TRAP;
1329 break;
1330 }
1331}
1332
1333/* Very cheap human name for vector lookup. */
1334static
1335const char *getvecname(unsigned long vec)
1336{
1337 char *ret;
1338
1339 switch (vec) {
1340 case 0x100: ret = "(System Reset)"; break;
1341 case 0x200: ret = "(Machine Check)"; break;
1342 case 0x300: ret = "(Data Access)"; break;
1343 case 0x380: ret = "(Data SLB Access)"; break;
1344 case 0x400: ret = "(Instruction Access)"; break;
1345 case 0x480: ret = "(Instruction SLB Access)"; break;
1346 case 0x500: ret = "(Hardware Interrupt)"; break;
1347 case 0x600: ret = "(Alignment)"; break;
1348 case 0x700: ret = "(Program Check)"; break;
1349 case 0x800: ret = "(FPU Unavailable)"; break;
1350 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001351 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1352 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 case 0xc00: ret = "(System Call)"; break;
1354 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001355 case 0xe40: ret = "(Emulation Assist)"; break;
1356 case 0xe60: ret = "(HMI)"; break;
1357 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 case 0xf00: ret = "(Performance Monitor)"; break;
1359 case 0xf20: ret = "(Altivec Unavailable)"; break;
1360 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001361 case 0x1500: ret = "(Denormalisation)"; break;
1362 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 default: ret = "";
1364 }
1365 return ret;
1366}
1367
1368static void get_function_bounds(unsigned long pc, unsigned long *startp,
1369 unsigned long *endp)
1370{
1371 unsigned long size, offset;
1372 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
1374 *startp = *endp = 0;
1375 if (pc == 0)
1376 return;
1377 if (setjmp(bus_error_jmp) == 0) {
1378 catch_memory_errors = 1;
1379 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001380 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 if (name != NULL) {
1382 *startp = pc - offset;
1383 *endp = pc - offset + size;
1384 }
1385 sync();
1386 }
1387 catch_memory_errors = 0;
1388}
1389
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001390#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1391#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1392
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393static void xmon_show_stack(unsigned long sp, unsigned long lr,
1394 unsigned long pc)
1395{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001396 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 unsigned long ip;
1398 unsigned long newsp;
1399 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 struct pt_regs regs;
1401
Michael Ellerman0104cd62012-10-09 04:20:36 +00001402 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 if (sp < PAGE_OFFSET) {
1404 if (sp != 0)
1405 printf("SP (%lx) is in userspace\n", sp);
1406 break;
1407 }
1408
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001409 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 || !mread(sp, &newsp, sizeof(unsigned long))) {
1411 printf("Couldn't read stack frame at %lx\n", sp);
1412 break;
1413 }
1414
1415 /*
1416 * For the first stack frame, try to work out if
1417 * LR and/or the saved LR value in the bottommost
1418 * stack frame are valid.
1419 */
1420 if ((pc | lr) != 0) {
1421 unsigned long fnstart, fnend;
1422 unsigned long nextip;
1423 int printip = 1;
1424
1425 get_function_bounds(pc, &fnstart, &fnend);
1426 nextip = 0;
1427 if (newsp > sp)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001428 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 sizeof(unsigned long));
1430 if (lr == ip) {
1431 if (lr < PAGE_OFFSET
1432 || (fnstart <= lr && lr < fnend))
1433 printip = 0;
1434 } else if (lr == nextip) {
1435 printip = 0;
1436 } else if (lr >= PAGE_OFFSET
1437 && !(fnstart <= lr && lr < fnend)) {
1438 printf("[link register ] ");
1439 xmon_print_symbol(lr, " ", "\n");
1440 }
1441 if (printip) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001442 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 xmon_print_symbol(ip, " ", " (unreliable)\n");
1444 }
1445 pc = lr = 0;
1446
1447 } else {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001448 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 xmon_print_symbol(ip, " ", "\n");
1450 }
1451
1452 /* Look for "regshere" marker to see if this is
1453 an exception frame. */
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001454 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001455 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001456 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 != sizeof(regs)) {
1458 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001459 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 break;
1461 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001462 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 getvecname(TRAP(&regs)));
1464 pc = regs.nip;
1465 lr = regs.link;
1466 xmon_print_symbol(pc, " ", "\n");
1467 }
1468
1469 if (newsp == 0)
1470 break;
1471
1472 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474}
1475
1476static void backtrace(struct pt_regs *excp)
1477{
1478 unsigned long sp;
1479
1480 if (scanhex(&sp))
1481 xmon_show_stack(sp, 0, 0);
1482 else
1483 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1484 scannl();
1485}
1486
1487static void print_bug_trap(struct pt_regs *regs)
1488{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001489#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001490 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 unsigned long addr;
1492
1493 if (regs->msr & MSR_PR)
1494 return; /* not in kernel */
1495 addr = regs->nip; /* address of trap instruction */
1496 if (addr < PAGE_OFFSET)
1497 return;
1498 bug = find_bug(regs->nip);
1499 if (bug == NULL)
1500 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001501 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 return;
1503
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001504#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001505 printf("kernel BUG at %s:%u!\n",
1506 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001507#else
1508 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1509#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001510#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511}
1512
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001513static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514{
1515 unsigned long trap;
1516
1517#ifdef CONFIG_SMP
1518 printf("cpu 0x%x: ", smp_processor_id());
1519#endif /* CONFIG_SMP */
1520
1521 trap = TRAP(fp);
1522 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1523 printf(" pc: ");
1524 xmon_print_symbol(fp->nip, ": ", "\n");
1525
1526 printf(" lr: ", fp->link);
1527 xmon_print_symbol(fp->link, ": ", "\n");
1528
1529 printf(" sp: %lx\n", fp->gpr[1]);
1530 printf(" msr: %lx\n", fp->msr);
1531
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001532 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 printf(" dar: %lx\n", fp->dar);
1534 if (trap != 0x380)
1535 printf(" dsisr: %lx\n", fp->dsisr);
1536 }
1537
1538 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001539#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001540 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1541 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001542#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 if (current) {
1544 printf(" pid = %ld, comm = %s\n",
1545 current->pid, current->comm);
1546 }
1547
1548 if (trap == 0x700)
1549 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001550
1551 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552}
1553
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001554static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001556 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 unsigned long base;
1558 struct pt_regs regs;
1559
1560 if (scanhex(&base)) {
1561 if (setjmp(bus_error_jmp) == 0) {
1562 catch_memory_errors = 1;
1563 sync();
1564 regs = *(struct pt_regs *)base;
1565 sync();
1566 __delay(200);
1567 } else {
1568 catch_memory_errors = 0;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001569 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 base);
1571 return;
1572 }
1573 catch_memory_errors = 0;
1574 fp = &regs;
1575 }
1576
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001577#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 if (FULL_REGS(fp)) {
1579 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001580 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1582 } else {
1583 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001584 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1586 }
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001587#else
1588 for (n = 0; n < 32; ++n) {
1589 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1590 (n & 3) == 3? "\n": " ");
1591 if (n == 12 && !FULL_REGS(fp)) {
1592 printf("\n");
1593 break;
1594 }
1595 }
1596#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 printf("pc = ");
1598 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001599 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1600 printf("cfar= ");
1601 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 printf("lr = ");
1604 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001605 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1606 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001608 trap = TRAP(fp);
1609 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1610 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611}
1612
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001613static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614{
1615 int cmd;
1616 unsigned long nflush;
1617
1618 cmd = inchar();
1619 if (cmd != 'i')
1620 termch = cmd;
1621 scanhex((void *)&adrs);
1622 if (termch != '\n')
1623 termch = 0;
1624 nflush = 1;
1625 scanhex(&nflush);
1626 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1627 if (setjmp(bus_error_jmp) == 0) {
1628 catch_memory_errors = 1;
1629 sync();
1630
1631 if (cmd != 'i') {
1632 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1633 cflush((void *) adrs);
1634 } else {
1635 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1636 cinval((void *) adrs);
1637 }
1638 sync();
1639 /* wait a little while to see if we get a machine check */
1640 __delay(200);
1641 }
1642 catch_memory_errors = 0;
1643}
1644
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001645extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1646extern void xmon_mtspr(int spr, unsigned long value);
1647
1648static int
1649read_spr(int n, unsigned long *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 unsigned long ret = -1UL;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001652 int ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
1654 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001655 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 sync();
1657
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001658 ret = xmon_mfspr(n, *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
1660 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001661 *vp = ret;
1662 ok = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001664 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001666 return ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667}
1668
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001669static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670write_spr(int n, unsigned long val)
1671{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001673 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 sync();
1675
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001676 xmon_mtspr(n, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
1678 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001679 } else {
1680 printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001682 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683}
1684
Michael Ellerman18461932016-07-07 22:54:29 +10001685static void dump_206_sprs(void)
1686{
1687#ifdef CONFIG_PPC64
1688 if (!cpu_has_feature(CPU_FTR_ARCH_206))
1689 return;
1690
1691 /* Actually some of these pre-date 2.06, but whatevs */
1692
1693 printf("srr0 = %.16x srr1 = %.16x dsisr = %.8x\n",
1694 mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
1695 printf("dscr = %.16x ppr = %.16x pir = %.8x\n",
1696 mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
1697
1698 if (!(mfmsr() & MSR_HV))
1699 return;
1700
1701 printf("sdr1 = %.16x hdar = %.16x hdsisr = %.8x\n",
1702 mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
1703 printf("hsrr0 = %.16x hsrr1 = %.16x hdec = %.8x\n",
1704 mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
1705 printf("lpcr = %.16x pcr = %.16x lpidr = %.8x\n",
1706 mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
1707 printf("hsprg0 = %.16x hsprg1 = %.16x\n",
1708 mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1));
1709 printf("dabr = %.16x dabrx = %.16x\n",
1710 mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
1711#endif
1712}
1713
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001714static void dump_207_sprs(void)
1715{
1716#ifdef CONFIG_PPC64
1717 unsigned long msr;
1718
1719 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
1720 return;
1721
1722 printf("dpdes = %.16x tir = %.16x cir = %.8x\n",
1723 mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
1724
1725 printf("fscr = %.16x tar = %.16x pspb = %.8x\n",
1726 mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
1727
1728 msr = mfmsr();
1729 if (msr & MSR_TM) {
1730 /* Only if TM has been enabled in the kernel */
1731 printf("tfhar = %.16x tfiar = %.16x texasr = %.16x\n",
1732 mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
1733 mfspr(SPRN_TEXASR));
1734 }
1735
1736 printf("mmcr0 = %.16x mmcr1 = %.16x mmcr2 = %.16x\n",
1737 mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
1738 printf("pmc1 = %.8x pmc2 = %.8x pmc3 = %.8x pmc4 = %.8x\n",
1739 mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
1740 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
1741 printf("mmcra = %.16x siar = %.16x pmc5 = %.8x\n",
1742 mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
1743 printf("sdar = %.16x sier = %.16x pmc6 = %.8x\n",
1744 mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
1745 printf("ebbhr = %.16x ebbrr = %.16x bescr = %.16x\n",
1746 mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
1747
1748 if (!(msr & MSR_HV))
1749 return;
1750
1751 printf("hfscr = %.16x dhdes = %.16x rpr = %.16x\n",
1752 mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
1753 printf("dawr = %.16x dawrx = %.16x ciabr = %.16x\n",
1754 mfspr(SPRN_DAWR), mfspr(SPRN_DAWRX), mfspr(SPRN_CIABR));
1755#endif
1756}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001758static void dump_one_spr(int spr, bool show_unimplemented)
1759{
1760 unsigned long val;
1761
1762 val = 0xdeadbeef;
1763 if (!read_spr(spr, &val)) {
1764 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1765 return;
1766 }
1767
1768 if (val == 0xdeadbeef) {
1769 /* Looks like read was a nop, confirm */
1770 val = 0x0badcafe;
1771 if (!read_spr(spr, &val)) {
1772 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1773 return;
1774 }
1775
1776 if (val == 0x0badcafe) {
1777 if (show_unimplemented)
1778 printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
1779 return;
1780 }
1781 }
1782
1783 printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
1784}
1785
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001786static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787{
Michael Ellerman13629da2016-07-07 22:54:27 +10001788 static unsigned long regno;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 int cmd;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001790 int spr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791
1792 cmd = skipbl();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001793
1794 switch (cmd) {
1795 case '\n': {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001796 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 asm("mr %0,1" : "=r" (sp) :);
1798 asm("mr %0,2" : "=r" (toc) :);
1799
Michael Ellerman56346ad2016-07-07 22:54:28 +10001800 printf("msr = "REG" sprg0 = "REG"\n",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001801 mfmsr(), mfspr(SPRN_SPRG0));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001802 printf("pvr = "REG" sprg1 = "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001803 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001804 printf("dec = "REG" sprg2 = "REG"\n",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001805 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001806 printf("sp = "REG" sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
1807 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
1808
Michael Ellerman18461932016-07-07 22:54:29 +10001809 dump_206_sprs();
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001810 dump_207_sprs();
Michael Ellerman18461932016-07-07 22:54:29 +10001811
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 return;
1813 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001814 case 'w': {
1815 unsigned long val;
1816 scanhex(&regno);
1817 val = 0;
1818 read_spr(regno, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 scanhex(&val);
1820 write_spr(regno, val);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001821 dump_one_spr(regno, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001824 case 'r':
1825 scanhex(&regno);
1826 dump_one_spr(regno, true);
1827 break;
1828 case 'a':
1829 /* dump ALL SPRs */
1830 for (spr = 1; spr < 1024; ++spr)
1831 dump_one_spr(spr, false);
1832 break;
1833 }
1834
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 scannl();
1836}
1837
1838/*
1839 * Stuff for reading and writing memory safely
1840 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001841static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842mread(unsigned long adrs, void *buf, int size)
1843{
1844 volatile int n;
1845 char *p, *q;
1846
1847 n = 0;
1848 if (setjmp(bus_error_jmp) == 0) {
1849 catch_memory_errors = 1;
1850 sync();
1851 p = (char *)adrs;
1852 q = (char *)buf;
1853 switch (size) {
1854 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001855 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 break;
1857 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001858 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 break;
1860 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001861 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 break;
1863 default:
1864 for( ; n < size; ++n) {
1865 *q++ = *p++;
1866 sync();
1867 }
1868 }
1869 sync();
1870 /* wait a little while to see if we get a machine check */
1871 __delay(200);
1872 n = size;
1873 }
1874 catch_memory_errors = 0;
1875 return n;
1876}
1877
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001878static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879mwrite(unsigned long adrs, void *buf, int size)
1880{
1881 volatile int n;
1882 char *p, *q;
1883
1884 n = 0;
1885 if (setjmp(bus_error_jmp) == 0) {
1886 catch_memory_errors = 1;
1887 sync();
1888 p = (char *) adrs;
1889 q = (char *) buf;
1890 switch (size) {
1891 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001892 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 break;
1894 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001895 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 break;
1897 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001898 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 break;
1900 default:
1901 for ( ; n < size; ++n) {
1902 *p++ = *q++;
1903 sync();
1904 }
1905 }
1906 sync();
1907 /* wait a little while to see if we get a machine check */
1908 __delay(200);
1909 n = size;
1910 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10001911 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 }
1913 catch_memory_errors = 0;
1914 return n;
1915}
1916
1917static int fault_type;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001918static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919static char *fault_chars[] = { "--", "**", "##" };
1920
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001921static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001923 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 switch (TRAP(regs)) {
1925 case 0x200:
1926 fault_type = 0;
1927 break;
1928 case 0x300:
1929 case 0x380:
1930 fault_type = 1;
1931 break;
1932 default:
1933 fault_type = 2;
1934 }
1935
1936 longjmp(bus_error_jmp, 1);
1937
1938 return 0;
1939}
1940
1941#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1942
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001943static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944byterev(unsigned char *val, int size)
1945{
1946 int t;
1947
1948 switch (size) {
1949 case 2:
1950 SWAP(val[0], val[1], t);
1951 break;
1952 case 4:
1953 SWAP(val[0], val[3], t);
1954 SWAP(val[1], val[2], t);
1955 break;
1956 case 8: /* is there really any use for this? */
1957 SWAP(val[0], val[7], t);
1958 SWAP(val[1], val[6], t);
1959 SWAP(val[2], val[5], t);
1960 SWAP(val[3], val[4], t);
1961 break;
1962 }
1963}
1964
1965static int brev;
1966static int mnoread;
1967
Michael Ellermane3bc8042012-08-23 22:09:13 +00001968static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 "Memory examine command usage:\n"
1970 "m [addr] [flags] examine/change memory\n"
1971 " addr is optional. will start where left off.\n"
1972 " flags may include chars from this set:\n"
1973 " b modify by bytes (default)\n"
1974 " w modify by words (2 byte)\n"
1975 " l modify by longs (4 byte)\n"
1976 " d modify by doubleword (8 byte)\n"
1977 " r toggle reverse byte order mode\n"
1978 " n do not read memory (for i/o spaces)\n"
1979 " . ok to read (default)\n"
1980 "NOTE: flags are saved as defaults\n"
1981 "";
1982
Michael Ellermane3bc8042012-08-23 22:09:13 +00001983static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 "Memory examine subcommands:\n"
1985 " hexval write this val to current location\n"
1986 " 'string' write chars from string to this location\n"
1987 " ' increment address\n"
1988 " ^ decrement address\n"
1989 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1990 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1991 " ` clear no-read flag\n"
1992 " ; stay at this addr\n"
1993 " v change to byte mode\n"
1994 " w change to word (2 byte) mode\n"
1995 " l change to long (4 byte) mode\n"
1996 " u change to doubleword (8 byte) mode\n"
1997 " m addr change current addr\n"
1998 " n toggle no-read flag\n"
1999 " r toggle byte reverse flag\n"
2000 " < count back up count bytes\n"
2001 " > count skip forward count bytes\n"
2002 " x exit this mode\n"
2003 "";
2004
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002005static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006memex(void)
2007{
2008 int cmd, inc, i, nslash;
2009 unsigned long n;
2010 unsigned char val[16];
2011
2012 scanhex((void *)&adrs);
2013 cmd = skipbl();
2014 if (cmd == '?') {
2015 printf(memex_help_string);
2016 return;
2017 } else {
2018 termch = cmd;
2019 }
2020 last_cmd = "m\n";
2021 while ((cmd = skipbl()) != '\n') {
2022 switch( cmd ){
2023 case 'b': size = 1; break;
2024 case 'w': size = 2; break;
2025 case 'l': size = 4; break;
2026 case 'd': size = 8; break;
2027 case 'r': brev = !brev; break;
2028 case 'n': mnoread = 1; break;
2029 case '.': mnoread = 0; break;
2030 }
2031 }
2032 if( size <= 0 )
2033 size = 1;
2034 else if( size > 8 )
2035 size = 8;
2036 for(;;){
2037 if (!mnoread)
2038 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002039 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 if (!mnoread) {
2041 if (brev)
2042 byterev(val, size);
2043 putchar(' ');
2044 for (i = 0; i < n; ++i)
2045 printf("%.2x", val[i]);
2046 for (; i < size; ++i)
2047 printf("%s", fault_chars[fault_type]);
2048 }
2049 putchar(' ');
2050 inc = size;
2051 nslash = 0;
2052 for(;;){
2053 if( scanhex(&n) ){
2054 for (i = 0; i < size; ++i)
2055 val[i] = n >> (i * 8);
2056 if (!brev)
2057 byterev(val, size);
2058 mwrite(adrs, val, size);
2059 inc = size;
2060 }
2061 cmd = skipbl();
2062 if (cmd == '\n')
2063 break;
2064 inc = 0;
2065 switch (cmd) {
2066 case '\'':
2067 for(;;){
2068 n = inchar();
2069 if( n == '\\' )
2070 n = bsesc();
2071 else if( n == '\'' )
2072 break;
2073 for (i = 0; i < size; ++i)
2074 val[i] = n >> (i * 8);
2075 if (!brev)
2076 byterev(val, size);
2077 mwrite(adrs, val, size);
2078 adrs += size;
2079 }
2080 adrs -= size;
2081 inc = size;
2082 break;
2083 case ',':
2084 adrs += size;
2085 break;
2086 case '.':
2087 mnoread = 0;
2088 break;
2089 case ';':
2090 break;
2091 case 'x':
2092 case EOF:
2093 scannl();
2094 return;
2095 case 'b':
2096 case 'v':
2097 size = 1;
2098 break;
2099 case 'w':
2100 size = 2;
2101 break;
2102 case 'l':
2103 size = 4;
2104 break;
2105 case 'u':
2106 size = 8;
2107 break;
2108 case '^':
2109 adrs -= size;
2110 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 case '/':
2112 if (nslash > 0)
2113 adrs -= 1 << nslash;
2114 else
2115 nslash = 0;
2116 nslash += 4;
2117 adrs += 1 << nslash;
2118 break;
2119 case '\\':
2120 if (nslash < 0)
2121 adrs += 1 << -nslash;
2122 else
2123 nslash = 0;
2124 nslash -= 4;
2125 adrs -= 1 << -nslash;
2126 break;
2127 case 'm':
2128 scanhex((void *)&adrs);
2129 break;
2130 case 'n':
2131 mnoread = 1;
2132 break;
2133 case 'r':
2134 brev = !brev;
2135 break;
2136 case '<':
2137 n = size;
2138 scanhex(&n);
2139 adrs -= n;
2140 break;
2141 case '>':
2142 n = size;
2143 scanhex(&n);
2144 adrs += n;
2145 break;
2146 case '?':
2147 printf(memex_subcmd_help_string);
2148 break;
2149 }
2150 }
2151 adrs += inc;
2152 }
2153}
2154
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002155static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156bsesc(void)
2157{
2158 int c;
2159
2160 c = inchar();
2161 switch( c ){
2162 case 'n': c = '\n'; break;
2163 case 'r': c = '\r'; break;
2164 case 'b': c = '\b'; break;
2165 case 't': c = '\t'; break;
2166 }
2167 return c;
2168}
2169
Olaf Hering7e5b5932006-03-08 20:40:28 +01002170static void xmon_rawdump (unsigned long adrs, long ndump)
2171{
2172 long n, m, r, nr;
2173 unsigned char temp[16];
2174
2175 for (n = ndump; n > 0;) {
2176 r = n < 16? n: 16;
2177 nr = mread(adrs, temp, r);
2178 adrs += nr;
2179 for (m = 0; m < r; ++m) {
2180 if (m < nr)
2181 printf("%.2x", temp[m]);
2182 else
2183 printf("%s", fault_chars[fault_type]);
2184 }
2185 n -= r;
2186 if (nr < r)
2187 break;
2188 }
2189 printf("\n");
2190}
2191
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002192#ifdef CONFIG_PPC64
2193static void dump_one_paca(int cpu)
2194{
2195 struct paca_struct *p;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002196#ifdef CONFIG_PPC_STD_MMU_64
2197 int i = 0;
2198#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002199
2200 if (setjmp(bus_error_jmp) != 0) {
2201 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2202 return;
2203 }
2204
2205 catch_memory_errors = 1;
2206 sync();
2207
2208 p = &paca[cpu];
2209
2210 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2211
Michael Ellermanad987fc2015-10-14 16:58:36 +11002212 printf(" %-*s = %s\n", 20, "possible", cpu_possible(cpu) ? "yes" : "no");
2213 printf(" %-*s = %s\n", 20, "present", cpu_present(cpu) ? "yes" : "no");
2214 printf(" %-*s = %s\n", 20, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002215
2216#define DUMP(paca, name, format) \
Michael Ellermanad987fc2015-10-14 16:58:36 +11002217 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 20, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002218 offsetof(struct paca_struct, name));
2219
2220 DUMP(p, lock_token, "x");
2221 DUMP(p, paca_index, "x");
2222 DUMP(p, kernel_toc, "lx");
2223 DUMP(p, kernelbase, "lx");
2224 DUMP(p, kernel_msr, "lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002225 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302226#ifdef CONFIG_PPC_BOOK3S_64
2227 DUMP(p, mc_emergency_sp, "p");
2228 DUMP(p, in_mce, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002229 DUMP(p, hmi_event_available, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302230#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002231 DUMP(p, data_offset, "lx");
2232 DUMP(p, hw_cpu_id, "x");
2233 DUMP(p, cpu_start, "x");
2234 DUMP(p, kexec_state, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002235#ifdef CONFIG_PPC_STD_MMU_64
2236 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2237 u64 esid, vsid;
2238
2239 if (!p->slb_shadow_ptr)
2240 continue;
2241
2242 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2243 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
2244
2245 if (esid || vsid) {
2246 printf(" slb_shadow[%d]: = 0x%016lx 0x%016lx\n",
2247 i, esid, vsid);
2248 }
2249 }
2250 DUMP(p, vmalloc_sllp, "x");
2251 DUMP(p, slb_cache_ptr, "x");
2252 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2253 printf(" slb_cache[%d]: = 0x%016lx\n", i, p->slb_cache[i]);
2254#endif
2255 DUMP(p, dscr_default, "llx");
2256#ifdef CONFIG_PPC_BOOK3E
2257 DUMP(p, pgd, "p");
2258 DUMP(p, kernel_pgd, "p");
2259 DUMP(p, tcd_ptr, "p");
2260 DUMP(p, mc_kstack, "p");
2261 DUMP(p, crit_kstack, "p");
2262 DUMP(p, dbg_kstack, "p");
2263#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002264 DUMP(p, __current, "p");
2265 DUMP(p, kstack, "lx");
2266 DUMP(p, stab_rr, "lx");
2267 DUMP(p, saved_r1, "lx");
2268 DUMP(p, trap_save, "x");
2269 DUMP(p, soft_enabled, "x");
2270 DUMP(p, irq_happened, "x");
2271 DUMP(p, io_sync, "x");
2272 DUMP(p, irq_work_pending, "x");
2273 DUMP(p, nap_state_lost, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002274 DUMP(p, sprg_vdso, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002275
Michael Ellermanad987fc2015-10-14 16:58:36 +11002276#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
2277 DUMP(p, tm_scratch, "llx");
2278#endif
2279
2280#ifdef CONFIG_PPC_POWERNV
2281 DUMP(p, core_idle_state_ptr, "p");
2282 DUMP(p, thread_idle_state, "x");
2283 DUMP(p, thread_mask, "x");
2284 DUMP(p, subcore_sibling_mask, "x");
2285#endif
2286
Christophe Leroyc223c902016-05-17 08:33:46 +02002287 DUMP(p, accounting.user_time, "llx");
2288 DUMP(p, accounting.system_time, "llx");
2289 DUMP(p, accounting.user_time_scaled, "llx");
2290 DUMP(p, accounting.starttime, "llx");
2291 DUMP(p, accounting.starttime_user, "llx");
2292 DUMP(p, accounting.startspurr, "llx");
2293 DUMP(p, accounting.utime_sspurr, "llx");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002294 DUMP(p, stolen_time, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002295#undef DUMP
2296
2297 catch_memory_errors = 0;
2298 sync();
2299}
2300
2301static void dump_all_pacas(void)
2302{
2303 int cpu;
2304
2305 if (num_possible_cpus() == 0) {
2306 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2307 return;
2308 }
2309
2310 for_each_possible_cpu(cpu)
2311 dump_one_paca(cpu);
2312}
2313
2314static void dump_pacas(void)
2315{
2316 unsigned long num;
2317 int c;
2318
2319 c = inchar();
2320 if (c == 'a') {
2321 dump_all_pacas();
2322 return;
2323 }
2324
2325 termch = c; /* Put c back, it wasn't 'a' */
2326
2327 if (scanhex(&num))
2328 dump_one_paca(num);
2329 else
2330 dump_one_paca(xmon_owner);
2331}
2332#endif
2333
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002334static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335dump(void)
2336{
2337 int c;
2338
2339 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002340
2341#ifdef CONFIG_PPC64
2342 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002343 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002344 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002345 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002346 return;
2347 }
2348#endif
2349
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2351 termch = c;
2352 scanhex((void *)&adrs);
2353 if (termch != '\n')
2354 termch = 0;
2355 if (c == 'i') {
2356 scanhex(&nidump);
2357 if (nidump == 0)
2358 nidump = 16;
2359 else if (nidump > MAX_DUMP)
2360 nidump = MAX_DUMP;
2361 adrs += ppc_inst_dump(adrs, nidump, 1);
2362 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002363 } else if (c == 'l') {
2364 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002365 } else if (c == 'o') {
2366 dump_opal_msglog();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002367 } else if (c == 'r') {
2368 scanhex(&ndump);
2369 if (ndump == 0)
2370 ndump = 64;
2371 xmon_rawdump(adrs, ndump);
2372 adrs += ndump;
2373 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 } else {
2375 scanhex(&ndump);
2376 if (ndump == 0)
2377 ndump = 64;
2378 else if (ndump > MAX_DUMP)
2379 ndump = MAX_DUMP;
2380 prdump(adrs, ndump);
2381 adrs += ndump;
2382 last_cmd = "d\n";
2383 }
2384}
2385
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002386static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387prdump(unsigned long adrs, long ndump)
2388{
2389 long n, m, c, r, nr;
2390 unsigned char temp[16];
2391
2392 for (n = ndump; n > 0;) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002393 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 putchar(' ');
2395 r = n < 16? n: 16;
2396 nr = mread(adrs, temp, r);
2397 adrs += nr;
2398 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002399 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002400 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 if (m < nr)
2402 printf("%.2x", temp[m]);
2403 else
2404 printf("%s", fault_chars[fault_type]);
2405 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002406 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002407 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002408 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 printf(" |");
2412 for (m = 0; m < r; ++m) {
2413 if (m < nr) {
2414 c = temp[m];
2415 putchar(' ' <= c && c <= '~'? c: '.');
2416 } else
2417 putchar(' ');
2418 }
2419 n -= r;
2420 for (; m < 16; ++m)
2421 putchar(' ');
2422 printf("|\n");
2423 if (nr < r)
2424 break;
2425 }
2426}
2427
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002428typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2429
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002430static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002431generic_inst_dump(unsigned long adr, long count, int praddr,
2432 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433{
2434 int nr, dotted;
2435 unsigned long first_adr;
2436 unsigned long inst, last_inst = 0;
2437 unsigned char val[4];
2438
2439 dotted = 0;
2440 for (first_adr = adr; count > 0; --count, adr += 4) {
2441 nr = mread(adr, val, 4);
2442 if (nr == 0) {
2443 if (praddr) {
2444 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002445 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 }
2447 break;
2448 }
2449 inst = GETWORD(val);
2450 if (adr > first_adr && inst == last_inst) {
2451 if (!dotted) {
2452 printf(" ...\n");
2453 dotted = 1;
2454 }
2455 continue;
2456 }
2457 dotted = 0;
2458 last_inst = inst;
2459 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002460 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002462 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 printf("\n");
2464 }
2465 return adr - first_adr;
2466}
2467
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002468static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002469ppc_inst_dump(unsigned long adr, long count, int praddr)
2470{
2471 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2472}
2473
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474void
2475print_address(unsigned long addr)
2476{
2477 xmon_print_symbol(addr, "\t# ", "");
2478}
2479
Vinay Sridharf312deb2009-05-14 23:13:07 +00002480void
2481dump_log_buf(void)
2482{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002483 struct kmsg_dumper dumper = { .active = 1 };
2484 unsigned char buf[128];
2485 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002486
Michael Ellermane3bc8042012-08-23 22:09:13 +00002487 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002488 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002489 return;
2490 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002491
Michael Ellermane3bc8042012-08-23 22:09:13 +00002492 catch_memory_errors = 1;
2493 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002494
Michael Ellermanca5dd392012-08-23 22:09:12 +00002495 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002496 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002497 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2498 buf[len] = '\0';
2499 printf("%s", buf);
2500 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002501 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002502
Michael Ellermane3bc8042012-08-23 22:09:13 +00002503 sync();
2504 /* wait a little while to see if we get a machine check */
2505 __delay(200);
2506 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002507}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002509#ifdef CONFIG_PPC_POWERNV
2510static void dump_opal_msglog(void)
2511{
2512 unsigned char buf[128];
2513 ssize_t res;
2514 loff_t pos = 0;
2515
2516 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2517 printf("Machine is not running OPAL firmware.\n");
2518 return;
2519 }
2520
2521 if (setjmp(bus_error_jmp) != 0) {
2522 printf("Error dumping OPAL msglog!\n");
2523 return;
2524 }
2525
2526 catch_memory_errors = 1;
2527 sync();
2528
2529 xmon_start_pagination();
2530 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2531 if (res < 0) {
2532 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2533 break;
2534 }
2535 buf[res] = '\0';
2536 printf("%s", buf);
2537 pos += res;
2538 }
2539 xmon_end_pagination();
2540
2541 sync();
2542 /* wait a little while to see if we get a machine check */
2543 __delay(200);
2544 catch_memory_errors = 0;
2545}
2546#endif
2547
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548/*
2549 * Memory operations - move, set, print differences
2550 */
2551static unsigned long mdest; /* destination address */
2552static unsigned long msrc; /* source address */
2553static unsigned long mval; /* byte value to set memory to */
2554static unsigned long mcount; /* # bytes to affect */
2555static unsigned long mdiffs; /* max # differences to print */
2556
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002557static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558memops(int cmd)
2559{
2560 scanhex((void *)&mdest);
2561 if( termch != '\n' )
2562 termch = 0;
2563 scanhex((void *)(cmd == 's'? &mval: &msrc));
2564 if( termch != '\n' )
2565 termch = 0;
2566 scanhex((void *)&mcount);
2567 switch( cmd ){
2568 case 'm':
2569 memmove((void *)mdest, (void *)msrc, mcount);
2570 break;
2571 case 's':
2572 memset((void *)mdest, mval, mcount);
2573 break;
2574 case 'd':
2575 if( termch != '\n' )
2576 termch = 0;
2577 scanhex((void *)&mdiffs);
2578 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2579 break;
2580 }
2581}
2582
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002583static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2585{
2586 unsigned n, prt;
2587
2588 prt = 0;
2589 for( n = nb; n > 0; --n )
2590 if( *p1++ != *p2++ )
2591 if( ++prt <= maxpr )
2592 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2593 p1[-1], p2 - 1, p2[-1]);
2594 if( prt > maxpr )
2595 printf("Total of %d differences\n", prt);
2596}
2597
2598static unsigned mend;
2599static unsigned mask;
2600
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002601static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602memlocate(void)
2603{
2604 unsigned a, n;
2605 unsigned char val[4];
2606
2607 last_cmd = "ml";
2608 scanhex((void *)&mdest);
2609 if (termch != '\n') {
2610 termch = 0;
2611 scanhex((void *)&mend);
2612 if (termch != '\n') {
2613 termch = 0;
2614 scanhex((void *)&mval);
2615 mask = ~0;
2616 if (termch != '\n') termch = 0;
2617 scanhex((void *)&mask);
2618 }
2619 }
2620 n = 0;
2621 for (a = mdest; a < mend; a += 4) {
2622 if (mread(a, val, 4) == 4
2623 && ((GETWORD(val) ^ mval) & mask) == 0) {
2624 printf("%.16x: %.16x\n", a, GETWORD(val));
2625 if (++n >= 10)
2626 break;
2627 }
2628 }
2629}
2630
2631static unsigned long mskip = 0x1000;
2632static unsigned long mlim = 0xffffffff;
2633
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002634static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635memzcan(void)
2636{
2637 unsigned char v;
2638 unsigned a;
2639 int ok, ook;
2640
2641 scanhex(&mdest);
2642 if (termch != '\n') termch = 0;
2643 scanhex(&mskip);
2644 if (termch != '\n') termch = 0;
2645 scanhex(&mlim);
2646 ook = 0;
2647 for (a = mdest; a < mlim; a += mskip) {
2648 ok = mread(a, &v, 1);
2649 if (ok && !ook) {
2650 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 } else if (!ok && ook)
2652 printf("%.8x\n", a - mskip);
2653 ook = ok;
2654 if (a + mskip < a)
2655 break;
2656 }
2657 if (ook)
2658 printf("%.8x\n", a - mskip);
2659}
2660
Douglas Miller6dfb5402015-11-23 09:01:15 -06002661static void show_task(struct task_struct *tsk)
2662{
2663 char state;
2664
2665 /*
2666 * Cloned from kdb_task_state_char(), which is not entirely
2667 * appropriate for calling from xmon. This could be moved
2668 * to a common, generic, routine used by both.
2669 */
2670 state = (tsk->state == 0) ? 'R' :
2671 (tsk->state < 0) ? 'U' :
2672 (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
2673 (tsk->state & TASK_STOPPED) ? 'T' :
2674 (tsk->state & TASK_TRACED) ? 'C' :
2675 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
2676 (tsk->exit_state & EXIT_DEAD) ? 'E' :
2677 (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
2678
2679 printf("%p %016lx %6d %6d %c %2d %s\n", tsk,
2680 tsk->thread.ksp,
2681 tsk->pid, tsk->parent->pid,
2682 state, task_thread_info(tsk)->cpu,
2683 tsk->comm);
2684}
2685
2686static void show_tasks(void)
2687{
2688 unsigned long tskv;
2689 struct task_struct *tsk = NULL;
2690
2691 printf(" task_struct ->thread.ksp PID PPID S P CMD\n");
2692
2693 if (scanhex(&tskv))
2694 tsk = (struct task_struct *)tskv;
2695
2696 if (setjmp(bus_error_jmp) != 0) {
2697 catch_memory_errors = 0;
2698 printf("*** Error dumping task %p\n", tsk);
2699 return;
2700 }
2701
2702 catch_memory_errors = 1;
2703 sync();
2704
2705 if (tsk)
2706 show_task(tsk);
2707 else
2708 for_each_process(tsk)
2709 show_task(tsk);
2710
2711 sync();
2712 __delay(200);
2713 catch_memory_errors = 0;
2714}
2715
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002716static void proccall(void)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002717{
2718 unsigned long args[8];
2719 unsigned long ret;
2720 int i;
2721 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2722 unsigned long, unsigned long, unsigned long,
2723 unsigned long, unsigned long, unsigned long);
2724 callfunc_t func;
2725
2726 if (!scanhex(&adrs))
2727 return;
2728 if (termch != '\n')
2729 termch = 0;
2730 for (i = 0; i < 8; ++i)
2731 args[i] = 0;
2732 for (i = 0; i < 8; ++i) {
2733 if (!scanhex(&args[i]) || termch == '\n')
2734 break;
2735 termch = 0;
2736 }
2737 func = (callfunc_t) adrs;
2738 ret = 0;
2739 if (setjmp(bus_error_jmp) == 0) {
2740 catch_memory_errors = 1;
2741 sync();
2742 ret = func(args[0], args[1], args[2], args[3],
2743 args[4], args[5], args[6], args[7]);
2744 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10002745 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002746 } else {
2747 printf("*** %x exception occurred\n", fault_except);
2748 }
2749 catch_memory_errors = 0;
2750}
2751
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752/* Input scanning routines */
2753int
2754skipbl(void)
2755{
2756 int c;
2757
2758 if( termch != 0 ){
2759 c = termch;
2760 termch = 0;
2761 } else
2762 c = inchar();
2763 while( c == ' ' || c == '\t' )
2764 c = inchar();
2765 return c;
2766}
2767
2768#define N_PTREGS 44
2769static char *regnames[N_PTREGS] = {
2770 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2771 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2772 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2773 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002774 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2775#ifdef CONFIG_PPC64
2776 "softe",
2777#else
2778 "mq",
2779#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 "trap", "dar", "dsisr", "res"
2781};
2782
2783int
2784scanhex(unsigned long *vp)
2785{
2786 int c, d;
2787 unsigned long v;
2788
2789 c = skipbl();
2790 if (c == '%') {
2791 /* parse register name */
2792 char regname[8];
2793 int i;
2794
2795 for (i = 0; i < sizeof(regname) - 1; ++i) {
2796 c = inchar();
2797 if (!isalnum(c)) {
2798 termch = c;
2799 break;
2800 }
2801 regname[i] = c;
2802 }
2803 regname[i] = 0;
2804 for (i = 0; i < N_PTREGS; ++i) {
2805 if (strcmp(regnames[i], regname) == 0) {
2806 if (xmon_regs == NULL) {
2807 printf("regs not available\n");
2808 return 0;
2809 }
2810 *vp = ((unsigned long *)xmon_regs)[i];
2811 return 1;
2812 }
2813 }
2814 printf("invalid register name '%%%s'\n", regname);
2815 return 0;
2816 }
2817
2818 /* skip leading "0x" if any */
2819
2820 if (c == '0') {
2821 c = inchar();
2822 if (c == 'x') {
2823 c = inchar();
2824 } else {
2825 d = hexdigit(c);
2826 if (d == EOF) {
2827 termch = c;
2828 *vp = 0;
2829 return 1;
2830 }
2831 }
2832 } else if (c == '$') {
2833 int i;
2834 for (i=0; i<63; i++) {
2835 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02002836 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 termch = c;
2838 break;
2839 }
2840 tmpstr[i] = c;
2841 }
2842 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002843 *vp = 0;
2844 if (setjmp(bus_error_jmp) == 0) {
2845 catch_memory_errors = 1;
2846 sync();
2847 *vp = kallsyms_lookup_name(tmpstr);
2848 sync();
2849 }
2850 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 if (!(*vp)) {
2852 printf("unknown symbol '%s'\n", tmpstr);
2853 return 0;
2854 }
2855 return 1;
2856 }
2857
2858 d = hexdigit(c);
2859 if (d == EOF) {
2860 termch = c;
2861 return 0;
2862 }
2863 v = 0;
2864 do {
2865 v = (v << 4) + d;
2866 c = inchar();
2867 d = hexdigit(c);
2868 } while (d != EOF);
2869 termch = c;
2870 *vp = v;
2871 return 1;
2872}
2873
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002874static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875scannl(void)
2876{
2877 int c;
2878
2879 c = termch;
2880 termch = 0;
2881 while( c != '\n' )
2882 c = inchar();
2883}
2884
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002885static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886{
2887 if( '0' <= c && c <= '9' )
2888 return c - '0';
2889 if( 'A' <= c && c <= 'F' )
2890 return c - ('A' - 10);
2891 if( 'a' <= c && c <= 'f' )
2892 return c - ('a' - 10);
2893 return EOF;
2894}
2895
2896void
2897getstring(char *s, int size)
2898{
2899 int c;
2900
2901 c = skipbl();
2902 do {
2903 if( size > 1 ){
2904 *s++ = c;
2905 --size;
2906 }
2907 c = inchar();
2908 } while( c != ' ' && c != '\t' && c != '\n' );
2909 termch = c;
2910 *s = 0;
2911}
2912
2913static char line[256];
2914static char *lineptr;
2915
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002916static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917flush_input(void)
2918{
2919 lineptr = NULL;
2920}
2921
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002922static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923inchar(void)
2924{
2925 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002926 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 lineptr = NULL;
2928 return EOF;
2929 }
2930 lineptr = line;
2931 }
2932 return *lineptr++;
2933}
2934
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002935static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936take_input(char *str)
2937{
2938 lineptr = str;
2939}
2940
2941
2942static void
2943symbol_lookup(void)
2944{
2945 int type = inchar();
2946 unsigned long addr;
2947 static char tmp[64];
2948
2949 switch (type) {
2950 case 'a':
2951 if (scanhex(&addr))
2952 xmon_print_symbol(addr, ": ", "\n");
2953 termch = 0;
2954 break;
2955 case 's':
2956 getstring(tmp, 64);
2957 if (setjmp(bus_error_jmp) == 0) {
2958 catch_memory_errors = 1;
2959 sync();
2960 addr = kallsyms_lookup_name(tmp);
2961 if (addr)
2962 printf("%s: %lx\n", tmp, addr);
2963 else
2964 printf("Symbol '%s' not found.\n", tmp);
2965 sync();
2966 }
2967 catch_memory_errors = 0;
2968 termch = 0;
2969 break;
2970 }
2971}
2972
2973
2974/* Print an address in numeric and symbolic form (if possible) */
2975static void xmon_print_symbol(unsigned long address, const char *mid,
2976 const char *after)
2977{
2978 char *modname;
2979 const char *name = NULL;
2980 unsigned long offset, size;
2981
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002982 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 if (setjmp(bus_error_jmp) == 0) {
2984 catch_memory_errors = 1;
2985 sync();
2986 name = kallsyms_lookup(address, &size, &offset, &modname,
2987 tmpstr);
2988 sync();
2989 /* wait a little while to see if we get a machine check */
2990 __delay(200);
2991 }
2992
2993 catch_memory_errors = 0;
2994
2995 if (name) {
2996 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2997 if (modname)
2998 printf(" [%s]", modname);
2999 }
3000 printf("%s", after);
3001}
3002
Aneesh Kumar K.Vcaca2852016-04-29 23:26:07 +10003003#ifdef CONFIG_PPC_STD_MMU_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10003004void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005{
3006 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05303007 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11003008 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009
Michael Ellerman736256e2014-05-26 21:02:14 +10003010 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011
Michael Neuling584f8b72007-12-06 17:24:48 +11003012 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11003013 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
3014 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Anshuman Khandual8218a302015-07-29 12:40:04 +05303015 if (esid || vsid) {
will schmidtb3b95952007-12-07 08:22:23 +11003016 printf("%02d %016lx %016lx", i, esid, vsid);
Anshuman Khandual8218a302015-07-29 12:40:04 +05303017 if (esid & SLB_ESID_V) {
will schmidtb3b95952007-12-07 08:22:23 +11003018 llp = vsid & SLB_VSID_LLP;
3019 if (vsid & SLB_VSID_B_1T) {
3020 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
3021 GET_ESID_1T(esid),
3022 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
3023 llp);
3024 } else {
3025 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
3026 GET_ESID(esid),
3027 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
3028 llp);
3029 }
3030 } else
3031 printf("\n");
3032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 }
3034}
Paul Mackerrasf78541d2005-10-28 22:53:37 +10003035#endif
3036
3037#ifdef CONFIG_PPC_STD_MMU_32
3038void dump_segments(void)
3039{
3040 int i;
3041
3042 printf("sr0-15 =");
3043 for (i = 0; i < 16; ++i)
3044 printf(" %x", mfsrin(i));
3045 printf("\n");
3046}
3047#endif
3048
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003049#ifdef CONFIG_44x
3050static void dump_tlb_44x(void)
3051{
3052 int i;
3053
3054 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
3055 unsigned long w0,w1,w2;
3056 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
3057 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
3058 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
3059 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
3060 if (w0 & PPC44x_TLB_VALID) {
3061 printf("V %08x -> %01x%08x %c%c%c%c%c",
3062 w0 & PPC44x_TLB_EPN_MASK,
3063 w1 & PPC44x_TLB_ERPN_MASK,
3064 w1 & PPC44x_TLB_RPN_MASK,
3065 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
3066 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
3067 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
3068 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
3069 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
3070 }
3071 printf("\n");
3072 }
3073}
3074#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003075
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10003076#ifdef CONFIG_PPC_BOOK3E
3077static void dump_tlb_book3e(void)
3078{
3079 u32 mmucfg, pidmask, lpidmask;
3080 u64 ramask;
3081 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3082 int mmu_version;
3083 static const char *pgsz_names[] = {
3084 " 1K",
3085 " 2K",
3086 " 4K",
3087 " 8K",
3088 " 16K",
3089 " 32K",
3090 " 64K",
3091 "128K",
3092 "256K",
3093 "512K",
3094 " 1M",
3095 " 2M",
3096 " 4M",
3097 " 8M",
3098 " 16M",
3099 " 32M",
3100 " 64M",
3101 "128M",
3102 "256M",
3103 "512M",
3104 " 1G",
3105 " 2G",
3106 " 4G",
3107 " 8G",
3108 " 16G",
3109 " 32G",
3110 " 64G",
3111 "128G",
3112 "256G",
3113 "512G",
3114 " 1T",
3115 " 2T",
3116 };
3117
3118 /* Gather some infos about the MMU */
3119 mmucfg = mfspr(SPRN_MMUCFG);
3120 mmu_version = (mmucfg & 3) + 1;
3121 ntlbs = ((mmucfg >> 2) & 3) + 1;
3122 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3123 lpidsz = (mmucfg >> 24) & 0xf;
3124 rasz = (mmucfg >> 16) & 0x7f;
3125 if ((mmu_version > 1) && (mmucfg & 0x10000))
3126 lrat = 1;
3127 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3128 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3129 pidmask = (1ul << pidsz) - 1;
3130 lpidmask = (1ul << lpidsz) - 1;
3131 ramask = (1ull << rasz) - 1;
3132
3133 for (tlb = 0; tlb < ntlbs; tlb++) {
3134 u32 tlbcfg;
3135 int nent, assoc, new_cc = 1;
3136 printf("TLB %d:\n------\n", tlb);
3137 switch(tlb) {
3138 case 0:
3139 tlbcfg = mfspr(SPRN_TLB0CFG);
3140 break;
3141 case 1:
3142 tlbcfg = mfspr(SPRN_TLB1CFG);
3143 break;
3144 case 2:
3145 tlbcfg = mfspr(SPRN_TLB2CFG);
3146 break;
3147 case 3:
3148 tlbcfg = mfspr(SPRN_TLB3CFG);
3149 break;
3150 default:
3151 printf("Unsupported TLB number !\n");
3152 continue;
3153 }
3154 nent = tlbcfg & 0xfff;
3155 assoc = (tlbcfg >> 24) & 0xff;
3156 for (i = 0; i < nent; i++) {
3157 u32 mas0 = MAS0_TLBSEL(tlb);
3158 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3159 u64 mas2 = 0;
3160 u64 mas7_mas3;
3161 int esel = i, cc = i;
3162
3163 if (assoc != 0) {
3164 cc = i / assoc;
3165 esel = i % assoc;
3166 mas2 = cc * 0x1000;
3167 }
3168
3169 mas0 |= MAS0_ESEL(esel);
3170 mtspr(SPRN_MAS0, mas0);
3171 mtspr(SPRN_MAS1, mas1);
3172 mtspr(SPRN_MAS2, mas2);
3173 asm volatile("tlbre 0,0,0" : : : "memory");
3174 mas1 = mfspr(SPRN_MAS1);
3175 mas2 = mfspr(SPRN_MAS2);
3176 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3177 if (assoc && (i % assoc) == 0)
3178 new_cc = 1;
3179 if (!(mas1 & MAS1_VALID))
3180 continue;
3181 if (assoc == 0)
3182 printf("%04x- ", i);
3183 else if (new_cc)
3184 printf("%04x-%c", cc, 'A' + esel);
3185 else
3186 printf(" |%c", 'A' + esel);
3187 new_cc = 0;
3188 printf(" %016llx %04x %s %c%c AS%c",
3189 mas2 & ~0x3ffull,
3190 (mas1 >> 16) & 0x3fff,
3191 pgsz_names[(mas1 >> 7) & 0x1f],
3192 mas1 & MAS1_IND ? 'I' : ' ',
3193 mas1 & MAS1_IPROT ? 'P' : ' ',
3194 mas1 & MAS1_TS ? '1' : '0');
3195 printf(" %c%c%c%c%c%c%c",
3196 mas2 & MAS2_X0 ? 'a' : ' ',
3197 mas2 & MAS2_X1 ? 'v' : ' ',
3198 mas2 & MAS2_W ? 'w' : ' ',
3199 mas2 & MAS2_I ? 'i' : ' ',
3200 mas2 & MAS2_M ? 'm' : ' ',
3201 mas2 & MAS2_G ? 'g' : ' ',
3202 mas2 & MAS2_E ? 'e' : ' ');
3203 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3204 if (mas1 & MAS1_IND)
3205 printf(" %s\n",
3206 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3207 else
3208 printf(" U%c%c%c S%c%c%c\n",
3209 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3210 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3211 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3212 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3213 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3214 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3215 }
3216 }
3217}
3218#endif /* CONFIG_PPC_BOOK3E */
3219
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003220static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003222 if (enable) {
3223 __debugger = xmon;
3224 __debugger_ipi = xmon_ipi;
3225 __debugger_bpt = xmon_bpt;
3226 __debugger_sstep = xmon_sstep;
3227 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003228 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003229 __debugger_fault_handler = xmon_fault_handler;
3230 } else {
3231 __debugger = NULL;
3232 __debugger_ipi = NULL;
3233 __debugger_bpt = NULL;
3234 __debugger_sstep = NULL;
3235 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003236 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003237 __debugger_fault_handler = NULL;
3238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003240
3241#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003242static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003243{
3244 /* ensure xmon is enabled */
3245 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003246 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003247}
3248
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003249static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003250 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003251 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003252 .action_msg = "Entering xmon",
3253};
3254
3255static int __init setup_xmon_sysrq(void)
3256{
3257 register_sysrq_key('x', &sysrq_xmon_op);
3258 return 0;
3259}
3260__initcall(setup_xmon_sysrq);
3261#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003262
Olaf Heringf5e6a282007-06-24 16:57:08 +10003263static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10003264
3265static int __init early_parse_xmon(char *p)
3266{
3267 if (!p || strncmp(p, "early", 5) == 0) {
3268 /* just "xmon" is equivalent to "xmon=early" */
3269 xmon_init(1);
3270 xmon_early = 1;
3271 } else if (strncmp(p, "on", 2) == 0)
3272 xmon_init(1);
3273 else if (strncmp(p, "off", 3) == 0)
3274 xmon_off = 1;
3275 else if (strncmp(p, "nobt", 4) == 0)
3276 xmon_no_auto_backtrace = 1;
3277 else
3278 return 1;
3279
3280 return 0;
3281}
3282early_param("xmon", early_parse_xmon);
3283
3284void __init xmon_setup(void)
3285{
3286#ifdef CONFIG_XMON_DEFAULT
3287 if (!xmon_off)
3288 xmon_init(1);
3289#endif
3290 if (xmon_early)
3291 debugger(NULL);
3292}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003293
Arnd Bergmanne0555952006-11-27 19:18:55 +01003294#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003295
3296struct spu_info {
3297 struct spu *spu;
3298 u64 saved_mfc_sr1_RW;
3299 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003300 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003301 u8 stopped_ok;
3302};
3303
3304#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3305
3306static struct spu_info spu_info[XMON_NUM_SPUS];
3307
3308void xmon_register_spus(struct list_head *list)
3309{
3310 struct spu *spu;
3311
3312 list_for_each_entry(spu, list, full_list) {
3313 if (spu->number >= XMON_NUM_SPUS) {
3314 WARN_ON(1);
3315 continue;
3316 }
3317
3318 spu_info[spu->number].spu = spu;
3319 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003320 spu_info[spu->number].dump_addr = (unsigned long)
3321 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003322 }
3323}
3324
3325static void stop_spus(void)
3326{
3327 struct spu *spu;
3328 int i;
3329 u64 tmp;
3330
3331 for (i = 0; i < XMON_NUM_SPUS; i++) {
3332 if (!spu_info[i].spu)
3333 continue;
3334
3335 if (setjmp(bus_error_jmp) == 0) {
3336 catch_memory_errors = 1;
3337 sync();
3338
3339 spu = spu_info[i].spu;
3340
3341 spu_info[i].saved_spu_runcntl_RW =
3342 in_be32(&spu->problem->spu_runcntl_RW);
3343
3344 tmp = spu_mfc_sr1_get(spu);
3345 spu_info[i].saved_mfc_sr1_RW = tmp;
3346
3347 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3348 spu_mfc_sr1_set(spu, tmp);
3349
3350 sync();
3351 __delay(200);
3352
3353 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003354
3355 printf("Stopped spu %.2d (was %s)\n", i,
3356 spu_info[i].saved_spu_runcntl_RW ?
3357 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003358 } else {
3359 catch_memory_errors = 0;
3360 printf("*** Error stopping spu %.2d\n", i);
3361 }
3362 catch_memory_errors = 0;
3363 }
3364}
3365
3366static void restart_spus(void)
3367{
3368 struct spu *spu;
3369 int i;
3370
3371 for (i = 0; i < XMON_NUM_SPUS; i++) {
3372 if (!spu_info[i].spu)
3373 continue;
3374
3375 if (!spu_info[i].stopped_ok) {
3376 printf("*** Error, spu %d was not successfully stopped"
3377 ", not restarting\n", i);
3378 continue;
3379 }
3380
3381 if (setjmp(bus_error_jmp) == 0) {
3382 catch_memory_errors = 1;
3383 sync();
3384
3385 spu = spu_info[i].spu;
3386 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3387 out_be32(&spu->problem->spu_runcntl_RW,
3388 spu_info[i].saved_spu_runcntl_RW);
3389
3390 sync();
3391 __delay(200);
3392
3393 printf("Restarted spu %.2d\n", i);
3394 } else {
3395 catch_memory_errors = 0;
3396 printf("*** Error restarting spu %.2d\n", i);
3397 }
3398 catch_memory_errors = 0;
3399 }
3400}
3401
Michael Ellermana8984972006-10-24 18:31:28 +02003402#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003403#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003404do { \
3405 if (setjmp(bus_error_jmp) == 0) { \
3406 catch_memory_errors = 1; \
3407 sync(); \
3408 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003409 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003410 sync(); \
3411 __delay(200); \
3412 } else { \
3413 catch_memory_errors = 0; \
3414 printf(" %-*s = *** Error reading field.\n", \
3415 DUMP_WIDTH, #field); \
3416 } \
3417 catch_memory_errors = 0; \
3418} while (0)
3419
Michael Ellerman437a0702006-11-23 00:46:39 +01003420#define DUMP_FIELD(obj, format, field) \
3421 DUMP_VALUE(format, field, obj->field)
3422
Michael Ellermana8984972006-10-24 18:31:28 +02003423static void dump_spu_fields(struct spu *spu)
3424{
3425 printf("Dumping spu fields at address %p:\n", spu);
3426
3427 DUMP_FIELD(spu, "0x%x", number);
3428 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003429 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3430 DUMP_FIELD(spu, "0x%p", local_store);
3431 DUMP_FIELD(spu, "0x%lx", ls_size);
3432 DUMP_FIELD(spu, "0x%x", node);
3433 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003434 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003435 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003436 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3437 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003438 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3439 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3440 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3441 DUMP_FIELD(spu, "0x%x", slb_replace);
3442 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003443 DUMP_FIELD(spu, "0x%p", mm);
3444 DUMP_FIELD(spu, "0x%p", ctx);
3445 DUMP_FIELD(spu, "0x%p", rq);
3446 DUMP_FIELD(spu, "0x%p", timestamp);
3447 DUMP_FIELD(spu, "0x%lx", problem_phys);
3448 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003449 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3450 in_be32(&spu->problem->spu_runcntl_RW));
3451 DUMP_VALUE("0x%x", problem->spu_status_R,
3452 in_be32(&spu->problem->spu_status_R));
3453 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3454 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003455 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003456 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003457}
3458
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003459int
3460spu_inst_dump(unsigned long adr, long count, int praddr)
3461{
3462 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3463}
3464
3465static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003466{
3467 unsigned long offset, addr, ls_addr;
3468
3469 if (setjmp(bus_error_jmp) == 0) {
3470 catch_memory_errors = 1;
3471 sync();
3472 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3473 sync();
3474 __delay(200);
3475 } else {
3476 catch_memory_errors = 0;
3477 printf("*** Error: accessing spu info for spu %d\n", num);
3478 return;
3479 }
3480 catch_memory_errors = 0;
3481
3482 if (scanhex(&offset))
3483 addr = ls_addr + offset;
3484 else
3485 addr = spu_info[num].dump_addr;
3486
3487 if (addr >= ls_addr + LS_SIZE) {
3488 printf("*** Error: address outside of local store\n");
3489 return;
3490 }
3491
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003492 switch (subcmd) {
3493 case 'i':
3494 addr += spu_inst_dump(addr, 16, 1);
3495 last_cmd = "sdi\n";
3496 break;
3497 default:
3498 prdump(addr, 64);
3499 addr += 64;
3500 last_cmd = "sd\n";
3501 break;
3502 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003503
3504 spu_info[num].dump_addr = addr;
3505}
3506
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003507static int do_spu_cmd(void)
3508{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003509 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003510 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003511
3512 cmd = inchar();
3513 switch (cmd) {
3514 case 's':
3515 stop_spus();
3516 break;
3517 case 'r':
3518 restart_spus();
3519 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003520 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003521 subcmd = inchar();
3522 if (isxdigit(subcmd) || subcmd == '\n')
3523 termch = subcmd;
3524 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003525 scanhex(&num);
3526 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003527 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003528 return 0;
3529 }
3530
3531 switch (cmd) {
3532 case 'f':
3533 dump_spu_fields(spu_info[num].spu);
3534 break;
3535 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003536 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003537 break;
3538 }
3539
Michael Ellermana8984972006-10-24 18:31:28 +02003540 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003541 default:
3542 return -1;
3543 }
3544
3545 return 0;
3546}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003547#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003548static int do_spu_cmd(void)
3549{
3550 return -1;
3551}
3552#endif