blob: e0522f60f0eeb310657684bd1c01c65f439cf8e7 [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 */
Michael Ellerman56144ec2015-11-06 13:21:17 +110013
14#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/errno.h>
Ingo Molnar3f07c012017-02-08 18:51:30 +010016#include <linux/sched/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/smp.h>
18#include <linux/mm.h>
19#include <linux/reboot.h>
20#include <linux/delay.h>
21#include <linux/kallsyms.h>
Michael Ellermanca5dd392012-08-23 22:09:12 +000022#include <linux/kmsg_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040024#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110025#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080026#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010027#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080028#include <linux/bug.h>
Anton Blancharda71d64b2014-08-05 14:55:00 +100029#include <linux/nmi.h>
Vincent Bernat05b981f2014-07-15 13:43:47 +020030#include <linux/ctype.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
Michael Ellerman7644d582017-02-10 12:04:56 +110032#include <asm/debugfs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/ptrace.h>
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +100034#include <asm/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/string.h>
36#include <asm/prom.h>
37#include <asm/machdep.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100038#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/processor.h>
40#include <asm/pgtable.h>
41#include <asm/mmu.h>
42#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <asm/cputable.h>
44#include <asm/rtas.h>
45#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100046#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020047#include <asm/spu.h>
48#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110049#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000050#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010051#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000052#include <asm/hw_breakpoint.h>
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +100053#include <asm/xive.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110054#include <asm/opal.h>
55#include <asm/firmware.h>
Balbir Singhefe4fbb2017-06-27 17:48:58 +100056#include <asm/code-patching.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110057
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100058#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100060#include <asm/paca.h>
61#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Anshuman Khandual1ad7d702014-11-28 10:06:42 +053063#if defined(CONFIG_PPC_SPLPAR)
64#include <asm/plpar_wrappers.h>
65#else
66static inline long plapr_set_ciabr(unsigned long ciabr) {return 0; };
67#endif
68
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010070#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Linus Torvalds1da177e2005-04-16 15:20:36 -070072#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100073static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074static unsigned long xmon_taken = 1;
75static int xmon_owner;
76static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000077#else
78#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070079#endif /* CONFIG_SMP */
80
Anton Blanchard5be34922010-01-12 00:50:14 +000081static unsigned long in_xmon __read_mostly = 0;
Pan Xinhui3b5bf422017-03-22 16:27:49 -030082static int xmon_on = IS_ENABLED(CONFIG_XMON_DEFAULT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84static unsigned long adrs;
85static int size = 1;
86#define MAX_DUMP (128 * 1024)
87static unsigned long ndump = 64;
88static unsigned long nidump = 16;
89static unsigned long ncsum = 4096;
90static int termch;
91static char tmpstr[128];
92
Linus Torvalds1da177e2005-04-16 15:20:36 -070093static long bus_error_jmp[JMP_BUF_LEN];
94static int catch_memory_errors;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +100095static int catch_spr_faults;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98/* Breakpoint stuff */
99struct bpt {
100 unsigned long address;
101 unsigned int instr[2];
102 atomic_t ref_count;
103 int enabled;
104 unsigned long pad;
105};
106
107/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100108#define BP_CIABR 1
109#define BP_TRAP 2
110#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
112#define NBPTS 256
113static struct bpt bpts[NBPTS];
114static struct bpt dabr;
115static struct bpt *iabr;
116static unsigned bpinstr = 0x7fe00008; /* trap */
117
118#define BP_NUM(bp) ((bp) - bpts + 1)
119
120/* Prototypes */
121static int cmds(struct pt_regs *);
122static int mread(unsigned long, void *, int);
123static int mwrite(unsigned long, void *, int);
124static int handle_fault(struct pt_regs *);
125static void byterev(unsigned char *, int);
126static void memex(void);
127static int bsesc(void);
128static void dump(void);
129static void prdump(unsigned long, long);
130static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000131static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100132
133#ifdef CONFIG_PPC_POWERNV
134static void dump_opal_msglog(void);
135#else
136static inline void dump_opal_msglog(void)
137{
138 printf("Machine is not running OPAL firmware.\n");
139}
140#endif
141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static void backtrace(struct pt_regs *);
143static void excprint(struct pt_regs *);
144static void prregs(struct pt_regs *);
145static void memops(int);
146static void memlocate(void);
147static void memzcan(void);
148static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
149int skipbl(void);
150int scanhex(unsigned long *valp);
151static void scannl(void);
152static int hexdigit(int);
153void getstring(char *, int);
154static void flush_input(void);
155static int inchar(void);
156static void take_input(char *);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000157static int read_spr(int, unsigned long *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158static void write_spr(int, unsigned long);
159static void super_regs(void);
160static void remove_bpts(void);
161static void insert_bpts(void);
162static void remove_cpu_bpts(void);
163static void insert_cpu_bpts(void);
164static struct bpt *at_breakpoint(unsigned long pc);
165static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
166static int do_step(struct pt_regs *);
167static void bpt_cmds(void);
168static void cacheflush(void);
169static int cpu_cmd(void);
170static void csum(void);
171static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000172static void proccall(void);
Douglas Miller6dfb5402015-11-23 09:01:15 -0600173static void show_tasks(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174void dump_segments(void);
175static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200176static void xmon_show_stack(unsigned long sp, unsigned long lr,
177 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178static void xmon_print_symbol(unsigned long address, const char *mid,
179 const char *after);
180static const char *getvecname(unsigned long vec);
181
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200182static int do_spu_cmd(void);
183
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100184#ifdef CONFIG_44x
185static void dump_tlb_44x(void);
186#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000187#ifdef CONFIG_PPC_BOOK3E
188static void dump_tlb_book3e(void);
189#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100190
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000191#ifdef CONFIG_PPC64
192#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000193#else
194#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000195#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100197#ifdef __LITTLE_ENDIAN__
198#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
199#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100201#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203static char *help_string = "\
204Commands:\n\
205 b show breakpoints\n\
206 bd set data breakpoint\n\
207 bi set instruction breakpoint\n\
208 bc clear breakpoint\n"
209#ifdef CONFIG_SMP
210 "\
211 c print cpus stopped in xmon\n\
212 c# try to switch to cpu number h (in hex)\n"
213#endif
214 "\
215 C checksum\n\
216 d dump bytes\n\
Douglas Miller5e48dc02017-02-07 07:40:44 -0600217 d1 dump 1 byte values\n\
218 d2 dump 2 byte values\n\
219 d4 dump 4 byte values\n\
220 d8 dump 8 byte values\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 di dump instructions\n\
222 df dump float values\n\
223 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000224 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100225#ifdef CONFIG_PPC_POWERNV
226 "\
227 do dump the OPAL message log\n"
228#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000229#ifdef CONFIG_PPC64
230 "\
231 dp[#] dump paca for current cpu, or cpu #\n\
232 dpa dump paca for all possible cpus\n"
233#endif
234 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100235 dr dump stream of raw bytes\n\
Michael Ellerman56144ec2015-11-06 13:21:17 +1100236 dt dump the tracing buffers (uses printk)\n\
Breno Leitao4125d012017-08-02 17:14:05 -0300237 dtc dump the tracing buffers for current CPU (uses printk)\n\
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +1000238"
239#ifdef CONFIG_PPC_POWERNV
240" dx# dump xive on CPU #\n\
241 dxi# dump xive irq state #\n\
242 dxa dump xive on all CPUs\n"
243#endif
244" e print exception information\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 f flush cache\n\
246 la lookup symbol+offset of specified address\n\
247 ls lookup address of specified symbol\n\
248 m examine/change memory\n\
249 mm move a block of memory\n\
250 ms set a block of memory\n\
251 md compare two blocks of memory\n\
252 ml locate a block of memory\n\
253 mz zero a block of memory\n\
254 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000255 p call a procedure\n\
Douglas Miller6dfb5402015-11-23 09:01:15 -0600256 P list processes/tasks\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200258 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100259#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200260" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200261 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100262 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900263 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100264 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200265#endif
266" S print special registers\n\
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000267 Sa print all SPRs\n\
268 Sr # read SPR #\n\
269 Sw #v write v to SPR #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100272 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000273#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000274" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000275#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000276" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000277#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100278" u dump TLB\n"
279#endif
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000280" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100281" # n limit output to n lines per page (for dp, dpa, dl)\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000282" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 zh halt\n"
284;
285
286static struct pt_regs *xmon_regs;
287
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000288static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
290 asm volatile("sync; isync");
291}
292
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000293static inline void store_inst(void *p)
294{
295 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
296}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000298static inline void cflush(void *p)
299{
300 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
301}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000303static inline void cinval(void *p)
304{
305 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
306}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530308/**
309 * write_ciabr() - write the CIABR SPR
310 * @ciabr: The value to write.
311 *
312 * This function writes a value to the CIARB register either directly
313 * through mtspr instruction if the kernel is in HV privilege mode or
314 * call a hypervisor function to achieve the same in case the kernel
315 * is in supervisor privilege mode.
316 */
317static void write_ciabr(unsigned long ciabr)
318{
319 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
320 return;
321
322 if (cpu_has_feature(CPU_FTR_HVMODE)) {
323 mtspr(SPRN_CIABR, ciabr);
324 return;
325 }
326 plapr_set_ciabr(ciabr);
327}
328
329/**
330 * set_ciabr() - set the CIABR
331 * @addr: The value to set.
332 *
333 * This function sets the correct privilege value into the the HW
334 * breakpoint address before writing it up in the CIABR register.
335 */
336static void set_ciabr(unsigned long addr)
337{
338 addr &= ~CIABR_PRIV;
339
340 if (cpu_has_feature(CPU_FTR_HVMODE))
341 addr |= CIABR_PRIV_HYPER;
342 else
343 addr |= CIABR_PRIV_SUPER;
344 write_ciabr(addr);
345}
346
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347/*
348 * Disable surveillance (the service processor watchdog function)
349 * while we are in xmon.
350 * XXX we should re-enable it when we leave. :)
351 */
352#define SURVEILLANCE_TOKEN 9000
353
354static inline void disable_surveillance(void)
355{
356#ifdef CONFIG_PPC_PSERIES
357 /* Since this can't be a module, args should end up below 4GB. */
358 static struct rtas_args args;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100359 int token;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
361 /*
362 * At this point we have got all the cpus we can into
363 * xmon, so there is hopefully no other cpu calling RTAS
364 * at the moment, even though we don't take rtas.lock.
365 * If we did try to take rtas.lock there would be a
366 * real possibility of deadlock.
367 */
Michael Ellerman08eb1052015-11-24 22:26:09 +1100368 token = rtas_token("set-indicator");
369 if (token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100371
372 rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0);
373
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374#endif /* CONFIG_PPC_PSERIES */
375}
376
377#ifdef CONFIG_SMP
378static int xmon_speaker;
379
380static void get_output_lock(void)
381{
382 int me = smp_processor_id() + 0x100;
383 int last_speaker = 0, prev;
384 long timeout;
385
386 if (xmon_speaker == me)
387 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100390 last_speaker = cmpxchg(&xmon_speaker, 0, me);
391 if (last_speaker == 0)
392 return;
393
Michael Ellerman15075892013-12-23 23:46:05 +1100394 /*
395 * Wait a full second for the lock, we might be on a slow
396 * console, but check every 100us.
397 */
398 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100400 if (--timeout > 0) {
401 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100403 }
404
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 /* hostile takeover */
406 prev = cmpxchg(&xmon_speaker, last_speaker, me);
407 if (prev == last_speaker)
408 return;
409 break;
410 }
411 }
412}
413
414static void release_output_lock(void)
415{
416 xmon_speaker = 0;
417}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000418
419int cpus_are_in_xmon(void)
420{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000421 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000422}
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000423
424static bool wait_for_other_cpus(int ncpus)
425{
426 unsigned long timeout;
427
428 /* We wait for 2s, which is a metric "little while" */
429 for (timeout = 20000; timeout != 0; --timeout) {
430 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
431 return true;
432 udelay(100);
433 barrier();
434 }
435
436 return false;
437}
438#endif /* CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Josh Boyerdaf8f402009-09-23 03:51:04 +0000440static inline int unrecoverable_excp(struct pt_regs *regs)
441{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000442#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000443 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000444 return 0;
445#else
446 return ((regs->msr & MSR_RI) == 0);
447#endif
448}
449
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000450static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
452 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 struct bpt *bp;
454 long recurse_jmp[JMP_BUF_LEN];
455 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100456 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457#ifdef CONFIG_SMP
458 int cpu;
459 int secondary;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460#endif
461
Anton Blanchardf13659e2007-03-21 01:48:34 +1100462 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000463 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
465 bp = in_breakpoint_table(regs->nip, &offset);
466 if (bp != NULL) {
467 regs->nip = bp->address + offset;
468 atomic_dec(&bp->ref_count);
469 }
470
471 remove_cpu_bpts();
472
473#ifdef CONFIG_SMP
474 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000475 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000476 /*
477 * We catch SPR read/write faults here because the 0x700, 0xf60
478 * etc. handlers don't call debugger_fault_handler().
479 */
480 if (catch_spr_faults)
481 longjmp(bus_error_jmp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 get_output_lock();
483 excprint(regs);
484 printf("cpu 0x%x: Exception %lx %s in xmon, "
485 "returning to main loop\n",
486 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000487 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 longjmp(xmon_fault_jmp[cpu], 1);
489 }
490
491 if (setjmp(recurse_jmp) != 0) {
492 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000493 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 printf("xmon: WARNING: bad recursive fault "
495 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000496 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 goto waiting;
498 }
499 secondary = !(xmon_taken && cpu == xmon_owner);
500 goto cmdloop;
501 }
502
503 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000506 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000508 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 fromipi = 0;
510
511 if (!fromipi) {
512 get_output_lock();
513 excprint(regs);
514 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000515 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 cpu, BP_NUM(bp));
517 xmon_print_symbol(regs->nip, " ", ")\n");
518 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000519 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 printf("WARNING: exception is not recoverable, "
521 "can't continue\n");
522 release_output_lock();
523 }
524
Michael Ellermand2b496e2013-12-23 23:46:06 +1100525 cpumask_set_cpu(cpu, &cpus_in_xmon);
526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 waiting:
528 secondary = 1;
529 while (secondary && !xmon_gate) {
530 if (in_xmon == 0) {
531 if (fromipi)
532 goto leave;
533 secondary = test_and_set_bit(0, &in_xmon);
534 }
535 barrier();
536 }
537
538 if (!secondary && !xmon_gate) {
539 /* we are the first cpu to come in */
540 /* interrupt other cpu(s) */
541 int ncpus = num_online_cpus();
542
543 xmon_owner = cpu;
544 mb();
545 if (ncpus > 1) {
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000546 /*
547 * A system reset (trap == 0x100) can be triggered on
548 * all CPUs, so when we come in via 0x100 try waiting
549 * for the other CPUs to come in before we send the
550 * debugger break (IPI). This is similar to
551 * crash_kexec_secondary().
552 */
553 if (TRAP(regs) != 0x100 || !wait_for_other_cpus(ncpus))
554 smp_send_debugger_break();
555
556 wait_for_other_cpus(ncpus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 }
558 remove_bpts();
559 disable_surveillance();
560 /* for breakpoint or single step, print the current instr. */
561 if (bp || TRAP(regs) == 0xd00)
562 ppc_inst_dump(regs->nip, 1, 0);
563 printf("enter ? for help\n");
564 mb();
565 xmon_gate = 1;
566 barrier();
567 }
568
569 cmdloop:
570 while (in_xmon) {
571 if (secondary) {
572 if (cpu == xmon_owner) {
573 if (!test_and_set_bit(0, &xmon_taken)) {
574 secondary = 0;
575 continue;
576 }
577 /* missed it */
578 while (cpu == xmon_owner)
579 barrier();
580 }
581 barrier();
582 } else {
583 cmd = cmds(regs);
584 if (cmd != 0) {
585 /* exiting xmon */
586 insert_bpts();
587 xmon_gate = 0;
588 wmb();
589 in_xmon = 0;
590 break;
591 }
592 /* have switched to some other cpu */
593 secondary = 1;
594 }
595 }
596 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000597 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599#else
600 /* UP is simple... */
601 if (in_xmon) {
602 printf("Exception %lx %s in xmon, returning to main loop\n",
603 regs->trap, getvecname(TRAP(regs)));
604 longjmp(xmon_fault_jmp[0], 1);
605 }
606 if (setjmp(recurse_jmp) == 0) {
607 xmon_fault_jmp[0] = recurse_jmp;
608 in_xmon = 1;
609
610 excprint(regs);
611 bp = at_breakpoint(regs->nip);
612 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000613 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 xmon_print_symbol(regs->nip, " ", ")\n");
615 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000616 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 printf("WARNING: exception is not recoverable, "
618 "can't continue\n");
619 remove_bpts();
620 disable_surveillance();
621 /* for breakpoint or single step, print the current instr. */
622 if (bp || TRAP(regs) == 0xd00)
623 ppc_inst_dump(regs->nip, 1, 0);
624 printf("enter ? for help\n");
625 }
626
627 cmd = cmds(regs);
628
629 insert_bpts();
630 in_xmon = 0;
631#endif
632
Josh Boyercdd39042009-10-05 04:46:05 +0000633#ifdef CONFIG_BOOKE
634 if (regs->msr & MSR_DE) {
635 bp = at_breakpoint(regs->nip);
636 if (bp != NULL) {
637 regs->nip = (unsigned long) &bp->instr[0];
638 atomic_inc(&bp->ref_count);
639 }
640 }
641#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000642 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 bp = at_breakpoint(regs->nip);
644 if (bp != NULL) {
645 int stepped = emulate_step(regs, bp->instr[0]);
646 if (stepped == 0) {
647 regs->nip = (unsigned long) &bp->instr[0];
648 atomic_inc(&bp->ref_count);
649 } else if (stepped < 0) {
650 printf("Couldn't single-step %s instruction\n",
651 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
652 }
653 }
654 }
Josh Boyercdd39042009-10-05 04:46:05 +0000655#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 insert_cpu_bpts();
657
Anton Blancharda71d64b2014-08-05 14:55:00 +1000658 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100659 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000661 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662}
663
664int xmon(struct pt_regs *excp)
665{
666 struct pt_regs regs;
667
668 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000669 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 excp = &regs;
671 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 return xmon_core(excp, 0);
674}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000675EXPORT_SYMBOL(xmon);
676
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000677irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000678{
679 unsigned long flags;
680 local_irq_save(flags);
681 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000682 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000683 local_irq_restore(flags);
684 return IRQ_HANDLED;
685}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000687static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
689 struct bpt *bp;
690 unsigned long offset;
691
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000692 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return 0;
694
695 /* Are we at the trap at bp->instr[1] for some bp? */
696 bp = in_breakpoint_table(regs->nip, &offset);
697 if (bp != NULL && offset == 4) {
698 regs->nip = bp->address + 4;
699 atomic_dec(&bp->ref_count);
700 return 1;
701 }
702
703 /* Are we at a breakpoint? */
704 bp = at_breakpoint(regs->nip);
705 if (!bp)
706 return 0;
707
708 xmon_core(regs, 0);
709
710 return 1;
711}
712
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000713static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
715 if (user_mode(regs))
716 return 0;
717 xmon_core(regs, 0);
718 return 1;
719}
720
Michael Neuling9422de32012-12-20 14:06:44 +0000721static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000723 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000725 if (dabr.enabled == 0)
726 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 xmon_core(regs, 0);
728 return 1;
729}
730
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000731static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000733 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000735 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 return 0;
737 xmon_core(regs, 0);
738 return 1;
739}
740
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000741static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742{
743#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000744 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 xmon_core(regs, 1);
746#endif
747 return 0;
748}
749
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000750static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
752 struct bpt *bp;
753 unsigned long offset;
754
755 if (in_xmon && catch_memory_errors)
756 handle_fault(regs); /* doesn't return */
757
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000758 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 bp = in_breakpoint_table(regs->nip, &offset);
760 if (bp != NULL) {
761 regs->nip = bp->address + offset;
762 atomic_dec(&bp->ref_count);
763 }
764 }
765
766 return 0;
767}
768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769static struct bpt *at_breakpoint(unsigned long pc)
770{
771 int i;
772 struct bpt *bp;
773
774 bp = bpts;
775 for (i = 0; i < NBPTS; ++i, ++bp)
776 if (bp->enabled && pc == bp->address)
777 return bp;
778 return NULL;
779}
780
781static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
782{
783 unsigned long off;
784
785 off = nip - (unsigned long) bpts;
786 if (off >= sizeof(bpts))
787 return NULL;
788 off %= sizeof(struct bpt);
789 if (off != offsetof(struct bpt, instr[0])
790 && off != offsetof(struct bpt, instr[1]))
791 return NULL;
792 *offp = off - offsetof(struct bpt, instr[0]);
793 return (struct bpt *) (nip - off);
794}
795
796static struct bpt *new_breakpoint(unsigned long a)
797{
798 struct bpt *bp;
799
800 a &= ~3UL;
801 bp = at_breakpoint(a);
802 if (bp)
803 return bp;
804
805 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
806 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
807 bp->address = a;
808 bp->instr[1] = bpinstr;
809 store_inst(&bp->instr[1]);
810 return bp;
811 }
812 }
813
814 printf("Sorry, no free breakpoints. Please clear one first.\n");
815 return NULL;
816}
817
818static void insert_bpts(void)
819{
820 int i;
821 struct bpt *bp;
822
823 bp = bpts;
824 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100825 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 continue;
827 if (mread(bp->address, &bp->instr[0], 4) != 4) {
828 printf("Couldn't read instruction at %lx, "
829 "disabling breakpoint there\n", bp->address);
830 bp->enabled = 0;
831 continue;
832 }
833 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
834 printf("Breakpoint at %lx is on an mtmsrd or rfid "
835 "instruction, disabling it\n", bp->address);
836 bp->enabled = 0;
837 continue;
838 }
839 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100840 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 continue;
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000842 if (patch_instruction((unsigned int *)bp->address,
843 bpinstr) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 printf("Couldn't write instruction at %lx, "
845 "disabling breakpoint there\n", bp->address);
846 bp->enabled &= ~BP_TRAP;
847 continue;
848 }
849 store_inst((void *)bp->address);
850 }
851}
852
853static void insert_cpu_bpts(void)
854{
Michael Neuling9422de32012-12-20 14:06:44 +0000855 struct arch_hw_breakpoint brk;
856
857 if (dabr.enabled) {
858 brk.address = dabr.address;
859 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
860 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400861 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000862 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530863
864 if (iabr)
865 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866}
867
868static void remove_bpts(void)
869{
870 int i;
871 struct bpt *bp;
872 unsigned instr;
873
874 bp = bpts;
875 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100876 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 continue;
878 if (mread(bp->address, &instr, 4) == 4
879 && instr == bpinstr
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000880 && patch_instruction(
881 (unsigned int *)bp->address, bp->instr[0]) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 printf("Couldn't remove breakpoint at %lx\n",
883 bp->address);
884 else
885 store_inst((void *)bp->address);
886 }
887}
888
889static void remove_cpu_bpts(void)
890{
Michael Neuling9422de32012-12-20 14:06:44 +0000891 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530892 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893}
894
Sam bobroff958b7c82015-10-08 11:50:23 +1100895static void set_lpp_cmd(void)
896{
897 unsigned long lpp;
898
899 if (!scanhex(&lpp)) {
900 printf("Invalid number.\n");
901 lpp = 0;
902 }
903 xmon_set_pagination_lpp(lpp);
904}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905/* Command interpreting routine */
906static char *last_cmd;
907
908static int
909cmds(struct pt_regs *excp)
910{
911 int cmd = 0;
912
913 last_cmd = NULL;
914 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200915
Guilherme G. Piccolib5617832017-03-22 16:27:50 -0300916 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
Olaf Hering26c8af52006-09-08 16:29:21 +0200917
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 for(;;) {
919#ifdef CONFIG_SMP
920 printf("%x:", smp_processor_id());
921#endif /* CONFIG_SMP */
922 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 flush_input();
924 termch = 0;
925 cmd = skipbl();
926 if( cmd == '\n' ) {
927 if (last_cmd == NULL)
928 continue;
929 take_input(last_cmd);
930 last_cmd = NULL;
931 cmd = inchar();
932 }
933 switch (cmd) {
934 case 'm':
935 cmd = inchar();
936 switch (cmd) {
937 case 'm':
938 case 's':
939 case 'd':
940 memops(cmd);
941 break;
942 case 'l':
943 memlocate();
944 break;
945 case 'z':
946 memzcan();
947 break;
948 case 'i':
Michal Hocko9af744d2017-02-22 15:46:16 -0800949 show_mem(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 break;
951 default:
952 termch = cmd;
953 memex();
954 }
955 break;
956 case 'd':
957 dump();
958 break;
959 case 'l':
960 symbol_lookup();
961 break;
962 case 'r':
963 prregs(excp); /* print regs */
964 break;
965 case 'e':
966 excprint(excp);
967 break;
968 case 'S':
969 super_regs();
970 break;
971 case 't':
972 backtrace(excp);
973 break;
974 case 'f':
975 cacheflush();
976 break;
977 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200978 if (do_spu_cmd() == 0)
979 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 if (do_step(excp))
981 return cmd;
982 break;
983 case 'x':
984 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100985 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100987 printf(" <no input ...>\n");
988 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 return cmd;
990 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000991 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 break;
Sam bobroff958b7c82015-10-08 11:50:23 +1100993 case '#':
994 set_lpp_cmd();
995 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 case 'b':
997 bpt_cmds();
998 break;
999 case 'C':
1000 csum();
1001 break;
1002 case 'c':
1003 if (cpu_cmd())
1004 return 0;
1005 break;
1006 case 'z':
1007 bootcmds();
1008 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001009 case 'p':
1010 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -06001012 case 'P':
1013 show_tasks();
1014 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001015#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 case 'u':
1017 dump_segments();
1018 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +11001019#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11001020 case 'u':
1021 dump_tlb_44x();
1022 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +00001023#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10001024 case 'u':
1025 dump_tlb_book3e();
1026 break;
1027#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 default:
1029 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +00001030 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 if (' ' < cmd && cmd <= '~')
1032 putchar(cmd);
1033 else
1034 printf("\\x%x", cmd);
1035 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +00001036 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 printf(" (type ? for help)\n");
1038 break;
1039 }
1040 }
1041}
1042
Josh Boyercdd39042009-10-05 04:46:05 +00001043#ifdef CONFIG_BOOKE
1044static int do_step(struct pt_regs *regs)
1045{
1046 regs->msr |= MSR_DE;
1047 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1048 return 1;
1049}
1050#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051/*
1052 * Step a single instruction.
1053 * Some instructions we emulate, others we execute with MSR_SE set.
1054 */
1055static int do_step(struct pt_regs *regs)
1056{
1057 unsigned int instr;
1058 int stepped;
1059
1060 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001061 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 if (mread(regs->nip, &instr, 4) == 4) {
1063 stepped = emulate_step(regs, instr);
1064 if (stepped < 0) {
1065 printf("Couldn't single-step %s instruction\n",
1066 (IS_RFID(instr)? "rfid": "mtmsrd"));
1067 return 0;
1068 }
1069 if (stepped > 0) {
1070 regs->trap = 0xd00 | (regs->trap & 1);
1071 printf("stepped to ");
1072 xmon_print_symbol(regs->nip, " ", "\n");
1073 ppc_inst_dump(regs->nip, 1, 0);
1074 return 0;
1075 }
1076 }
1077 }
1078 regs->msr |= MSR_SE;
1079 return 1;
1080}
Josh Boyercdd39042009-10-05 04:46:05 +00001081#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
1083static void bootcmds(void)
1084{
1085 int cmd;
1086
1087 cmd = inchar();
1088 if (cmd == 'r')
1089 ppc_md.restart(NULL);
1090 else if (cmd == 'h')
1091 ppc_md.halt();
1092 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001093 if (pm_power_off)
1094 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095}
1096
1097static int cpu_cmd(void)
1098{
1099#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001100 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
1103 if (!scanhex(&cpu)) {
1104 /* print cpus waiting or in xmon */
1105 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001106 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001107 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001108 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001109 if (cpu == last_cpu + 1) {
1110 last_cpu = cpu;
1111 } else {
1112 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001113 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001114 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001115 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 }
1118 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001119 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001120 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 printf("\n");
1122 return 0;
1123 }
1124 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001125 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 printf("cpu 0x%x isn't in xmon\n", cpu);
1127 return 0;
1128 }
1129 xmon_taken = 0;
1130 mb();
1131 xmon_owner = cpu;
1132 timeout = 10000000;
1133 while (!xmon_taken) {
1134 if (--timeout == 0) {
1135 if (test_and_set_bit(0, &xmon_taken))
1136 break;
1137 /* take control back */
1138 mb();
1139 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001140 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 return 0;
1142 }
1143 barrier();
1144 }
1145 return 1;
1146#else
1147 return 0;
1148#endif /* CONFIG_SMP */
1149}
1150
1151static unsigned short fcstab[256] = {
1152 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1153 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1154 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1155 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1156 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1157 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1158 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1159 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1160 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1161 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1162 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1163 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1164 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1165 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1166 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1167 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1168 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1169 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1170 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1171 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1172 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1173 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1174 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1175 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1176 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1177 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1178 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1179 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1180 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1181 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1182 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1183 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1184};
1185
1186#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1187
1188static void
1189csum(void)
1190{
1191 unsigned int i;
1192 unsigned short fcs;
1193 unsigned char v;
1194
1195 if (!scanhex(&adrs))
1196 return;
1197 if (!scanhex(&ncsum))
1198 return;
1199 fcs = 0xffff;
1200 for (i = 0; i < ncsum; ++i) {
1201 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001202 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 break;
1204 }
1205 fcs = FCS(fcs, v);
1206 }
1207 printf("%x\n", fcs);
1208}
1209
1210/*
1211 * Check if this is a suitable place to put a breakpoint.
1212 */
1213static long check_bp_loc(unsigned long addr)
1214{
1215 unsigned int instr;
1216
1217 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001218 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 printf("Breakpoints may only be placed at kernel addresses\n");
1220 return 0;
1221 }
1222 if (!mread(addr, &instr, sizeof(instr))) {
1223 printf("Can't read instruction at address %lx\n", addr);
1224 return 0;
1225 }
1226 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1227 printf("Breakpoints may not be placed on mtmsrd or rfid "
1228 "instructions\n");
1229 return 0;
1230 }
1231 return 1;
1232}
1233
Michael Ellermane3bc8042012-08-23 22:09:13 +00001234static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 "Breakpoint command usage:\n"
1236 "b show breakpoints\n"
1237 "b <addr> [cnt] set breakpoint at given instr addr\n"
1238 "bc clear all breakpoints\n"
1239 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301240 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 "bd <addr> [cnt] set hardware data breakpoint\n"
1242 "";
1243
1244static void
1245bpt_cmds(void)
1246{
1247 int cmd;
1248 unsigned long a;
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001249 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 struct bpt *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
1252 cmd = inchar();
1253 switch (cmd) {
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001254#ifndef CONFIG_PPC_8xx
1255 static const char badaddr[] = "Only kernel addresses are permitted for breakpoints\n";
1256 int mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 case 'd': /* bd - hardware data breakpoint */
1258 mode = 7;
1259 cmd = inchar();
1260 if (cmd == 'r')
1261 mode = 5;
1262 else if (cmd == 'w')
1263 mode = 6;
1264 else
1265 termch = cmd;
1266 dabr.address = 0;
1267 dabr.enabled = 0;
1268 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001269 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 printf(badaddr);
1271 break;
1272 }
Michael Neuling9422de32012-12-20 14:06:44 +00001273 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 dabr.enabled = mode | BP_DABR;
1275 }
1276 break;
1277
1278 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301279 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 printf("Hardware instruction breakpoint "
1281 "not supported on this cpu\n");
1282 break;
1283 }
1284 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001285 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 iabr = NULL;
1287 }
1288 if (!scanhex(&a))
1289 break;
1290 if (!check_bp_loc(a))
1291 break;
1292 bp = new_breakpoint(a);
1293 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001294 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 iabr = bp;
1296 }
1297 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001298#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
1300 case 'c':
1301 if (!scanhex(&a)) {
1302 /* clear all breakpoints */
1303 for (i = 0; i < NBPTS; ++i)
1304 bpts[i].enabled = 0;
1305 iabr = NULL;
1306 dabr.enabled = 0;
1307 printf("All breakpoints cleared\n");
1308 break;
1309 }
1310
1311 if (a <= NBPTS && a >= 1) {
1312 /* assume a breakpoint number */
1313 bp = &bpts[a-1]; /* bp nums are 1 based */
1314 } else {
1315 /* assume a breakpoint address */
1316 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001317 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001318 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 break;
1320 }
1321 }
1322
Michael Ellerman736256e2014-05-26 21:02:14 +10001323 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 xmon_print_symbol(bp->address, " ", ")\n");
1325 bp->enabled = 0;
1326 break;
1327
1328 default:
1329 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001330 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 if (cmd == '?') {
1332 printf(breakpoint_help_string);
1333 break;
1334 }
1335 termch = cmd;
1336 if (!scanhex(&a)) {
1337 /* print all breakpoints */
1338 printf(" type address\n");
1339 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001340 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 if (dabr.enabled & 1)
1342 printf("r");
1343 if (dabr.enabled & 2)
1344 printf("w");
1345 printf("]\n");
1346 }
1347 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1348 if (!bp->enabled)
1349 continue;
1350 printf("%2x %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001351 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 xmon_print_symbol(bp->address, " ", "\n");
1353 }
1354 break;
1355 }
1356
1357 if (!check_bp_loc(a))
1358 break;
1359 bp = new_breakpoint(a);
1360 if (bp != NULL)
1361 bp->enabled |= BP_TRAP;
1362 break;
1363 }
1364}
1365
1366/* Very cheap human name for vector lookup. */
1367static
1368const char *getvecname(unsigned long vec)
1369{
1370 char *ret;
1371
1372 switch (vec) {
1373 case 0x100: ret = "(System Reset)"; break;
1374 case 0x200: ret = "(Machine Check)"; break;
1375 case 0x300: ret = "(Data Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001376 case 0x380:
1377 if (radix_enabled())
1378 ret = "(Data Access Out of Range)";
1379 else
1380 ret = "(Data SLB Access)";
1381 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 case 0x400: ret = "(Instruction Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001383 case 0x480:
1384 if (radix_enabled())
1385 ret = "(Instruction Access Out of Range)";
1386 else
1387 ret = "(Instruction SLB Access)";
1388 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 case 0x500: ret = "(Hardware Interrupt)"; break;
1390 case 0x600: ret = "(Alignment)"; break;
1391 case 0x700: ret = "(Program Check)"; break;
1392 case 0x800: ret = "(FPU Unavailable)"; break;
1393 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001394 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1395 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 case 0xc00: ret = "(System Call)"; break;
1397 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001398 case 0xe40: ret = "(Emulation Assist)"; break;
1399 case 0xe60: ret = "(HMI)"; break;
1400 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 case 0xf00: ret = "(Performance Monitor)"; break;
1402 case 0xf20: ret = "(Altivec Unavailable)"; break;
1403 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001404 case 0x1500: ret = "(Denormalisation)"; break;
1405 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 default: ret = "";
1407 }
1408 return ret;
1409}
1410
1411static void get_function_bounds(unsigned long pc, unsigned long *startp,
1412 unsigned long *endp)
1413{
1414 unsigned long size, offset;
1415 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
1417 *startp = *endp = 0;
1418 if (pc == 0)
1419 return;
1420 if (setjmp(bus_error_jmp) == 0) {
1421 catch_memory_errors = 1;
1422 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001423 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 if (name != NULL) {
1425 *startp = pc - offset;
1426 *endp = pc - offset + size;
1427 }
1428 sync();
1429 }
1430 catch_memory_errors = 0;
1431}
1432
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001433#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1434#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1435
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436static void xmon_show_stack(unsigned long sp, unsigned long lr,
1437 unsigned long pc)
1438{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001439 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 unsigned long ip;
1441 unsigned long newsp;
1442 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 struct pt_regs regs;
1444
Michael Ellerman0104cd62012-10-09 04:20:36 +00001445 while (max_to_print--) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301446 if (!is_kernel_addr(sp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 if (sp != 0)
1448 printf("SP (%lx) is in userspace\n", sp);
1449 break;
1450 }
1451
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001452 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 || !mread(sp, &newsp, sizeof(unsigned long))) {
1454 printf("Couldn't read stack frame at %lx\n", sp);
1455 break;
1456 }
1457
1458 /*
1459 * For the first stack frame, try to work out if
1460 * LR and/or the saved LR value in the bottommost
1461 * stack frame are valid.
1462 */
1463 if ((pc | lr) != 0) {
1464 unsigned long fnstart, fnend;
1465 unsigned long nextip;
1466 int printip = 1;
1467
1468 get_function_bounds(pc, &fnstart, &fnend);
1469 nextip = 0;
1470 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001471 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 sizeof(unsigned long));
1473 if (lr == ip) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301474 if (!is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 || (fnstart <= lr && lr < fnend))
1476 printip = 0;
1477 } else if (lr == nextip) {
1478 printip = 0;
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301479 } else if (is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 && !(fnstart <= lr && lr < fnend)) {
1481 printf("[link register ] ");
1482 xmon_print_symbol(lr, " ", "\n");
1483 }
1484 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001485 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 xmon_print_symbol(ip, " ", " (unreliable)\n");
1487 }
1488 pc = lr = 0;
1489
1490 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001491 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 xmon_print_symbol(ip, " ", "\n");
1493 }
1494
1495 /* Look for "regshere" marker to see if this is
1496 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001497 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001498 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001499 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 != sizeof(regs)) {
1501 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001502 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 break;
1504 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001505 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 getvecname(TRAP(&regs)));
1507 pc = regs.nip;
1508 lr = regs.link;
1509 xmon_print_symbol(pc, " ", "\n");
1510 }
1511
1512 if (newsp == 0)
1513 break;
1514
1515 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517}
1518
1519static void backtrace(struct pt_regs *excp)
1520{
1521 unsigned long sp;
1522
1523 if (scanhex(&sp))
1524 xmon_show_stack(sp, 0, 0);
1525 else
1526 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1527 scannl();
1528}
1529
1530static void print_bug_trap(struct pt_regs *regs)
1531{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001532#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001533 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 unsigned long addr;
1535
1536 if (regs->msr & MSR_PR)
1537 return; /* not in kernel */
1538 addr = regs->nip; /* address of trap instruction */
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301539 if (!is_kernel_addr(addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 return;
1541 bug = find_bug(regs->nip);
1542 if (bug == NULL)
1543 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001544 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 return;
1546
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001547#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001548 printf("kernel BUG at %s:%u!\n",
1549 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001550#else
1551 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1552#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001553#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554}
1555
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001556static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557{
1558 unsigned long trap;
1559
1560#ifdef CONFIG_SMP
1561 printf("cpu 0x%x: ", smp_processor_id());
1562#endif /* CONFIG_SMP */
1563
1564 trap = TRAP(fp);
1565 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1566 printf(" pc: ");
1567 xmon_print_symbol(fp->nip, ": ", "\n");
1568
1569 printf(" lr: ", fp->link);
1570 xmon_print_symbol(fp->link, ": ", "\n");
1571
1572 printf(" sp: %lx\n", fp->gpr[1]);
1573 printf(" msr: %lx\n", fp->msr);
1574
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001575 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 printf(" dar: %lx\n", fp->dar);
1577 if (trap != 0x380)
1578 printf(" dsisr: %lx\n", fp->dsisr);
1579 }
1580
1581 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001582#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001583 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1584 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001585#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 if (current) {
1587 printf(" pid = %ld, comm = %s\n",
1588 current->pid, current->comm);
1589 }
1590
1591 if (trap == 0x700)
1592 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001593
1594 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595}
1596
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001597static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001599 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 unsigned long base;
1601 struct pt_regs regs;
1602
1603 if (scanhex(&base)) {
1604 if (setjmp(bus_error_jmp) == 0) {
1605 catch_memory_errors = 1;
1606 sync();
1607 regs = *(struct pt_regs *)base;
1608 sync();
1609 __delay(200);
1610 } else {
1611 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001612 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 base);
1614 return;
1615 }
1616 catch_memory_errors = 0;
1617 fp = &regs;
1618 }
1619
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001620#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 if (FULL_REGS(fp)) {
1622 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001623 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1625 } else {
1626 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001627 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1629 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001630#else
1631 for (n = 0; n < 32; ++n) {
1632 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1633 (n & 3) == 3? "\n": " ");
1634 if (n == 12 && !FULL_REGS(fp)) {
1635 printf("\n");
1636 break;
1637 }
1638 }
1639#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 printf("pc = ");
1641 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001642 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1643 printf("cfar= ");
1644 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 printf("lr = ");
1647 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001648 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1649 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001651 trap = TRAP(fp);
1652 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1653 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654}
1655
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001656static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657{
1658 int cmd;
1659 unsigned long nflush;
1660
1661 cmd = inchar();
1662 if (cmd != 'i')
1663 termch = cmd;
1664 scanhex((void *)&adrs);
1665 if (termch != '\n')
1666 termch = 0;
1667 nflush = 1;
1668 scanhex(&nflush);
1669 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1670 if (setjmp(bus_error_jmp) == 0) {
1671 catch_memory_errors = 1;
1672 sync();
1673
1674 if (cmd != 'i') {
1675 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1676 cflush((void *) adrs);
1677 } else {
1678 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1679 cinval((void *) adrs);
1680 }
1681 sync();
1682 /* wait a little while to see if we get a machine check */
1683 __delay(200);
1684 }
1685 catch_memory_errors = 0;
1686}
1687
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001688extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1689extern void xmon_mtspr(int spr, unsigned long value);
1690
1691static int
1692read_spr(int n, unsigned long *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 unsigned long ret = -1UL;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001695 int ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001698 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 sync();
1700
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001701 ret = xmon_mfspr(n, *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
1703 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001704 *vp = ret;
1705 ok = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001707 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001709 return ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710}
1711
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001712static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713write_spr(int n, unsigned long val)
1714{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001716 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 sync();
1718
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001719 xmon_mtspr(n, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720
1721 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001722 } else {
1723 printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001725 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726}
1727
Michael Ellerman18461932016-07-07 22:54:29 +10001728static void dump_206_sprs(void)
1729{
1730#ifdef CONFIG_PPC64
1731 if (!cpu_has_feature(CPU_FTR_ARCH_206))
1732 return;
1733
1734 /* Actually some of these pre-date 2.06, but whatevs */
1735
1736 printf("srr0 = %.16x srr1 = %.16x dsisr = %.8x\n",
1737 mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
1738 printf("dscr = %.16x ppr = %.16x pir = %.8x\n",
1739 mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
1740
1741 if (!(mfmsr() & MSR_HV))
1742 return;
1743
1744 printf("sdr1 = %.16x hdar = %.16x hdsisr = %.8x\n",
1745 mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
1746 printf("hsrr0 = %.16x hsrr1 = %.16x hdec = %.8x\n",
1747 mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
1748 printf("lpcr = %.16x pcr = %.16x lpidr = %.8x\n",
1749 mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
1750 printf("hsprg0 = %.16x hsprg1 = %.16x\n",
1751 mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1));
1752 printf("dabr = %.16x dabrx = %.16x\n",
1753 mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
1754#endif
1755}
1756
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001757static void dump_207_sprs(void)
1758{
1759#ifdef CONFIG_PPC64
1760 unsigned long msr;
1761
1762 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
1763 return;
1764
1765 printf("dpdes = %.16x tir = %.16x cir = %.8x\n",
1766 mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
1767
1768 printf("fscr = %.16x tar = %.16x pspb = %.8x\n",
1769 mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
1770
1771 msr = mfmsr();
1772 if (msr & MSR_TM) {
1773 /* Only if TM has been enabled in the kernel */
1774 printf("tfhar = %.16x tfiar = %.16x texasr = %.16x\n",
1775 mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
1776 mfspr(SPRN_TEXASR));
1777 }
1778
1779 printf("mmcr0 = %.16x mmcr1 = %.16x mmcr2 = %.16x\n",
1780 mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
1781 printf("pmc1 = %.8x pmc2 = %.8x pmc3 = %.8x pmc4 = %.8x\n",
1782 mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
1783 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
1784 printf("mmcra = %.16x siar = %.16x pmc5 = %.8x\n",
1785 mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
1786 printf("sdar = %.16x sier = %.16x pmc6 = %.8x\n",
1787 mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
1788 printf("ebbhr = %.16x ebbrr = %.16x bescr = %.16x\n",
1789 mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
1790
1791 if (!(msr & MSR_HV))
1792 return;
1793
1794 printf("hfscr = %.16x dhdes = %.16x rpr = %.16x\n",
1795 mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
1796 printf("dawr = %.16x dawrx = %.16x ciabr = %.16x\n",
1797 mfspr(SPRN_DAWR), mfspr(SPRN_DAWRX), mfspr(SPRN_CIABR));
1798#endif
1799}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001801static void dump_one_spr(int spr, bool show_unimplemented)
1802{
1803 unsigned long val;
1804
1805 val = 0xdeadbeef;
1806 if (!read_spr(spr, &val)) {
1807 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1808 return;
1809 }
1810
1811 if (val == 0xdeadbeef) {
1812 /* Looks like read was a nop, confirm */
1813 val = 0x0badcafe;
1814 if (!read_spr(spr, &val)) {
1815 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1816 return;
1817 }
1818
1819 if (val == 0x0badcafe) {
1820 if (show_unimplemented)
1821 printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
1822 return;
1823 }
1824 }
1825
1826 printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
1827}
1828
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001829static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830{
Michael Ellerman13629da2016-07-07 22:54:27 +10001831 static unsigned long regno;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 int cmd;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001833 int spr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834
1835 cmd = skipbl();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001836
1837 switch (cmd) {
1838 case '\n': {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001839 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 asm("mr %0,1" : "=r" (sp) :);
1841 asm("mr %0,2" : "=r" (toc) :);
1842
Michael Ellerman56346ad2016-07-07 22:54:28 +10001843 printf("msr = "REG" sprg0 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001844 mfmsr(), mfspr(SPRN_SPRG0));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001845 printf("pvr = "REG" sprg1 = "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001846 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001847 printf("dec = "REG" sprg2 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001848 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001849 printf("sp = "REG" sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
1850 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
1851
Michael Ellerman18461932016-07-07 22:54:29 +10001852 dump_206_sprs();
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001853 dump_207_sprs();
Michael Ellerman18461932016-07-07 22:54:29 +10001854
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 return;
1856 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001857 case 'w': {
1858 unsigned long val;
1859 scanhex(&regno);
1860 val = 0;
1861 read_spr(regno, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 scanhex(&val);
1863 write_spr(regno, val);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001864 dump_one_spr(regno, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001867 case 'r':
1868 scanhex(&regno);
1869 dump_one_spr(regno, true);
1870 break;
1871 case 'a':
1872 /* dump ALL SPRs */
1873 for (spr = 1; spr < 1024; ++spr)
1874 dump_one_spr(spr, false);
1875 break;
1876 }
1877
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 scannl();
1879}
1880
1881/*
1882 * Stuff for reading and writing memory safely
1883 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001884static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885mread(unsigned long adrs, void *buf, int size)
1886{
1887 volatile int n;
1888 char *p, *q;
1889
1890 n = 0;
1891 if (setjmp(bus_error_jmp) == 0) {
1892 catch_memory_errors = 1;
1893 sync();
1894 p = (char *)adrs;
1895 q = (char *)buf;
1896 switch (size) {
1897 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001898 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 break;
1900 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001901 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 break;
1903 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001904 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 break;
1906 default:
1907 for( ; n < size; ++n) {
1908 *q++ = *p++;
1909 sync();
1910 }
1911 }
1912 sync();
1913 /* wait a little while to see if we get a machine check */
1914 __delay(200);
1915 n = size;
1916 }
1917 catch_memory_errors = 0;
1918 return n;
1919}
1920
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001921static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922mwrite(unsigned long adrs, void *buf, int size)
1923{
1924 volatile int n;
1925 char *p, *q;
1926
1927 n = 0;
1928 if (setjmp(bus_error_jmp) == 0) {
1929 catch_memory_errors = 1;
1930 sync();
1931 p = (char *) adrs;
1932 q = (char *) buf;
1933 switch (size) {
1934 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001935 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 break;
1937 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001938 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 break;
1940 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001941 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 break;
1943 default:
1944 for ( ; n < size; ++n) {
1945 *p++ = *q++;
1946 sync();
1947 }
1948 }
1949 sync();
1950 /* wait a little while to see if we get a machine check */
1951 __delay(200);
1952 n = size;
1953 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10001954 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 }
1956 catch_memory_errors = 0;
1957 return n;
1958}
1959
1960static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001961static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962static char *fault_chars[] = { "--", "**", "##" };
1963
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001964static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001966 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 switch (TRAP(regs)) {
1968 case 0x200:
1969 fault_type = 0;
1970 break;
1971 case 0x300:
1972 case 0x380:
1973 fault_type = 1;
1974 break;
1975 default:
1976 fault_type = 2;
1977 }
1978
1979 longjmp(bus_error_jmp, 1);
1980
1981 return 0;
1982}
1983
1984#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1985
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001986static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987byterev(unsigned char *val, int size)
1988{
1989 int t;
1990
1991 switch (size) {
1992 case 2:
1993 SWAP(val[0], val[1], t);
1994 break;
1995 case 4:
1996 SWAP(val[0], val[3], t);
1997 SWAP(val[1], val[2], t);
1998 break;
1999 case 8: /* is there really any use for this? */
2000 SWAP(val[0], val[7], t);
2001 SWAP(val[1], val[6], t);
2002 SWAP(val[2], val[5], t);
2003 SWAP(val[3], val[4], t);
2004 break;
2005 }
2006}
2007
2008static int brev;
2009static int mnoread;
2010
Michael Ellermane3bc8042012-08-23 22:09:13 +00002011static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 "Memory examine command usage:\n"
2013 "m [addr] [flags] examine/change memory\n"
2014 " addr is optional. will start where left off.\n"
2015 " flags may include chars from this set:\n"
2016 " b modify by bytes (default)\n"
2017 " w modify by words (2 byte)\n"
2018 " l modify by longs (4 byte)\n"
2019 " d modify by doubleword (8 byte)\n"
2020 " r toggle reverse byte order mode\n"
2021 " n do not read memory (for i/o spaces)\n"
2022 " . ok to read (default)\n"
2023 "NOTE: flags are saved as defaults\n"
2024 "";
2025
Michael Ellermane3bc8042012-08-23 22:09:13 +00002026static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 "Memory examine subcommands:\n"
2028 " hexval write this val to current location\n"
2029 " 'string' write chars from string to this location\n"
2030 " ' increment address\n"
2031 " ^ decrement address\n"
2032 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
2033 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
2034 " ` clear no-read flag\n"
2035 " ; stay at this addr\n"
2036 " v change to byte mode\n"
2037 " w change to word (2 byte) mode\n"
2038 " l change to long (4 byte) mode\n"
2039 " u change to doubleword (8 byte) mode\n"
2040 " m addr change current addr\n"
2041 " n toggle no-read flag\n"
2042 " r toggle byte reverse flag\n"
2043 " < count back up count bytes\n"
2044 " > count skip forward count bytes\n"
2045 " x exit this mode\n"
2046 "";
2047
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002048static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049memex(void)
2050{
2051 int cmd, inc, i, nslash;
2052 unsigned long n;
2053 unsigned char val[16];
2054
2055 scanhex((void *)&adrs);
2056 cmd = skipbl();
2057 if (cmd == '?') {
2058 printf(memex_help_string);
2059 return;
2060 } else {
2061 termch = cmd;
2062 }
2063 last_cmd = "m\n";
2064 while ((cmd = skipbl()) != '\n') {
2065 switch( cmd ){
2066 case 'b': size = 1; break;
2067 case 'w': size = 2; break;
2068 case 'l': size = 4; break;
2069 case 'd': size = 8; break;
2070 case 'r': brev = !brev; break;
2071 case 'n': mnoread = 1; break;
2072 case '.': mnoread = 0; break;
2073 }
2074 }
2075 if( size <= 0 )
2076 size = 1;
2077 else if( size > 8 )
2078 size = 8;
2079 for(;;){
2080 if (!mnoread)
2081 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002082 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 if (!mnoread) {
2084 if (brev)
2085 byterev(val, size);
2086 putchar(' ');
2087 for (i = 0; i < n; ++i)
2088 printf("%.2x", val[i]);
2089 for (; i < size; ++i)
2090 printf("%s", fault_chars[fault_type]);
2091 }
2092 putchar(' ');
2093 inc = size;
2094 nslash = 0;
2095 for(;;){
2096 if( scanhex(&n) ){
2097 for (i = 0; i < size; ++i)
2098 val[i] = n >> (i * 8);
2099 if (!brev)
2100 byterev(val, size);
2101 mwrite(adrs, val, size);
2102 inc = size;
2103 }
2104 cmd = skipbl();
2105 if (cmd == '\n')
2106 break;
2107 inc = 0;
2108 switch (cmd) {
2109 case '\'':
2110 for(;;){
2111 n = inchar();
2112 if( n == '\\' )
2113 n = bsesc();
2114 else if( n == '\'' )
2115 break;
2116 for (i = 0; i < size; ++i)
2117 val[i] = n >> (i * 8);
2118 if (!brev)
2119 byterev(val, size);
2120 mwrite(adrs, val, size);
2121 adrs += size;
2122 }
2123 adrs -= size;
2124 inc = size;
2125 break;
2126 case ',':
2127 adrs += size;
2128 break;
2129 case '.':
2130 mnoread = 0;
2131 break;
2132 case ';':
2133 break;
2134 case 'x':
2135 case EOF:
2136 scannl();
2137 return;
2138 case 'b':
2139 case 'v':
2140 size = 1;
2141 break;
2142 case 'w':
2143 size = 2;
2144 break;
2145 case 'l':
2146 size = 4;
2147 break;
2148 case 'u':
2149 size = 8;
2150 break;
2151 case '^':
2152 adrs -= size;
2153 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 case '/':
2155 if (nslash > 0)
2156 adrs -= 1 << nslash;
2157 else
2158 nslash = 0;
2159 nslash += 4;
2160 adrs += 1 << nslash;
2161 break;
2162 case '\\':
2163 if (nslash < 0)
2164 adrs += 1 << -nslash;
2165 else
2166 nslash = 0;
2167 nslash -= 4;
2168 adrs -= 1 << -nslash;
2169 break;
2170 case 'm':
2171 scanhex((void *)&adrs);
2172 break;
2173 case 'n':
2174 mnoread = 1;
2175 break;
2176 case 'r':
2177 brev = !brev;
2178 break;
2179 case '<':
2180 n = size;
2181 scanhex(&n);
2182 adrs -= n;
2183 break;
2184 case '>':
2185 n = size;
2186 scanhex(&n);
2187 adrs += n;
2188 break;
2189 case '?':
2190 printf(memex_subcmd_help_string);
2191 break;
2192 }
2193 }
2194 adrs += inc;
2195 }
2196}
2197
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002198static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199bsesc(void)
2200{
2201 int c;
2202
2203 c = inchar();
2204 switch( c ){
2205 case 'n': c = '\n'; break;
2206 case 'r': c = '\r'; break;
2207 case 'b': c = '\b'; break;
2208 case 't': c = '\t'; break;
2209 }
2210 return c;
2211}
2212
Olaf Hering7e5b5932006-03-08 20:40:28 +01002213static void xmon_rawdump (unsigned long adrs, long ndump)
2214{
2215 long n, m, r, nr;
2216 unsigned char temp[16];
2217
2218 for (n = ndump; n > 0;) {
2219 r = n < 16? n: 16;
2220 nr = mread(adrs, temp, r);
2221 adrs += nr;
2222 for (m = 0; m < r; ++m) {
2223 if (m < nr)
2224 printf("%.2x", temp[m]);
2225 else
2226 printf("%s", fault_chars[fault_type]);
2227 }
2228 n -= r;
2229 if (nr < r)
2230 break;
2231 }
2232 printf("\n");
2233}
2234
Breno Leitao4125d012017-08-02 17:14:05 -03002235static void dump_tracing(void)
2236{
2237 int c;
2238
2239 c = inchar();
2240 if (c == 'c')
2241 ftrace_dump(DUMP_ORIG);
2242 else
2243 ftrace_dump(DUMP_ALL);
2244
2245 tracing_on();
2246}
2247
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002248#ifdef CONFIG_PPC64
2249static void dump_one_paca(int cpu)
2250{
2251 struct paca_struct *p;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002252#ifdef CONFIG_PPC_STD_MMU_64
2253 int i = 0;
2254#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002255
2256 if (setjmp(bus_error_jmp) != 0) {
2257 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2258 return;
2259 }
2260
2261 catch_memory_errors = 1;
2262 sync();
2263
2264 p = &paca[cpu];
2265
2266 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2267
Michael Ellermanad987fc2015-10-14 16:58:36 +11002268 printf(" %-*s = %s\n", 20, "possible", cpu_possible(cpu) ? "yes" : "no");
2269 printf(" %-*s = %s\n", 20, "present", cpu_present(cpu) ? "yes" : "no");
2270 printf(" %-*s = %s\n", 20, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002271
2272#define DUMP(paca, name, format) \
Michael Ellermanad987fc2015-10-14 16:58:36 +11002273 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 20, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002274 offsetof(struct paca_struct, name));
2275
2276 DUMP(p, lock_token, "x");
2277 DUMP(p, paca_index, "x");
2278 DUMP(p, kernel_toc, "lx");
2279 DUMP(p, kernelbase, "lx");
2280 DUMP(p, kernel_msr, "lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002281 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302282#ifdef CONFIG_PPC_BOOK3S_64
Nicholas Pigginb1ee8a32016-12-20 04:30:06 +10002283 DUMP(p, nmi_emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302284 DUMP(p, mc_emergency_sp, "p");
Nicholas Pigginc4f3b522016-12-20 04:30:05 +10002285 DUMP(p, in_nmi, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302286 DUMP(p, in_mce, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002287 DUMP(p, hmi_event_available, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302288#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002289 DUMP(p, data_offset, "lx");
2290 DUMP(p, hw_cpu_id, "x");
2291 DUMP(p, cpu_start, "x");
2292 DUMP(p, kexec_state, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002293#ifdef CONFIG_PPC_STD_MMU_64
2294 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2295 u64 esid, vsid;
2296
2297 if (!p->slb_shadow_ptr)
2298 continue;
2299
2300 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2301 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
2302
2303 if (esid || vsid) {
2304 printf(" slb_shadow[%d]: = 0x%016lx 0x%016lx\n",
2305 i, esid, vsid);
2306 }
2307 }
2308 DUMP(p, vmalloc_sllp, "x");
2309 DUMP(p, slb_cache_ptr, "x");
2310 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2311 printf(" slb_cache[%d]: = 0x%016lx\n", i, p->slb_cache[i]);
2312#endif
2313 DUMP(p, dscr_default, "llx");
2314#ifdef CONFIG_PPC_BOOK3E
2315 DUMP(p, pgd, "p");
2316 DUMP(p, kernel_pgd, "p");
2317 DUMP(p, tcd_ptr, "p");
2318 DUMP(p, mc_kstack, "p");
2319 DUMP(p, crit_kstack, "p");
2320 DUMP(p, dbg_kstack, "p");
2321#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002322 DUMP(p, __current, "p");
2323 DUMP(p, kstack, "lx");
2324 DUMP(p, stab_rr, "lx");
2325 DUMP(p, saved_r1, "lx");
2326 DUMP(p, trap_save, "x");
2327 DUMP(p, soft_enabled, "x");
2328 DUMP(p, irq_happened, "x");
2329 DUMP(p, io_sync, "x");
2330 DUMP(p, irq_work_pending, "x");
2331 DUMP(p, nap_state_lost, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002332 DUMP(p, sprg_vdso, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002333
Michael Ellermanad987fc2015-10-14 16:58:36 +11002334#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
2335 DUMP(p, tm_scratch, "llx");
2336#endif
2337
2338#ifdef CONFIG_PPC_POWERNV
2339 DUMP(p, core_idle_state_ptr, "p");
2340 DUMP(p, thread_idle_state, "x");
2341 DUMP(p, thread_mask, "x");
2342 DUMP(p, subcore_sibling_mask, "x");
2343#endif
2344
Frederic Weisbecker8c8b73c2017-01-05 18:11:45 +01002345 DUMP(p, accounting.utime, "llx");
2346 DUMP(p, accounting.stime, "llx");
2347 DUMP(p, accounting.utime_scaled, "llx");
Christophe Leroyc223c902016-05-17 08:33:46 +02002348 DUMP(p, accounting.starttime, "llx");
2349 DUMP(p, accounting.starttime_user, "llx");
2350 DUMP(p, accounting.startspurr, "llx");
2351 DUMP(p, accounting.utime_sspurr, "llx");
Frederic Weisbeckerf828c3d2017-01-05 18:11:46 +01002352 DUMP(p, accounting.steal_time, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002353#undef DUMP
2354
2355 catch_memory_errors = 0;
2356 sync();
2357}
2358
2359static void dump_all_pacas(void)
2360{
2361 int cpu;
2362
2363 if (num_possible_cpus() == 0) {
2364 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2365 return;
2366 }
2367
2368 for_each_possible_cpu(cpu)
2369 dump_one_paca(cpu);
2370}
2371
2372static void dump_pacas(void)
2373{
2374 unsigned long num;
2375 int c;
2376
2377 c = inchar();
2378 if (c == 'a') {
2379 dump_all_pacas();
2380 return;
2381 }
2382
2383 termch = c; /* Put c back, it wasn't 'a' */
2384
2385 if (scanhex(&num))
2386 dump_one_paca(num);
2387 else
2388 dump_one_paca(xmon_owner);
2389}
2390#endif
2391
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002392#ifdef CONFIG_PPC_POWERNV
2393static void dump_one_xive(int cpu)
2394{
2395 unsigned int hwid = get_hard_smp_processor_id(cpu);
2396
2397 opal_xive_dump(XIVE_DUMP_TM_HYP, hwid);
2398 opal_xive_dump(XIVE_DUMP_TM_POOL, hwid);
2399 opal_xive_dump(XIVE_DUMP_TM_OS, hwid);
2400 opal_xive_dump(XIVE_DUMP_TM_USER, hwid);
2401 opal_xive_dump(XIVE_DUMP_VP, hwid);
2402 opal_xive_dump(XIVE_DUMP_EMU_STATE, hwid);
2403
2404 if (setjmp(bus_error_jmp) != 0) {
2405 catch_memory_errors = 0;
2406 printf("*** Error dumping xive on cpu %d\n", cpu);
2407 return;
2408 }
2409
2410 catch_memory_errors = 1;
2411 sync();
2412 xmon_xive_do_dump(cpu);
2413 sync();
2414 __delay(200);
2415 catch_memory_errors = 0;
2416}
2417
2418static void dump_all_xives(void)
2419{
2420 int cpu;
2421
2422 if (num_possible_cpus() == 0) {
2423 printf("No possible cpus, use 'dx #' to dump individual cpus\n");
2424 return;
2425 }
2426
2427 for_each_possible_cpu(cpu)
2428 dump_one_xive(cpu);
2429}
2430
2431static void dump_one_xive_irq(u32 num)
2432{
2433 s64 rc;
2434 __be64 vp;
2435 u8 prio;
2436 __be32 lirq;
2437
2438 rc = opal_xive_get_irq_config(num, &vp, &prio, &lirq);
2439 xmon_printf("IRQ 0x%x config: vp=0x%llx prio=%d lirq=0x%x (rc=%lld)\n",
2440 num, be64_to_cpu(vp), prio, be32_to_cpu(lirq), rc);
2441}
2442
2443static void dump_xives(void)
2444{
2445 unsigned long num;
2446 int c;
2447
2448 c = inchar();
2449 if (c == 'a') {
2450 dump_all_xives();
2451 return;
2452 } else if (c == 'i') {
2453 if (scanhex(&num))
2454 dump_one_xive_irq(num);
2455 return;
2456 }
2457
2458 termch = c; /* Put c back, it wasn't 'a' */
2459
2460 if (scanhex(&num))
2461 dump_one_xive(num);
2462 else
2463 dump_one_xive(xmon_owner);
2464}
2465#endif /* CONFIG_PPC_POWERNV */
2466
Douglas Miller5e48dc02017-02-07 07:40:44 -06002467static void dump_by_size(unsigned long addr, long count, int size)
2468{
2469 unsigned char temp[16];
2470 int i, j;
2471 u64 val;
2472
2473 count = ALIGN(count, 16);
2474
2475 for (i = 0; i < count; i += 16, addr += 16) {
2476 printf(REG, addr);
2477
2478 if (mread(addr, temp, 16) != 16) {
2479 printf("\nFaulted reading %d bytes from 0x"REG"\n", 16, addr);
2480 return;
2481 }
2482
2483 for (j = 0; j < 16; j += size) {
2484 putchar(' ');
2485 switch (size) {
2486 case 1: val = temp[j]; break;
2487 case 2: val = *(u16 *)&temp[j]; break;
2488 case 4: val = *(u32 *)&temp[j]; break;
2489 case 8: val = *(u64 *)&temp[j]; break;
2490 default: val = 0;
2491 }
2492
2493 printf("%0*lx", size * 2, val);
2494 }
2495 printf("\n");
2496 }
2497}
2498
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002499static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500dump(void)
2501{
Douglas Miller5e48dc02017-02-07 07:40:44 -06002502 static char last[] = { "d?\n" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 int c;
2504
2505 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002506
2507#ifdef CONFIG_PPC64
2508 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002509 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002510 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002511 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002512 return;
2513 }
2514#endif
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002515#ifdef CONFIG_PPC_POWERNV
2516 if (c == 'x') {
2517 xmon_start_pagination();
2518 dump_xives();
2519 xmon_end_pagination();
2520 return;
2521 }
2522#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002523
Breno Leitao4125d012017-08-02 17:14:05 -03002524 if (c == 't') {
2525 dump_tracing();
2526 return;
2527 }
2528
Douglas Miller5e48dc02017-02-07 07:40:44 -06002529 if (c == '\n')
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 termch = c;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002531
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 scanhex((void *)&adrs);
2533 if (termch != '\n')
2534 termch = 0;
2535 if (c == 'i') {
2536 scanhex(&nidump);
2537 if (nidump == 0)
2538 nidump = 16;
2539 else if (nidump > MAX_DUMP)
2540 nidump = MAX_DUMP;
2541 adrs += ppc_inst_dump(adrs, nidump, 1);
2542 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002543 } else if (c == 'l') {
2544 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002545 } else if (c == 'o') {
2546 dump_opal_msglog();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002547 } else if (c == 'r') {
2548 scanhex(&ndump);
2549 if (ndump == 0)
2550 ndump = 64;
2551 xmon_rawdump(adrs, ndump);
2552 adrs += ndump;
2553 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 } else {
2555 scanhex(&ndump);
2556 if (ndump == 0)
2557 ndump = 64;
2558 else if (ndump > MAX_DUMP)
2559 ndump = MAX_DUMP;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002560
2561 switch (c) {
2562 case '8':
2563 case '4':
2564 case '2':
2565 case '1':
2566 ndump = ALIGN(ndump, 16);
2567 dump_by_size(adrs, ndump, c - '0');
2568 last[1] = c;
2569 last_cmd = last;
2570 break;
2571 default:
2572 prdump(adrs, ndump);
2573 last_cmd = "d\n";
2574 }
2575
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 adrs += ndump;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 }
2578}
2579
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002580static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581prdump(unsigned long adrs, long ndump)
2582{
2583 long n, m, c, r, nr;
2584 unsigned char temp[16];
2585
2586 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002587 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 putchar(' ');
2589 r = n < 16? n: 16;
2590 nr = mread(adrs, temp, r);
2591 adrs += nr;
2592 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002593 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002594 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 if (m < nr)
2596 printf("%.2x", temp[m]);
2597 else
2598 printf("%s", fault_chars[fault_type]);
2599 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002600 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002601 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002602 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002604 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 printf(" |");
2606 for (m = 0; m < r; ++m) {
2607 if (m < nr) {
2608 c = temp[m];
2609 putchar(' ' <= c && c <= '~'? c: '.');
2610 } else
2611 putchar(' ');
2612 }
2613 n -= r;
2614 for (; m < 16; ++m)
2615 putchar(' ');
2616 printf("|\n");
2617 if (nr < r)
2618 break;
2619 }
2620}
2621
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002622typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2623
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002624static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002625generic_inst_dump(unsigned long adr, long count, int praddr,
2626 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627{
2628 int nr, dotted;
2629 unsigned long first_adr;
2630 unsigned long inst, last_inst = 0;
2631 unsigned char val[4];
2632
2633 dotted = 0;
2634 for (first_adr = adr; count > 0; --count, adr += 4) {
2635 nr = mread(adr, val, 4);
2636 if (nr == 0) {
2637 if (praddr) {
2638 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002639 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 }
2641 break;
2642 }
2643 inst = GETWORD(val);
2644 if (adr > first_adr && inst == last_inst) {
2645 if (!dotted) {
2646 printf(" ...\n");
2647 dotted = 1;
2648 }
2649 continue;
2650 }
2651 dotted = 0;
2652 last_inst = inst;
2653 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002654 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002656 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 printf("\n");
2658 }
2659 return adr - first_adr;
2660}
2661
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002662static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002663ppc_inst_dump(unsigned long adr, long count, int praddr)
2664{
2665 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2666}
2667
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668void
2669print_address(unsigned long addr)
2670{
2671 xmon_print_symbol(addr, "\t# ", "");
2672}
2673
Vinay Sridharf312deb2009-05-14 23:13:07 +00002674void
2675dump_log_buf(void)
2676{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002677 struct kmsg_dumper dumper = { .active = 1 };
2678 unsigned char buf[128];
2679 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002680
Michael Ellermane3bc8042012-08-23 22:09:13 +00002681 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002682 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002683 return;
2684 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002685
Michael Ellermane3bc8042012-08-23 22:09:13 +00002686 catch_memory_errors = 1;
2687 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002688
Michael Ellermanca5dd392012-08-23 22:09:12 +00002689 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002690 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002691 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2692 buf[len] = '\0';
2693 printf("%s", buf);
2694 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002695 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002696
Michael Ellermane3bc8042012-08-23 22:09:13 +00002697 sync();
2698 /* wait a little while to see if we get a machine check */
2699 __delay(200);
2700 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002701}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002703#ifdef CONFIG_PPC_POWERNV
2704static void dump_opal_msglog(void)
2705{
2706 unsigned char buf[128];
2707 ssize_t res;
2708 loff_t pos = 0;
2709
2710 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2711 printf("Machine is not running OPAL firmware.\n");
2712 return;
2713 }
2714
2715 if (setjmp(bus_error_jmp) != 0) {
2716 printf("Error dumping OPAL msglog!\n");
2717 return;
2718 }
2719
2720 catch_memory_errors = 1;
2721 sync();
2722
2723 xmon_start_pagination();
2724 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2725 if (res < 0) {
2726 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2727 break;
2728 }
2729 buf[res] = '\0';
2730 printf("%s", buf);
2731 pos += res;
2732 }
2733 xmon_end_pagination();
2734
2735 sync();
2736 /* wait a little while to see if we get a machine check */
2737 __delay(200);
2738 catch_memory_errors = 0;
2739}
2740#endif
2741
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742/*
2743 * Memory operations - move, set, print differences
2744 */
2745static unsigned long mdest; /* destination address */
2746static unsigned long msrc; /* source address */
2747static unsigned long mval; /* byte value to set memory to */
2748static unsigned long mcount; /* # bytes to affect */
2749static unsigned long mdiffs; /* max # differences to print */
2750
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002751static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752memops(int cmd)
2753{
2754 scanhex((void *)&mdest);
2755 if( termch != '\n' )
2756 termch = 0;
2757 scanhex((void *)(cmd == 's'? &mval: &msrc));
2758 if( termch != '\n' )
2759 termch = 0;
2760 scanhex((void *)&mcount);
2761 switch( cmd ){
2762 case 'm':
2763 memmove((void *)mdest, (void *)msrc, mcount);
2764 break;
2765 case 's':
2766 memset((void *)mdest, mval, mcount);
2767 break;
2768 case 'd':
2769 if( termch != '\n' )
2770 termch = 0;
2771 scanhex((void *)&mdiffs);
2772 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2773 break;
2774 }
2775}
2776
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002777static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2779{
2780 unsigned n, prt;
2781
2782 prt = 0;
2783 for( n = nb; n > 0; --n )
2784 if( *p1++ != *p2++ )
2785 if( ++prt <= maxpr )
2786 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2787 p1[-1], p2 - 1, p2[-1]);
2788 if( prt > maxpr )
2789 printf("Total of %d differences\n", prt);
2790}
2791
2792static unsigned mend;
2793static unsigned mask;
2794
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002795static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796memlocate(void)
2797{
2798 unsigned a, n;
2799 unsigned char val[4];
2800
2801 last_cmd = "ml";
2802 scanhex((void *)&mdest);
2803 if (termch != '\n') {
2804 termch = 0;
2805 scanhex((void *)&mend);
2806 if (termch != '\n') {
2807 termch = 0;
2808 scanhex((void *)&mval);
2809 mask = ~0;
2810 if (termch != '\n') termch = 0;
2811 scanhex((void *)&mask);
2812 }
2813 }
2814 n = 0;
2815 for (a = mdest; a < mend; a += 4) {
2816 if (mread(a, val, 4) == 4
2817 && ((GETWORD(val) ^ mval) & mask) == 0) {
2818 printf("%.16x: %.16x\n", a, GETWORD(val));
2819 if (++n >= 10)
2820 break;
2821 }
2822 }
2823}
2824
2825static unsigned long mskip = 0x1000;
2826static unsigned long mlim = 0xffffffff;
2827
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002828static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829memzcan(void)
2830{
2831 unsigned char v;
2832 unsigned a;
2833 int ok, ook;
2834
2835 scanhex(&mdest);
2836 if (termch != '\n') termch = 0;
2837 scanhex(&mskip);
2838 if (termch != '\n') termch = 0;
2839 scanhex(&mlim);
2840 ook = 0;
2841 for (a = mdest; a < mlim; a += mskip) {
2842 ok = mread(a, &v, 1);
2843 if (ok && !ook) {
2844 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 } else if (!ok && ook)
2846 printf("%.8x\n", a - mskip);
2847 ook = ok;
2848 if (a + mskip < a)
2849 break;
2850 }
2851 if (ook)
2852 printf("%.8x\n", a - mskip);
2853}
2854
Douglas Miller6dfb5402015-11-23 09:01:15 -06002855static void show_task(struct task_struct *tsk)
2856{
2857 char state;
2858
2859 /*
2860 * Cloned from kdb_task_state_char(), which is not entirely
2861 * appropriate for calling from xmon. This could be moved
2862 * to a common, generic, routine used by both.
2863 */
2864 state = (tsk->state == 0) ? 'R' :
2865 (tsk->state < 0) ? 'U' :
2866 (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
2867 (tsk->state & TASK_STOPPED) ? 'T' :
2868 (tsk->state & TASK_TRACED) ? 'C' :
2869 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
2870 (tsk->exit_state & EXIT_DEAD) ? 'E' :
2871 (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
2872
2873 printf("%p %016lx %6d %6d %c %2d %s\n", tsk,
2874 tsk->thread.ksp,
2875 tsk->pid, tsk->parent->pid,
2876 state, task_thread_info(tsk)->cpu,
2877 tsk->comm);
2878}
2879
2880static void show_tasks(void)
2881{
2882 unsigned long tskv;
2883 struct task_struct *tsk = NULL;
2884
2885 printf(" task_struct ->thread.ksp PID PPID S P CMD\n");
2886
2887 if (scanhex(&tskv))
2888 tsk = (struct task_struct *)tskv;
2889
2890 if (setjmp(bus_error_jmp) != 0) {
2891 catch_memory_errors = 0;
2892 printf("*** Error dumping task %p\n", tsk);
2893 return;
2894 }
2895
2896 catch_memory_errors = 1;
2897 sync();
2898
2899 if (tsk)
2900 show_task(tsk);
2901 else
2902 for_each_process(tsk)
2903 show_task(tsk);
2904
2905 sync();
2906 __delay(200);
2907 catch_memory_errors = 0;
2908}
2909
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002910static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002911{
2912 unsigned long args[8];
2913 unsigned long ret;
2914 int i;
2915 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2916 unsigned long, unsigned long, unsigned long,
2917 unsigned long, unsigned long, unsigned long);
2918 callfunc_t func;
2919
2920 if (!scanhex(&adrs))
2921 return;
2922 if (termch != '\n')
2923 termch = 0;
2924 for (i = 0; i < 8; ++i)
2925 args[i] = 0;
2926 for (i = 0; i < 8; ++i) {
2927 if (!scanhex(&args[i]) || termch == '\n')
2928 break;
2929 termch = 0;
2930 }
2931 func = (callfunc_t) adrs;
2932 ret = 0;
2933 if (setjmp(bus_error_jmp) == 0) {
2934 catch_memory_errors = 1;
2935 sync();
2936 ret = func(args[0], args[1], args[2], args[3],
2937 args[4], args[5], args[6], args[7]);
2938 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10002939 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002940 } else {
2941 printf("*** %x exception occurred\n", fault_except);
2942 }
2943 catch_memory_errors = 0;
2944}
2945
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946/* Input scanning routines */
2947int
2948skipbl(void)
2949{
2950 int c;
2951
2952 if( termch != 0 ){
2953 c = termch;
2954 termch = 0;
2955 } else
2956 c = inchar();
2957 while( c == ' ' || c == '\t' )
2958 c = inchar();
2959 return c;
2960}
2961
2962#define N_PTREGS 44
2963static char *regnames[N_PTREGS] = {
2964 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2965 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2966 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2967 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002968 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2969#ifdef CONFIG_PPC64
2970 "softe",
2971#else
2972 "mq",
2973#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 "trap", "dar", "dsisr", "res"
2975};
2976
2977int
2978scanhex(unsigned long *vp)
2979{
2980 int c, d;
2981 unsigned long v;
2982
2983 c = skipbl();
2984 if (c == '%') {
2985 /* parse register name */
2986 char regname[8];
2987 int i;
2988
2989 for (i = 0; i < sizeof(regname) - 1; ++i) {
2990 c = inchar();
2991 if (!isalnum(c)) {
2992 termch = c;
2993 break;
2994 }
2995 regname[i] = c;
2996 }
2997 regname[i] = 0;
2998 for (i = 0; i < N_PTREGS; ++i) {
2999 if (strcmp(regnames[i], regname) == 0) {
3000 if (xmon_regs == NULL) {
3001 printf("regs not available\n");
3002 return 0;
3003 }
3004 *vp = ((unsigned long *)xmon_regs)[i];
3005 return 1;
3006 }
3007 }
3008 printf("invalid register name '%%%s'\n", regname);
3009 return 0;
3010 }
3011
3012 /* skip leading "0x" if any */
3013
3014 if (c == '0') {
3015 c = inchar();
3016 if (c == 'x') {
3017 c = inchar();
3018 } else {
3019 d = hexdigit(c);
3020 if (d == EOF) {
3021 termch = c;
3022 *vp = 0;
3023 return 1;
3024 }
3025 }
3026 } else if (c == '$') {
3027 int i;
3028 for (i=0; i<63; i++) {
3029 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02003030 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 termch = c;
3032 break;
3033 }
3034 tmpstr[i] = c;
3035 }
3036 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07003037 *vp = 0;
3038 if (setjmp(bus_error_jmp) == 0) {
3039 catch_memory_errors = 1;
3040 sync();
3041 *vp = kallsyms_lookup_name(tmpstr);
3042 sync();
3043 }
3044 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 if (!(*vp)) {
3046 printf("unknown symbol '%s'\n", tmpstr);
3047 return 0;
3048 }
3049 return 1;
3050 }
3051
3052 d = hexdigit(c);
3053 if (d == EOF) {
3054 termch = c;
3055 return 0;
3056 }
3057 v = 0;
3058 do {
3059 v = (v << 4) + d;
3060 c = inchar();
3061 d = hexdigit(c);
3062 } while (d != EOF);
3063 termch = c;
3064 *vp = v;
3065 return 1;
3066}
3067
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003068static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069scannl(void)
3070{
3071 int c;
3072
3073 c = termch;
3074 termch = 0;
3075 while( c != '\n' )
3076 c = inchar();
3077}
3078
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003079static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080{
3081 if( '0' <= c && c <= '9' )
3082 return c - '0';
3083 if( 'A' <= c && c <= 'F' )
3084 return c - ('A' - 10);
3085 if( 'a' <= c && c <= 'f' )
3086 return c - ('a' - 10);
3087 return EOF;
3088}
3089
3090void
3091getstring(char *s, int size)
3092{
3093 int c;
3094
3095 c = skipbl();
3096 do {
3097 if( size > 1 ){
3098 *s++ = c;
3099 --size;
3100 }
3101 c = inchar();
3102 } while( c != ' ' && c != '\t' && c != '\n' );
3103 termch = c;
3104 *s = 0;
3105}
3106
3107static char line[256];
3108static char *lineptr;
3109
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003110static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111flush_input(void)
3112{
3113 lineptr = NULL;
3114}
3115
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003116static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117inchar(void)
3118{
3119 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003120 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 lineptr = NULL;
3122 return EOF;
3123 }
3124 lineptr = line;
3125 }
3126 return *lineptr++;
3127}
3128
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003129static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130take_input(char *str)
3131{
3132 lineptr = str;
3133}
3134
3135
3136static void
3137symbol_lookup(void)
3138{
3139 int type = inchar();
3140 unsigned long addr;
3141 static char tmp[64];
3142
3143 switch (type) {
3144 case 'a':
3145 if (scanhex(&addr))
3146 xmon_print_symbol(addr, ": ", "\n");
3147 termch = 0;
3148 break;
3149 case 's':
3150 getstring(tmp, 64);
3151 if (setjmp(bus_error_jmp) == 0) {
3152 catch_memory_errors = 1;
3153 sync();
3154 addr = kallsyms_lookup_name(tmp);
3155 if (addr)
3156 printf("%s: %lx\n", tmp, addr);
3157 else
3158 printf("Symbol '%s' not found.\n", tmp);
3159 sync();
3160 }
3161 catch_memory_errors = 0;
3162 termch = 0;
3163 break;
3164 }
3165}
3166
3167
3168/* Print an address in numeric and symbolic form (if possible) */
3169static void xmon_print_symbol(unsigned long address, const char *mid,
3170 const char *after)
3171{
3172 char *modname;
3173 const char *name = NULL;
3174 unsigned long offset, size;
3175
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003176 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 if (setjmp(bus_error_jmp) == 0) {
3178 catch_memory_errors = 1;
3179 sync();
3180 name = kallsyms_lookup(address, &size, &offset, &modname,
3181 tmpstr);
3182 sync();
3183 /* wait a little while to see if we get a machine check */
3184 __delay(200);
3185 }
3186
3187 catch_memory_errors = 0;
3188
3189 if (name) {
3190 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
3191 if (modname)
3192 printf(" [%s]", modname);
3193 }
3194 printf("%s", after);
3195}
3196
Aneesh Kumar K.Vcaca2852016-04-29 23:26:07 +10003197#ifdef CONFIG_PPC_STD_MMU_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10003198void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199{
3200 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05303201 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11003202 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
Michael Ellerman736256e2014-05-26 21:02:14 +10003204 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205
Michael Neuling584f8b72007-12-06 17:24:48 +11003206 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11003207 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
3208 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Michael Ellerman85673642017-04-24 10:35:14 +10003209
3210 if (!esid && !vsid)
3211 continue;
3212
3213 printf("%02d %016lx %016lx", i, esid, vsid);
3214
3215 if (!(esid & SLB_ESID_V)) {
3216 printf("\n");
3217 continue;
3218 }
3219
3220 llp = vsid & SLB_VSID_LLP;
3221 if (vsid & SLB_VSID_B_1T) {
3222 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
3223 GET_ESID_1T(esid),
3224 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
3225 llp);
3226 } else {
3227 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
3228 GET_ESID(esid),
3229 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
3230 llp);
will schmidtb3b95952007-12-07 08:22:23 +11003231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 }
3233}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003234#endif
3235
3236#ifdef CONFIG_PPC_STD_MMU_32
3237void dump_segments(void)
3238{
3239 int i;
3240
3241 printf("sr0-15 =");
3242 for (i = 0; i < 16; ++i)
3243 printf(" %x", mfsrin(i));
3244 printf("\n");
3245}
3246#endif
3247
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003248#ifdef CONFIG_44x
3249static void dump_tlb_44x(void)
3250{
3251 int i;
3252
3253 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
3254 unsigned long w0,w1,w2;
3255 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
3256 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
3257 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
3258 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
3259 if (w0 & PPC44x_TLB_VALID) {
3260 printf("V %08x -> %01x%08x %c%c%c%c%c",
3261 w0 & PPC44x_TLB_EPN_MASK,
3262 w1 & PPC44x_TLB_ERPN_MASK,
3263 w1 & PPC44x_TLB_RPN_MASK,
3264 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
3265 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
3266 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
3267 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
3268 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
3269 }
3270 printf("\n");
3271 }
3272}
3273#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003274
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10003275#ifdef CONFIG_PPC_BOOK3E
3276static void dump_tlb_book3e(void)
3277{
3278 u32 mmucfg, pidmask, lpidmask;
3279 u64 ramask;
3280 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3281 int mmu_version;
3282 static const char *pgsz_names[] = {
3283 " 1K",
3284 " 2K",
3285 " 4K",
3286 " 8K",
3287 " 16K",
3288 " 32K",
3289 " 64K",
3290 "128K",
3291 "256K",
3292 "512K",
3293 " 1M",
3294 " 2M",
3295 " 4M",
3296 " 8M",
3297 " 16M",
3298 " 32M",
3299 " 64M",
3300 "128M",
3301 "256M",
3302 "512M",
3303 " 1G",
3304 " 2G",
3305 " 4G",
3306 " 8G",
3307 " 16G",
3308 " 32G",
3309 " 64G",
3310 "128G",
3311 "256G",
3312 "512G",
3313 " 1T",
3314 " 2T",
3315 };
3316
3317 /* Gather some infos about the MMU */
3318 mmucfg = mfspr(SPRN_MMUCFG);
3319 mmu_version = (mmucfg & 3) + 1;
3320 ntlbs = ((mmucfg >> 2) & 3) + 1;
3321 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3322 lpidsz = (mmucfg >> 24) & 0xf;
3323 rasz = (mmucfg >> 16) & 0x7f;
3324 if ((mmu_version > 1) && (mmucfg & 0x10000))
3325 lrat = 1;
3326 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3327 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3328 pidmask = (1ul << pidsz) - 1;
3329 lpidmask = (1ul << lpidsz) - 1;
3330 ramask = (1ull << rasz) - 1;
3331
3332 for (tlb = 0; tlb < ntlbs; tlb++) {
3333 u32 tlbcfg;
3334 int nent, assoc, new_cc = 1;
3335 printf("TLB %d:\n------\n", tlb);
3336 switch(tlb) {
3337 case 0:
3338 tlbcfg = mfspr(SPRN_TLB0CFG);
3339 break;
3340 case 1:
3341 tlbcfg = mfspr(SPRN_TLB1CFG);
3342 break;
3343 case 2:
3344 tlbcfg = mfspr(SPRN_TLB2CFG);
3345 break;
3346 case 3:
3347 tlbcfg = mfspr(SPRN_TLB3CFG);
3348 break;
3349 default:
3350 printf("Unsupported TLB number !\n");
3351 continue;
3352 }
3353 nent = tlbcfg & 0xfff;
3354 assoc = (tlbcfg >> 24) & 0xff;
3355 for (i = 0; i < nent; i++) {
3356 u32 mas0 = MAS0_TLBSEL(tlb);
3357 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3358 u64 mas2 = 0;
3359 u64 mas7_mas3;
3360 int esel = i, cc = i;
3361
3362 if (assoc != 0) {
3363 cc = i / assoc;
3364 esel = i % assoc;
3365 mas2 = cc * 0x1000;
3366 }
3367
3368 mas0 |= MAS0_ESEL(esel);
3369 mtspr(SPRN_MAS0, mas0);
3370 mtspr(SPRN_MAS1, mas1);
3371 mtspr(SPRN_MAS2, mas2);
3372 asm volatile("tlbre 0,0,0" : : : "memory");
3373 mas1 = mfspr(SPRN_MAS1);
3374 mas2 = mfspr(SPRN_MAS2);
3375 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3376 if (assoc && (i % assoc) == 0)
3377 new_cc = 1;
3378 if (!(mas1 & MAS1_VALID))
3379 continue;
3380 if (assoc == 0)
3381 printf("%04x- ", i);
3382 else if (new_cc)
3383 printf("%04x-%c", cc, 'A' + esel);
3384 else
3385 printf(" |%c", 'A' + esel);
3386 new_cc = 0;
3387 printf(" %016llx %04x %s %c%c AS%c",
3388 mas2 & ~0x3ffull,
3389 (mas1 >> 16) & 0x3fff,
3390 pgsz_names[(mas1 >> 7) & 0x1f],
3391 mas1 & MAS1_IND ? 'I' : ' ',
3392 mas1 & MAS1_IPROT ? 'P' : ' ',
3393 mas1 & MAS1_TS ? '1' : '0');
3394 printf(" %c%c%c%c%c%c%c",
3395 mas2 & MAS2_X0 ? 'a' : ' ',
3396 mas2 & MAS2_X1 ? 'v' : ' ',
3397 mas2 & MAS2_W ? 'w' : ' ',
3398 mas2 & MAS2_I ? 'i' : ' ',
3399 mas2 & MAS2_M ? 'm' : ' ',
3400 mas2 & MAS2_G ? 'g' : ' ',
3401 mas2 & MAS2_E ? 'e' : ' ');
3402 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3403 if (mas1 & MAS1_IND)
3404 printf(" %s\n",
3405 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3406 else
3407 printf(" U%c%c%c S%c%c%c\n",
3408 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3409 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3410 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3411 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3412 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3413 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3414 }
3415 }
3416}
3417#endif /* CONFIG_PPC_BOOK3E */
3418
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003419static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003421 if (enable) {
3422 __debugger = xmon;
3423 __debugger_ipi = xmon_ipi;
3424 __debugger_bpt = xmon_bpt;
3425 __debugger_sstep = xmon_sstep;
3426 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003427 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003428 __debugger_fault_handler = xmon_fault_handler;
3429 } else {
3430 __debugger = NULL;
3431 __debugger_ipi = NULL;
3432 __debugger_bpt = NULL;
3433 __debugger_sstep = NULL;
3434 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003435 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003436 __debugger_fault_handler = NULL;
3437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003439
3440#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003441static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003442{
3443 /* ensure xmon is enabled */
3444 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003445 debugger(get_irq_regs());
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003446 if (!xmon_on)
3447 xmon_init(0);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003448}
3449
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003450static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003451 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003452 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003453 .action_msg = "Entering xmon",
3454};
3455
3456static int __init setup_xmon_sysrq(void)
3457{
3458 register_sysrq_key('x', &sysrq_xmon_op);
3459 return 0;
3460}
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003461device_initcall(setup_xmon_sysrq);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003462#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003463
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003464#ifdef CONFIG_DEBUG_FS
3465static int xmon_dbgfs_set(void *data, u64 val)
3466{
3467 xmon_on = !!val;
3468 xmon_init(xmon_on);
3469
3470 return 0;
3471}
3472
3473static int xmon_dbgfs_get(void *data, u64 *val)
3474{
3475 *val = xmon_on;
3476 return 0;
3477}
3478
3479DEFINE_SIMPLE_ATTRIBUTE(xmon_dbgfs_ops, xmon_dbgfs_get,
3480 xmon_dbgfs_set, "%llu\n");
3481
3482static int __init setup_xmon_dbgfs(void)
3483{
3484 debugfs_create_file("xmon", 0600, powerpc_debugfs_root, NULL,
3485 &xmon_dbgfs_ops);
3486 return 0;
3487}
3488device_initcall(setup_xmon_dbgfs);
3489#endif /* CONFIG_DEBUG_FS */
3490
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003491static int xmon_early __initdata;
Michael Ellerman476792832006-10-03 14:12:08 +10003492
3493static int __init early_parse_xmon(char *p)
3494{
3495 if (!p || strncmp(p, "early", 5) == 0) {
3496 /* just "xmon" is equivalent to "xmon=early" */
3497 xmon_init(1);
3498 xmon_early = 1;
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003499 xmon_on = 1;
3500 } else if (strncmp(p, "on", 2) == 0) {
Michael Ellerman476792832006-10-03 14:12:08 +10003501 xmon_init(1);
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003502 xmon_on = 1;
3503 } else if (strncmp(p, "off", 3) == 0)
3504 xmon_on = 0;
Michael Ellerman476792832006-10-03 14:12:08 +10003505 else
3506 return 1;
3507
3508 return 0;
3509}
3510early_param("xmon", early_parse_xmon);
3511
3512void __init xmon_setup(void)
3513{
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003514 if (xmon_on)
Michael Ellerman476792832006-10-03 14:12:08 +10003515 xmon_init(1);
Michael Ellerman476792832006-10-03 14:12:08 +10003516 if (xmon_early)
3517 debugger(NULL);
3518}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003519
Arnd Bergmanne0555952006-11-27 19:18:55 +01003520#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003521
3522struct spu_info {
3523 struct spu *spu;
3524 u64 saved_mfc_sr1_RW;
3525 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003526 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003527 u8 stopped_ok;
3528};
3529
3530#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3531
3532static struct spu_info spu_info[XMON_NUM_SPUS];
3533
3534void xmon_register_spus(struct list_head *list)
3535{
3536 struct spu *spu;
3537
3538 list_for_each_entry(spu, list, full_list) {
3539 if (spu->number >= XMON_NUM_SPUS) {
3540 WARN_ON(1);
3541 continue;
3542 }
3543
3544 spu_info[spu->number].spu = spu;
3545 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003546 spu_info[spu->number].dump_addr = (unsigned long)
3547 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003548 }
3549}
3550
3551static void stop_spus(void)
3552{
3553 struct spu *spu;
3554 int i;
3555 u64 tmp;
3556
3557 for (i = 0; i < XMON_NUM_SPUS; i++) {
3558 if (!spu_info[i].spu)
3559 continue;
3560
3561 if (setjmp(bus_error_jmp) == 0) {
3562 catch_memory_errors = 1;
3563 sync();
3564
3565 spu = spu_info[i].spu;
3566
3567 spu_info[i].saved_spu_runcntl_RW =
3568 in_be32(&spu->problem->spu_runcntl_RW);
3569
3570 tmp = spu_mfc_sr1_get(spu);
3571 spu_info[i].saved_mfc_sr1_RW = tmp;
3572
3573 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3574 spu_mfc_sr1_set(spu, tmp);
3575
3576 sync();
3577 __delay(200);
3578
3579 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003580
3581 printf("Stopped spu %.2d (was %s)\n", i,
3582 spu_info[i].saved_spu_runcntl_RW ?
3583 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003584 } else {
3585 catch_memory_errors = 0;
3586 printf("*** Error stopping spu %.2d\n", i);
3587 }
3588 catch_memory_errors = 0;
3589 }
3590}
3591
3592static void restart_spus(void)
3593{
3594 struct spu *spu;
3595 int i;
3596
3597 for (i = 0; i < XMON_NUM_SPUS; i++) {
3598 if (!spu_info[i].spu)
3599 continue;
3600
3601 if (!spu_info[i].stopped_ok) {
3602 printf("*** Error, spu %d was not successfully stopped"
3603 ", not restarting\n", i);
3604 continue;
3605 }
3606
3607 if (setjmp(bus_error_jmp) == 0) {
3608 catch_memory_errors = 1;
3609 sync();
3610
3611 spu = spu_info[i].spu;
3612 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3613 out_be32(&spu->problem->spu_runcntl_RW,
3614 spu_info[i].saved_spu_runcntl_RW);
3615
3616 sync();
3617 __delay(200);
3618
3619 printf("Restarted spu %.2d\n", i);
3620 } else {
3621 catch_memory_errors = 0;
3622 printf("*** Error restarting spu %.2d\n", i);
3623 }
3624 catch_memory_errors = 0;
3625 }
3626}
3627
Michael Ellermana8984972006-10-24 18:31:28 +02003628#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003629#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003630do { \
3631 if (setjmp(bus_error_jmp) == 0) { \
3632 catch_memory_errors = 1; \
3633 sync(); \
3634 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003635 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003636 sync(); \
3637 __delay(200); \
3638 } else { \
3639 catch_memory_errors = 0; \
3640 printf(" %-*s = *** Error reading field.\n", \
3641 DUMP_WIDTH, #field); \
3642 } \
3643 catch_memory_errors = 0; \
3644} while (0)
3645
Michael Ellerman437a0702006-11-23 00:46:39 +01003646#define DUMP_FIELD(obj, format, field) \
3647 DUMP_VALUE(format, field, obj->field)
3648
Michael Ellermana8984972006-10-24 18:31:28 +02003649static void dump_spu_fields(struct spu *spu)
3650{
3651 printf("Dumping spu fields at address %p:\n", spu);
3652
3653 DUMP_FIELD(spu, "0x%x", number);
3654 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003655 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3656 DUMP_FIELD(spu, "0x%p", local_store);
3657 DUMP_FIELD(spu, "0x%lx", ls_size);
3658 DUMP_FIELD(spu, "0x%x", node);
3659 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003660 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003661 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003662 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3663 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003664 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3665 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3666 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3667 DUMP_FIELD(spu, "0x%x", slb_replace);
3668 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003669 DUMP_FIELD(spu, "0x%p", mm);
3670 DUMP_FIELD(spu, "0x%p", ctx);
3671 DUMP_FIELD(spu, "0x%p", rq);
3672 DUMP_FIELD(spu, "0x%p", timestamp);
3673 DUMP_FIELD(spu, "0x%lx", problem_phys);
3674 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003675 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3676 in_be32(&spu->problem->spu_runcntl_RW));
3677 DUMP_VALUE("0x%x", problem->spu_status_R,
3678 in_be32(&spu->problem->spu_status_R));
3679 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3680 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003681 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003682 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003683}
3684
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003685int
3686spu_inst_dump(unsigned long adr, long count, int praddr)
3687{
3688 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3689}
3690
3691static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003692{
3693 unsigned long offset, addr, ls_addr;
3694
3695 if (setjmp(bus_error_jmp) == 0) {
3696 catch_memory_errors = 1;
3697 sync();
3698 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3699 sync();
3700 __delay(200);
3701 } else {
3702 catch_memory_errors = 0;
3703 printf("*** Error: accessing spu info for spu %d\n", num);
3704 return;
3705 }
3706 catch_memory_errors = 0;
3707
3708 if (scanhex(&offset))
3709 addr = ls_addr + offset;
3710 else
3711 addr = spu_info[num].dump_addr;
3712
3713 if (addr >= ls_addr + LS_SIZE) {
3714 printf("*** Error: address outside of local store\n");
3715 return;
3716 }
3717
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003718 switch (subcmd) {
3719 case 'i':
3720 addr += spu_inst_dump(addr, 16, 1);
3721 last_cmd = "sdi\n";
3722 break;
3723 default:
3724 prdump(addr, 64);
3725 addr += 64;
3726 last_cmd = "sd\n";
3727 break;
3728 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003729
3730 spu_info[num].dump_addr = addr;
3731}
3732
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003733static int do_spu_cmd(void)
3734{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003735 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003736 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003737
3738 cmd = inchar();
3739 switch (cmd) {
3740 case 's':
3741 stop_spus();
3742 break;
3743 case 'r':
3744 restart_spus();
3745 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003746 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003747 subcmd = inchar();
3748 if (isxdigit(subcmd) || subcmd == '\n')
3749 termch = subcmd;
3750 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003751 scanhex(&num);
3752 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003753 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003754 return 0;
3755 }
3756
3757 switch (cmd) {
3758 case 'f':
3759 dump_spu_fields(spu_info[num].spu);
3760 break;
3761 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003762 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003763 break;
3764 }
3765
Michael Ellermana8984972006-10-24 18:31:28 +02003766 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003767 default:
3768 return -1;
3769 }
3770
3771 return 0;
3772}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003773#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003774static int do_spu_cmd(void)
3775{
3776 return -1;
3777}
3778#endif