blob: 9e68f1dca5685de84165542b3a7f24a935c4cb5e [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];
Breno Leitaoed49f7f2017-08-02 17:14:06 -030092static int tracing_enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static long bus_error_jmp[JMP_BUF_LEN];
95static int catch_memory_errors;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +100096static int catch_spr_faults;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99/* Breakpoint stuff */
100struct bpt {
101 unsigned long address;
102 unsigned int instr[2];
103 atomic_t ref_count;
104 int enabled;
105 unsigned long pad;
106};
107
108/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100109#define BP_CIABR 1
110#define BP_TRAP 2
111#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
113#define NBPTS 256
114static struct bpt bpts[NBPTS];
115static struct bpt dabr;
116static struct bpt *iabr;
117static unsigned bpinstr = 0x7fe00008; /* trap */
118
119#define BP_NUM(bp) ((bp) - bpts + 1)
120
121/* Prototypes */
122static int cmds(struct pt_regs *);
123static int mread(unsigned long, void *, int);
124static int mwrite(unsigned long, void *, int);
125static int handle_fault(struct pt_regs *);
126static void byterev(unsigned char *, int);
127static void memex(void);
128static int bsesc(void);
129static void dump(void);
130static void prdump(unsigned long, long);
131static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000132static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100133
134#ifdef CONFIG_PPC_POWERNV
135static void dump_opal_msglog(void);
136#else
137static inline void dump_opal_msglog(void)
138{
139 printf("Machine is not running OPAL firmware.\n");
140}
141#endif
142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143static void backtrace(struct pt_regs *);
144static void excprint(struct pt_regs *);
145static void prregs(struct pt_regs *);
146static void memops(int);
147static void memlocate(void);
148static void memzcan(void);
149static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
150int skipbl(void);
151int scanhex(unsigned long *valp);
152static void scannl(void);
153static int hexdigit(int);
154void getstring(char *, int);
155static void flush_input(void);
156static int inchar(void);
157static void take_input(char *);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000158static int read_spr(int, unsigned long *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159static void write_spr(int, unsigned long);
160static void super_regs(void);
161static void remove_bpts(void);
162static void insert_bpts(void);
163static void remove_cpu_bpts(void);
164static void insert_cpu_bpts(void);
165static struct bpt *at_breakpoint(unsigned long pc);
166static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
167static int do_step(struct pt_regs *);
168static void bpt_cmds(void);
169static void cacheflush(void);
170static int cpu_cmd(void);
171static void csum(void);
172static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000173static void proccall(void);
Douglas Miller6dfb5402015-11-23 09:01:15 -0600174static void show_tasks(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175void dump_segments(void);
176static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200177static void xmon_show_stack(unsigned long sp, unsigned long lr,
178 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179static void xmon_print_symbol(unsigned long address, const char *mid,
180 const char *after);
181static const char *getvecname(unsigned long vec);
182
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200183static int do_spu_cmd(void);
184
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100185#ifdef CONFIG_44x
186static void dump_tlb_44x(void);
187#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000188#ifdef CONFIG_PPC_BOOK3E
189static void dump_tlb_book3e(void);
190#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100191
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000192#ifdef CONFIG_PPC64
193#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000194#else
195#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000196#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100198#ifdef __LITTLE_ENDIAN__
199#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
200#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100202#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204static char *help_string = "\
205Commands:\n\
206 b show breakpoints\n\
207 bd set data breakpoint\n\
208 bi set instruction breakpoint\n\
209 bc clear breakpoint\n"
210#ifdef CONFIG_SMP
211 "\
212 c print cpus stopped in xmon\n\
213 c# try to switch to cpu number h (in hex)\n"
214#endif
215 "\
216 C checksum\n\
217 d dump bytes\n\
Douglas Miller5e48dc02017-02-07 07:40:44 -0600218 d1 dump 1 byte values\n\
219 d2 dump 2 byte values\n\
220 d4 dump 4 byte values\n\
221 d8 dump 8 byte values\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 di dump instructions\n\
223 df dump float values\n\
224 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000225 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100226#ifdef CONFIG_PPC_POWERNV
227 "\
228 do dump the OPAL message log\n"
229#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000230#ifdef CONFIG_PPC64
231 "\
232 dp[#] dump paca for current cpu, or cpu #\n\
233 dpa dump paca for all possible cpus\n"
234#endif
235 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100236 dr dump stream of raw bytes\n\
Michael Ellerman56144ec2015-11-06 13:21:17 +1100237 dt dump the tracing buffers (uses printk)\n\
Breno Leitao4125d012017-08-02 17:14:05 -0300238 dtc dump the tracing buffers for current CPU (uses printk)\n\
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +1000239"
240#ifdef CONFIG_PPC_POWERNV
241" dx# dump xive on CPU #\n\
242 dxi# dump xive irq state #\n\
243 dxa dump xive on all CPUs\n"
244#endif
245" e print exception information\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 f flush cache\n\
247 la lookup symbol+offset of specified address\n\
248 ls lookup address of specified symbol\n\
249 m examine/change memory\n\
250 mm move a block of memory\n\
251 ms set a block of memory\n\
252 md compare two blocks of memory\n\
253 ml locate a block of memory\n\
254 mz zero a block of memory\n\
255 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000256 p call a procedure\n\
Douglas Miller6dfb5402015-11-23 09:01:15 -0600257 P list processes/tasks\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200259 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100260#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200261" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200262 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100263 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900264 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100265 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200266#endif
267" S print special registers\n\
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000268 Sa print all SPRs\n\
269 Sr # read SPR #\n\
270 Sw #v write v to SPR #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100273 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000274#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000275" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000276#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000277" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000278#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100279" u dump TLB\n"
280#endif
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000281" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100282" # n limit output to n lines per page (for dp, dpa, dl)\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000283" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 zh halt\n"
285;
286
287static struct pt_regs *xmon_regs;
288
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000289static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
291 asm volatile("sync; isync");
292}
293
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000294static inline void store_inst(void *p)
295{
296 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
297}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000299static inline void cflush(void *p)
300{
301 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
302}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000304static inline void cinval(void *p)
305{
306 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
307}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530309/**
310 * write_ciabr() - write the CIABR SPR
311 * @ciabr: The value to write.
312 *
313 * This function writes a value to the CIARB register either directly
314 * through mtspr instruction if the kernel is in HV privilege mode or
315 * call a hypervisor function to achieve the same in case the kernel
316 * is in supervisor privilege mode.
317 */
318static void write_ciabr(unsigned long ciabr)
319{
320 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
321 return;
322
323 if (cpu_has_feature(CPU_FTR_HVMODE)) {
324 mtspr(SPRN_CIABR, ciabr);
325 return;
326 }
327 plapr_set_ciabr(ciabr);
328}
329
330/**
331 * set_ciabr() - set the CIABR
332 * @addr: The value to set.
333 *
334 * This function sets the correct privilege value into the the HW
335 * breakpoint address before writing it up in the CIABR register.
336 */
337static void set_ciabr(unsigned long addr)
338{
339 addr &= ~CIABR_PRIV;
340
341 if (cpu_has_feature(CPU_FTR_HVMODE))
342 addr |= CIABR_PRIV_HYPER;
343 else
344 addr |= CIABR_PRIV_SUPER;
345 write_ciabr(addr);
346}
347
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348/*
349 * Disable surveillance (the service processor watchdog function)
350 * while we are in xmon.
351 * XXX we should re-enable it when we leave. :)
352 */
353#define SURVEILLANCE_TOKEN 9000
354
355static inline void disable_surveillance(void)
356{
357#ifdef CONFIG_PPC_PSERIES
358 /* Since this can't be a module, args should end up below 4GB. */
359 static struct rtas_args args;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100360 int token;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362 /*
363 * At this point we have got all the cpus we can into
364 * xmon, so there is hopefully no other cpu calling RTAS
365 * at the moment, even though we don't take rtas.lock.
366 * If we did try to take rtas.lock there would be a
367 * real possibility of deadlock.
368 */
Michael Ellerman08eb1052015-11-24 22:26:09 +1100369 token = rtas_token("set-indicator");
370 if (token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100372
373 rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0);
374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375#endif /* CONFIG_PPC_PSERIES */
376}
377
378#ifdef CONFIG_SMP
379static int xmon_speaker;
380
381static void get_output_lock(void)
382{
383 int me = smp_processor_id() + 0x100;
384 int last_speaker = 0, prev;
385 long timeout;
386
387 if (xmon_speaker == me)
388 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100391 last_speaker = cmpxchg(&xmon_speaker, 0, me);
392 if (last_speaker == 0)
393 return;
394
Michael Ellerman15075892013-12-23 23:46:05 +1100395 /*
396 * Wait a full second for the lock, we might be on a slow
397 * console, but check every 100us.
398 */
399 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100401 if (--timeout > 0) {
402 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100404 }
405
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 /* hostile takeover */
407 prev = cmpxchg(&xmon_speaker, last_speaker, me);
408 if (prev == last_speaker)
409 return;
410 break;
411 }
412 }
413}
414
415static void release_output_lock(void)
416{
417 xmon_speaker = 0;
418}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000419
420int cpus_are_in_xmon(void)
421{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000422 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000423}
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000424
425static bool wait_for_other_cpus(int ncpus)
426{
427 unsigned long timeout;
428
429 /* We wait for 2s, which is a metric "little while" */
430 for (timeout = 20000; timeout != 0; --timeout) {
431 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
432 return true;
433 udelay(100);
434 barrier();
435 }
436
437 return false;
438}
439#endif /* CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Josh Boyerdaf8f402009-09-23 03:51:04 +0000441static inline int unrecoverable_excp(struct pt_regs *regs)
442{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000443#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000444 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000445 return 0;
446#else
447 return ((regs->msr & MSR_RI) == 0);
448#endif
449}
450
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000451static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
453 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 struct bpt *bp;
455 long recurse_jmp[JMP_BUF_LEN];
456 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100457 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458#ifdef CONFIG_SMP
459 int cpu;
460 int secondary;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461#endif
462
Anton Blanchardf13659e2007-03-21 01:48:34 +1100463 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000464 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
Breno Leitaoed49f7f2017-08-02 17:14:06 -0300466 tracing_enabled = tracing_is_on();
467 tracing_off();
468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 bp = in_breakpoint_table(regs->nip, &offset);
470 if (bp != NULL) {
471 regs->nip = bp->address + offset;
472 atomic_dec(&bp->ref_count);
473 }
474
475 remove_cpu_bpts();
476
477#ifdef CONFIG_SMP
478 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000479 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000480 /*
481 * We catch SPR read/write faults here because the 0x700, 0xf60
482 * etc. handlers don't call debugger_fault_handler().
483 */
484 if (catch_spr_faults)
485 longjmp(bus_error_jmp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 get_output_lock();
487 excprint(regs);
488 printf("cpu 0x%x: Exception %lx %s in xmon, "
489 "returning to main loop\n",
490 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000491 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 longjmp(xmon_fault_jmp[cpu], 1);
493 }
494
495 if (setjmp(recurse_jmp) != 0) {
496 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000497 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 printf("xmon: WARNING: bad recursive fault "
499 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000500 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 goto waiting;
502 }
503 secondary = !(xmon_taken && cpu == xmon_owner);
504 goto cmdloop;
505 }
506
507 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000510 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000512 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 fromipi = 0;
514
515 if (!fromipi) {
516 get_output_lock();
517 excprint(regs);
518 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000519 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 cpu, BP_NUM(bp));
521 xmon_print_symbol(regs->nip, " ", ")\n");
522 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000523 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 printf("WARNING: exception is not recoverable, "
525 "can't continue\n");
526 release_output_lock();
527 }
528
Michael Ellermand2b496e2013-12-23 23:46:06 +1100529 cpumask_set_cpu(cpu, &cpus_in_xmon);
530
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 waiting:
532 secondary = 1;
533 while (secondary && !xmon_gate) {
534 if (in_xmon == 0) {
535 if (fromipi)
536 goto leave;
537 secondary = test_and_set_bit(0, &in_xmon);
538 }
539 barrier();
540 }
541
542 if (!secondary && !xmon_gate) {
543 /* we are the first cpu to come in */
544 /* interrupt other cpu(s) */
545 int ncpus = num_online_cpus();
546
547 xmon_owner = cpu;
548 mb();
549 if (ncpus > 1) {
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000550 /*
551 * A system reset (trap == 0x100) can be triggered on
552 * all CPUs, so when we come in via 0x100 try waiting
553 * for the other CPUs to come in before we send the
554 * debugger break (IPI). This is similar to
555 * crash_kexec_secondary().
556 */
557 if (TRAP(regs) != 0x100 || !wait_for_other_cpus(ncpus))
558 smp_send_debugger_break();
559
560 wait_for_other_cpus(ncpus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 }
562 remove_bpts();
563 disable_surveillance();
564 /* for breakpoint or single step, print the current instr. */
565 if (bp || TRAP(regs) == 0xd00)
566 ppc_inst_dump(regs->nip, 1, 0);
567 printf("enter ? for help\n");
568 mb();
569 xmon_gate = 1;
570 barrier();
571 }
572
573 cmdloop:
574 while (in_xmon) {
575 if (secondary) {
576 if (cpu == xmon_owner) {
577 if (!test_and_set_bit(0, &xmon_taken)) {
578 secondary = 0;
579 continue;
580 }
581 /* missed it */
582 while (cpu == xmon_owner)
583 barrier();
584 }
585 barrier();
586 } else {
587 cmd = cmds(regs);
588 if (cmd != 0) {
589 /* exiting xmon */
590 insert_bpts();
591 xmon_gate = 0;
592 wmb();
593 in_xmon = 0;
594 break;
595 }
596 /* have switched to some other cpu */
597 secondary = 1;
598 }
599 }
600 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000601 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603#else
604 /* UP is simple... */
605 if (in_xmon) {
606 printf("Exception %lx %s in xmon, returning to main loop\n",
607 regs->trap, getvecname(TRAP(regs)));
608 longjmp(xmon_fault_jmp[0], 1);
609 }
610 if (setjmp(recurse_jmp) == 0) {
611 xmon_fault_jmp[0] = recurse_jmp;
612 in_xmon = 1;
613
614 excprint(regs);
615 bp = at_breakpoint(regs->nip);
616 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000617 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 xmon_print_symbol(regs->nip, " ", ")\n");
619 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000620 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 printf("WARNING: exception is not recoverable, "
622 "can't continue\n");
623 remove_bpts();
624 disable_surveillance();
625 /* for breakpoint or single step, print the current instr. */
626 if (bp || TRAP(regs) == 0xd00)
627 ppc_inst_dump(regs->nip, 1, 0);
628 printf("enter ? for help\n");
629 }
630
631 cmd = cmds(regs);
632
633 insert_bpts();
634 in_xmon = 0;
635#endif
636
Josh Boyercdd39042009-10-05 04:46:05 +0000637#ifdef CONFIG_BOOKE
638 if (regs->msr & MSR_DE) {
639 bp = at_breakpoint(regs->nip);
640 if (bp != NULL) {
641 regs->nip = (unsigned long) &bp->instr[0];
642 atomic_inc(&bp->ref_count);
643 }
644 }
645#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000646 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 bp = at_breakpoint(regs->nip);
648 if (bp != NULL) {
649 int stepped = emulate_step(regs, bp->instr[0]);
650 if (stepped == 0) {
651 regs->nip = (unsigned long) &bp->instr[0];
652 atomic_inc(&bp->ref_count);
653 } else if (stepped < 0) {
654 printf("Couldn't single-step %s instruction\n",
655 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
656 }
657 }
658 }
Josh Boyercdd39042009-10-05 04:46:05 +0000659#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 insert_cpu_bpts();
661
Anton Blancharda71d64b2014-08-05 14:55:00 +1000662 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100663 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000665 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666}
667
668int xmon(struct pt_regs *excp)
669{
670 struct pt_regs regs;
671
672 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000673 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 excp = &regs;
675 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200676
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 return xmon_core(excp, 0);
678}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000679EXPORT_SYMBOL(xmon);
680
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000681irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000682{
683 unsigned long flags;
684 local_irq_save(flags);
685 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000686 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000687 local_irq_restore(flags);
688 return IRQ_HANDLED;
689}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000691static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692{
693 struct bpt *bp;
694 unsigned long offset;
695
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000696 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return 0;
698
699 /* Are we at the trap at bp->instr[1] for some bp? */
700 bp = in_breakpoint_table(regs->nip, &offset);
701 if (bp != NULL && offset == 4) {
702 regs->nip = bp->address + 4;
703 atomic_dec(&bp->ref_count);
704 return 1;
705 }
706
707 /* Are we at a breakpoint? */
708 bp = at_breakpoint(regs->nip);
709 if (!bp)
710 return 0;
711
712 xmon_core(regs, 0);
713
714 return 1;
715}
716
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000717static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
719 if (user_mode(regs))
720 return 0;
721 xmon_core(regs, 0);
722 return 1;
723}
724
Michael Neuling9422de32012-12-20 14:06:44 +0000725static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000727 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000729 if (dabr.enabled == 0)
730 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 xmon_core(regs, 0);
732 return 1;
733}
734
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000735static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000737 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000739 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 return 0;
741 xmon_core(regs, 0);
742 return 1;
743}
744
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000745static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
747#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000748 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 xmon_core(regs, 1);
750#endif
751 return 0;
752}
753
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000754static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755{
756 struct bpt *bp;
757 unsigned long offset;
758
759 if (in_xmon && catch_memory_errors)
760 handle_fault(regs); /* doesn't return */
761
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000762 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 bp = in_breakpoint_table(regs->nip, &offset);
764 if (bp != NULL) {
765 regs->nip = bp->address + offset;
766 atomic_dec(&bp->ref_count);
767 }
768 }
769
770 return 0;
771}
772
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773static struct bpt *at_breakpoint(unsigned long pc)
774{
775 int i;
776 struct bpt *bp;
777
778 bp = bpts;
779 for (i = 0; i < NBPTS; ++i, ++bp)
780 if (bp->enabled && pc == bp->address)
781 return bp;
782 return NULL;
783}
784
785static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
786{
787 unsigned long off;
788
789 off = nip - (unsigned long) bpts;
790 if (off >= sizeof(bpts))
791 return NULL;
792 off %= sizeof(struct bpt);
793 if (off != offsetof(struct bpt, instr[0])
794 && off != offsetof(struct bpt, instr[1]))
795 return NULL;
796 *offp = off - offsetof(struct bpt, instr[0]);
797 return (struct bpt *) (nip - off);
798}
799
800static struct bpt *new_breakpoint(unsigned long a)
801{
802 struct bpt *bp;
803
804 a &= ~3UL;
805 bp = at_breakpoint(a);
806 if (bp)
807 return bp;
808
809 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
810 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
811 bp->address = a;
812 bp->instr[1] = bpinstr;
813 store_inst(&bp->instr[1]);
814 return bp;
815 }
816 }
817
818 printf("Sorry, no free breakpoints. Please clear one first.\n");
819 return NULL;
820}
821
822static void insert_bpts(void)
823{
824 int i;
825 struct bpt *bp;
826
827 bp = bpts;
828 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100829 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 continue;
831 if (mread(bp->address, &bp->instr[0], 4) != 4) {
832 printf("Couldn't read instruction at %lx, "
833 "disabling breakpoint there\n", bp->address);
834 bp->enabled = 0;
835 continue;
836 }
837 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
838 printf("Breakpoint at %lx is on an mtmsrd or rfid "
839 "instruction, disabling it\n", bp->address);
840 bp->enabled = 0;
841 continue;
842 }
843 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100844 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 continue;
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000846 if (patch_instruction((unsigned int *)bp->address,
847 bpinstr) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 printf("Couldn't write instruction at %lx, "
849 "disabling breakpoint there\n", bp->address);
850 bp->enabled &= ~BP_TRAP;
851 continue;
852 }
853 store_inst((void *)bp->address);
854 }
855}
856
857static void insert_cpu_bpts(void)
858{
Michael Neuling9422de32012-12-20 14:06:44 +0000859 struct arch_hw_breakpoint brk;
860
861 if (dabr.enabled) {
862 brk.address = dabr.address;
863 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
864 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400865 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000866 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530867
868 if (iabr)
869 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870}
871
872static void remove_bpts(void)
873{
874 int i;
875 struct bpt *bp;
876 unsigned instr;
877
878 bp = bpts;
879 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100880 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 continue;
882 if (mread(bp->address, &instr, 4) == 4
883 && instr == bpinstr
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000884 && patch_instruction(
885 (unsigned int *)bp->address, bp->instr[0]) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 printf("Couldn't remove breakpoint at %lx\n",
887 bp->address);
888 else
889 store_inst((void *)bp->address);
890 }
891}
892
893static void remove_cpu_bpts(void)
894{
Michael Neuling9422de32012-12-20 14:06:44 +0000895 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530896 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897}
898
Sam bobroff958b7c82015-10-08 11:50:23 +1100899static void set_lpp_cmd(void)
900{
901 unsigned long lpp;
902
903 if (!scanhex(&lpp)) {
904 printf("Invalid number.\n");
905 lpp = 0;
906 }
907 xmon_set_pagination_lpp(lpp);
908}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909/* Command interpreting routine */
910static char *last_cmd;
911
912static int
913cmds(struct pt_regs *excp)
914{
915 int cmd = 0;
916
917 last_cmd = NULL;
918 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200919
Guilherme G. Piccolib5617832017-03-22 16:27:50 -0300920 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
Olaf Hering26c8af52006-09-08 16:29:21 +0200921
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 for(;;) {
923#ifdef CONFIG_SMP
924 printf("%x:", smp_processor_id());
925#endif /* CONFIG_SMP */
926 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 flush_input();
928 termch = 0;
929 cmd = skipbl();
930 if( cmd == '\n' ) {
931 if (last_cmd == NULL)
932 continue;
933 take_input(last_cmd);
934 last_cmd = NULL;
935 cmd = inchar();
936 }
937 switch (cmd) {
938 case 'm':
939 cmd = inchar();
940 switch (cmd) {
941 case 'm':
942 case 's':
943 case 'd':
944 memops(cmd);
945 break;
946 case 'l':
947 memlocate();
948 break;
949 case 'z':
950 memzcan();
951 break;
952 case 'i':
Michal Hocko9af744d2017-02-22 15:46:16 -0800953 show_mem(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 break;
955 default:
956 termch = cmd;
957 memex();
958 }
959 break;
960 case 'd':
961 dump();
962 break;
963 case 'l':
964 symbol_lookup();
965 break;
966 case 'r':
967 prregs(excp); /* print regs */
968 break;
969 case 'e':
970 excprint(excp);
971 break;
972 case 'S':
973 super_regs();
974 break;
975 case 't':
976 backtrace(excp);
977 break;
978 case 'f':
979 cacheflush();
980 break;
981 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200982 if (do_spu_cmd() == 0)
983 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 if (do_step(excp))
985 return cmd;
986 break;
987 case 'x':
988 case 'X':
Breno Leitaoed49f7f2017-08-02 17:14:06 -0300989 if (tracing_enabled)
990 tracing_on();
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100991 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100993 printf(" <no input ...>\n");
994 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 return cmd;
996 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000997 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 break;
Sam bobroff958b7c82015-10-08 11:50:23 +1100999 case '#':
1000 set_lpp_cmd();
1001 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 case 'b':
1003 bpt_cmds();
1004 break;
1005 case 'C':
1006 csum();
1007 break;
1008 case 'c':
1009 if (cpu_cmd())
1010 return 0;
1011 break;
1012 case 'z':
1013 bootcmds();
1014 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001015 case 'p':
1016 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -06001018 case 'P':
1019 show_tasks();
1020 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001021#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 case 'u':
1023 dump_segments();
1024 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +11001025#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11001026 case 'u':
1027 dump_tlb_44x();
1028 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +00001029#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10001030 case 'u':
1031 dump_tlb_book3e();
1032 break;
1033#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 default:
1035 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +00001036 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 if (' ' < cmd && cmd <= '~')
1038 putchar(cmd);
1039 else
1040 printf("\\x%x", cmd);
1041 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +00001042 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 printf(" (type ? for help)\n");
1044 break;
1045 }
1046 }
1047}
1048
Josh Boyercdd39042009-10-05 04:46:05 +00001049#ifdef CONFIG_BOOKE
1050static int do_step(struct pt_regs *regs)
1051{
1052 regs->msr |= MSR_DE;
1053 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1054 return 1;
1055}
1056#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057/*
1058 * Step a single instruction.
1059 * Some instructions we emulate, others we execute with MSR_SE set.
1060 */
1061static int do_step(struct pt_regs *regs)
1062{
1063 unsigned int instr;
1064 int stepped;
1065
1066 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001067 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 if (mread(regs->nip, &instr, 4) == 4) {
1069 stepped = emulate_step(regs, instr);
1070 if (stepped < 0) {
1071 printf("Couldn't single-step %s instruction\n",
1072 (IS_RFID(instr)? "rfid": "mtmsrd"));
1073 return 0;
1074 }
1075 if (stepped > 0) {
1076 regs->trap = 0xd00 | (regs->trap & 1);
1077 printf("stepped to ");
1078 xmon_print_symbol(regs->nip, " ", "\n");
1079 ppc_inst_dump(regs->nip, 1, 0);
1080 return 0;
1081 }
1082 }
1083 }
1084 regs->msr |= MSR_SE;
1085 return 1;
1086}
Josh Boyercdd39042009-10-05 04:46:05 +00001087#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
1089static void bootcmds(void)
1090{
1091 int cmd;
1092
1093 cmd = inchar();
1094 if (cmd == 'r')
1095 ppc_md.restart(NULL);
1096 else if (cmd == 'h')
1097 ppc_md.halt();
1098 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001099 if (pm_power_off)
1100 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101}
1102
1103static int cpu_cmd(void)
1104{
1105#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001106 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
1109 if (!scanhex(&cpu)) {
1110 /* print cpus waiting or in xmon */
1111 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001112 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001113 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001114 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001115 if (cpu == last_cpu + 1) {
1116 last_cpu = cpu;
1117 } else {
1118 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001119 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001120 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001121 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 }
1124 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001125 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001126 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 printf("\n");
1128 return 0;
1129 }
1130 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001131 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 printf("cpu 0x%x isn't in xmon\n", cpu);
1133 return 0;
1134 }
1135 xmon_taken = 0;
1136 mb();
1137 xmon_owner = cpu;
1138 timeout = 10000000;
1139 while (!xmon_taken) {
1140 if (--timeout == 0) {
1141 if (test_and_set_bit(0, &xmon_taken))
1142 break;
1143 /* take control back */
1144 mb();
1145 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001146 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 return 0;
1148 }
1149 barrier();
1150 }
1151 return 1;
1152#else
1153 return 0;
1154#endif /* CONFIG_SMP */
1155}
1156
1157static unsigned short fcstab[256] = {
1158 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1159 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1160 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1161 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1162 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1163 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1164 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1165 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1166 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1167 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1168 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1169 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1170 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1171 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1172 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1173 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1174 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1175 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1176 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1177 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1178 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1179 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1180 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1181 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1182 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1183 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1184 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1185 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1186 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1187 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1188 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1189 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1190};
1191
1192#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1193
1194static void
1195csum(void)
1196{
1197 unsigned int i;
1198 unsigned short fcs;
1199 unsigned char v;
1200
1201 if (!scanhex(&adrs))
1202 return;
1203 if (!scanhex(&ncsum))
1204 return;
1205 fcs = 0xffff;
1206 for (i = 0; i < ncsum; ++i) {
1207 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001208 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 break;
1210 }
1211 fcs = FCS(fcs, v);
1212 }
1213 printf("%x\n", fcs);
1214}
1215
1216/*
1217 * Check if this is a suitable place to put a breakpoint.
1218 */
1219static long check_bp_loc(unsigned long addr)
1220{
1221 unsigned int instr;
1222
1223 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001224 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 printf("Breakpoints may only be placed at kernel addresses\n");
1226 return 0;
1227 }
1228 if (!mread(addr, &instr, sizeof(instr))) {
1229 printf("Can't read instruction at address %lx\n", addr);
1230 return 0;
1231 }
1232 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1233 printf("Breakpoints may not be placed on mtmsrd or rfid "
1234 "instructions\n");
1235 return 0;
1236 }
1237 return 1;
1238}
1239
Michael Ellermane3bc8042012-08-23 22:09:13 +00001240static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 "Breakpoint command usage:\n"
1242 "b show breakpoints\n"
1243 "b <addr> [cnt] set breakpoint at given instr addr\n"
1244 "bc clear all breakpoints\n"
1245 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301246 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 "bd <addr> [cnt] set hardware data breakpoint\n"
1248 "";
1249
1250static void
1251bpt_cmds(void)
1252{
1253 int cmd;
1254 unsigned long a;
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001255 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 struct bpt *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
1258 cmd = inchar();
1259 switch (cmd) {
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001260#ifndef CONFIG_PPC_8xx
1261 static const char badaddr[] = "Only kernel addresses are permitted for breakpoints\n";
1262 int mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 case 'd': /* bd - hardware data breakpoint */
1264 mode = 7;
1265 cmd = inchar();
1266 if (cmd == 'r')
1267 mode = 5;
1268 else if (cmd == 'w')
1269 mode = 6;
1270 else
1271 termch = cmd;
1272 dabr.address = 0;
1273 dabr.enabled = 0;
1274 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001275 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 printf(badaddr);
1277 break;
1278 }
Michael Neuling9422de32012-12-20 14:06:44 +00001279 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 dabr.enabled = mode | BP_DABR;
1281 }
1282 break;
1283
1284 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301285 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 printf("Hardware instruction breakpoint "
1287 "not supported on this cpu\n");
1288 break;
1289 }
1290 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001291 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 iabr = NULL;
1293 }
1294 if (!scanhex(&a))
1295 break;
1296 if (!check_bp_loc(a))
1297 break;
1298 bp = new_breakpoint(a);
1299 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001300 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 iabr = bp;
1302 }
1303 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001304#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
1306 case 'c':
1307 if (!scanhex(&a)) {
1308 /* clear all breakpoints */
1309 for (i = 0; i < NBPTS; ++i)
1310 bpts[i].enabled = 0;
1311 iabr = NULL;
1312 dabr.enabled = 0;
1313 printf("All breakpoints cleared\n");
1314 break;
1315 }
1316
1317 if (a <= NBPTS && a >= 1) {
1318 /* assume a breakpoint number */
1319 bp = &bpts[a-1]; /* bp nums are 1 based */
1320 } else {
1321 /* assume a breakpoint address */
1322 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001323 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001324 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 break;
1326 }
1327 }
1328
Michael Ellerman736256e2014-05-26 21:02:14 +10001329 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 xmon_print_symbol(bp->address, " ", ")\n");
1331 bp->enabled = 0;
1332 break;
1333
1334 default:
1335 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001336 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 if (cmd == '?') {
1338 printf(breakpoint_help_string);
1339 break;
1340 }
1341 termch = cmd;
1342 if (!scanhex(&a)) {
1343 /* print all breakpoints */
1344 printf(" type address\n");
1345 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001346 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 if (dabr.enabled & 1)
1348 printf("r");
1349 if (dabr.enabled & 2)
1350 printf("w");
1351 printf("]\n");
1352 }
1353 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1354 if (!bp->enabled)
1355 continue;
1356 printf("%2x %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001357 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 xmon_print_symbol(bp->address, " ", "\n");
1359 }
1360 break;
1361 }
1362
1363 if (!check_bp_loc(a))
1364 break;
1365 bp = new_breakpoint(a);
1366 if (bp != NULL)
1367 bp->enabled |= BP_TRAP;
1368 break;
1369 }
1370}
1371
1372/* Very cheap human name for vector lookup. */
1373static
1374const char *getvecname(unsigned long vec)
1375{
1376 char *ret;
1377
1378 switch (vec) {
1379 case 0x100: ret = "(System Reset)"; break;
1380 case 0x200: ret = "(Machine Check)"; break;
1381 case 0x300: ret = "(Data Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001382 case 0x380:
1383 if (radix_enabled())
1384 ret = "(Data Access Out of Range)";
1385 else
1386 ret = "(Data SLB Access)";
1387 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 case 0x400: ret = "(Instruction Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001389 case 0x480:
1390 if (radix_enabled())
1391 ret = "(Instruction Access Out of Range)";
1392 else
1393 ret = "(Instruction SLB Access)";
1394 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 case 0x500: ret = "(Hardware Interrupt)"; break;
1396 case 0x600: ret = "(Alignment)"; break;
1397 case 0x700: ret = "(Program Check)"; break;
1398 case 0x800: ret = "(FPU Unavailable)"; break;
1399 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001400 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1401 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 case 0xc00: ret = "(System Call)"; break;
1403 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001404 case 0xe40: ret = "(Emulation Assist)"; break;
1405 case 0xe60: ret = "(HMI)"; break;
1406 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 case 0xf00: ret = "(Performance Monitor)"; break;
1408 case 0xf20: ret = "(Altivec Unavailable)"; break;
1409 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001410 case 0x1500: ret = "(Denormalisation)"; break;
1411 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 default: ret = "";
1413 }
1414 return ret;
1415}
1416
1417static void get_function_bounds(unsigned long pc, unsigned long *startp,
1418 unsigned long *endp)
1419{
1420 unsigned long size, offset;
1421 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
1423 *startp = *endp = 0;
1424 if (pc == 0)
1425 return;
1426 if (setjmp(bus_error_jmp) == 0) {
1427 catch_memory_errors = 1;
1428 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001429 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 if (name != NULL) {
1431 *startp = pc - offset;
1432 *endp = pc - offset + size;
1433 }
1434 sync();
1435 }
1436 catch_memory_errors = 0;
1437}
1438
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001439#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1440#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1441
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442static void xmon_show_stack(unsigned long sp, unsigned long lr,
1443 unsigned long pc)
1444{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001445 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 unsigned long ip;
1447 unsigned long newsp;
1448 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 struct pt_regs regs;
1450
Michael Ellerman0104cd62012-10-09 04:20:36 +00001451 while (max_to_print--) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301452 if (!is_kernel_addr(sp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 if (sp != 0)
1454 printf("SP (%lx) is in userspace\n", sp);
1455 break;
1456 }
1457
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001458 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 || !mread(sp, &newsp, sizeof(unsigned long))) {
1460 printf("Couldn't read stack frame at %lx\n", sp);
1461 break;
1462 }
1463
1464 /*
1465 * For the first stack frame, try to work out if
1466 * LR and/or the saved LR value in the bottommost
1467 * stack frame are valid.
1468 */
1469 if ((pc | lr) != 0) {
1470 unsigned long fnstart, fnend;
1471 unsigned long nextip;
1472 int printip = 1;
1473
1474 get_function_bounds(pc, &fnstart, &fnend);
1475 nextip = 0;
1476 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001477 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 sizeof(unsigned long));
1479 if (lr == ip) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301480 if (!is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 || (fnstart <= lr && lr < fnend))
1482 printip = 0;
1483 } else if (lr == nextip) {
1484 printip = 0;
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301485 } else if (is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 && !(fnstart <= lr && lr < fnend)) {
1487 printf("[link register ] ");
1488 xmon_print_symbol(lr, " ", "\n");
1489 }
1490 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001491 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 xmon_print_symbol(ip, " ", " (unreliable)\n");
1493 }
1494 pc = lr = 0;
1495
1496 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001497 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 xmon_print_symbol(ip, " ", "\n");
1499 }
1500
1501 /* Look for "regshere" marker to see if this is
1502 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001503 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001504 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001505 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 != sizeof(regs)) {
1507 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001508 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 break;
1510 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001511 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 getvecname(TRAP(&regs)));
1513 pc = regs.nip;
1514 lr = regs.link;
1515 xmon_print_symbol(pc, " ", "\n");
1516 }
1517
1518 if (newsp == 0)
1519 break;
1520
1521 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523}
1524
1525static void backtrace(struct pt_regs *excp)
1526{
1527 unsigned long sp;
1528
1529 if (scanhex(&sp))
1530 xmon_show_stack(sp, 0, 0);
1531 else
1532 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1533 scannl();
1534}
1535
1536static void print_bug_trap(struct pt_regs *regs)
1537{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001538#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001539 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 unsigned long addr;
1541
1542 if (regs->msr & MSR_PR)
1543 return; /* not in kernel */
1544 addr = regs->nip; /* address of trap instruction */
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301545 if (!is_kernel_addr(addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 return;
1547 bug = find_bug(regs->nip);
1548 if (bug == NULL)
1549 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001550 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 return;
1552
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001553#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001554 printf("kernel BUG at %s:%u!\n",
1555 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001556#else
1557 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1558#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001559#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560}
1561
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001562static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563{
1564 unsigned long trap;
1565
1566#ifdef CONFIG_SMP
1567 printf("cpu 0x%x: ", smp_processor_id());
1568#endif /* CONFIG_SMP */
1569
1570 trap = TRAP(fp);
1571 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1572 printf(" pc: ");
1573 xmon_print_symbol(fp->nip, ": ", "\n");
1574
1575 printf(" lr: ", fp->link);
1576 xmon_print_symbol(fp->link, ": ", "\n");
1577
1578 printf(" sp: %lx\n", fp->gpr[1]);
1579 printf(" msr: %lx\n", fp->msr);
1580
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001581 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 printf(" dar: %lx\n", fp->dar);
1583 if (trap != 0x380)
1584 printf(" dsisr: %lx\n", fp->dsisr);
1585 }
1586
1587 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001588#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001589 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1590 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001591#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 if (current) {
1593 printf(" pid = %ld, comm = %s\n",
1594 current->pid, current->comm);
1595 }
1596
1597 if (trap == 0x700)
1598 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001599
1600 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601}
1602
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001603static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001605 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 unsigned long base;
1607 struct pt_regs regs;
1608
1609 if (scanhex(&base)) {
1610 if (setjmp(bus_error_jmp) == 0) {
1611 catch_memory_errors = 1;
1612 sync();
1613 regs = *(struct pt_regs *)base;
1614 sync();
1615 __delay(200);
1616 } else {
1617 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001618 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 base);
1620 return;
1621 }
1622 catch_memory_errors = 0;
1623 fp = &regs;
1624 }
1625
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001626#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 if (FULL_REGS(fp)) {
1628 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001629 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1631 } else {
1632 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001633 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1635 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001636#else
1637 for (n = 0; n < 32; ++n) {
1638 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1639 (n & 3) == 3? "\n": " ");
1640 if (n == 12 && !FULL_REGS(fp)) {
1641 printf("\n");
1642 break;
1643 }
1644 }
1645#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 printf("pc = ");
1647 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001648 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1649 printf("cfar= ");
1650 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 printf("lr = ");
1653 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001654 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1655 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001657 trap = TRAP(fp);
1658 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1659 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660}
1661
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001662static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663{
1664 int cmd;
1665 unsigned long nflush;
1666
1667 cmd = inchar();
1668 if (cmd != 'i')
1669 termch = cmd;
1670 scanhex((void *)&adrs);
1671 if (termch != '\n')
1672 termch = 0;
1673 nflush = 1;
1674 scanhex(&nflush);
1675 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1676 if (setjmp(bus_error_jmp) == 0) {
1677 catch_memory_errors = 1;
1678 sync();
1679
1680 if (cmd != 'i') {
1681 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1682 cflush((void *) adrs);
1683 } else {
1684 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1685 cinval((void *) adrs);
1686 }
1687 sync();
1688 /* wait a little while to see if we get a machine check */
1689 __delay(200);
1690 }
1691 catch_memory_errors = 0;
1692}
1693
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001694extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1695extern void xmon_mtspr(int spr, unsigned long value);
1696
1697static int
1698read_spr(int n, unsigned long *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 unsigned long ret = -1UL;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001701 int ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
1703 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001704 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 sync();
1706
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001707 ret = xmon_mfspr(n, *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
1709 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001710 *vp = ret;
1711 ok = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001713 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001715 return ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716}
1717
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001718static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719write_spr(int n, unsigned long val)
1720{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001722 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 sync();
1724
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001725 xmon_mtspr(n, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726
1727 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001728 } else {
1729 printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001731 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732}
1733
Michael Ellerman18461932016-07-07 22:54:29 +10001734static void dump_206_sprs(void)
1735{
1736#ifdef CONFIG_PPC64
1737 if (!cpu_has_feature(CPU_FTR_ARCH_206))
1738 return;
1739
1740 /* Actually some of these pre-date 2.06, but whatevs */
1741
Balbir Singhc47a9402017-08-29 17:22:36 +10001742 printf("srr0 = %.16lx srr1 = %.16lx dsisr = %.8x\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001743 mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001744 printf("dscr = %.16lx ppr = %.16lx pir = %.8x\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001745 mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
1746
1747 if (!(mfmsr() & MSR_HV))
1748 return;
1749
Balbir Singhc47a9402017-08-29 17:22:36 +10001750 printf("sdr1 = %.16lx hdar = %.16lx hdsisr = %.8x\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001751 mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001752 printf("hsrr0 = %.16lx hsrr1 = %.16lx hdec = %.8x\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001753 mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
Balbir Singhc47a9402017-08-29 17:22:36 +10001754 printf("lpcr = %.16lx pcr = %.16lx lpidr = %.8x\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001755 mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
Balbir Singhc47a9402017-08-29 17:22:36 +10001756 printf("hsprg0 = %.16lx hsprg1 = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001757 mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1));
Balbir Singhc47a9402017-08-29 17:22:36 +10001758 printf("dabr = %.16lx dabrx = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001759 mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
1760#endif
1761}
1762
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001763static void dump_207_sprs(void)
1764{
1765#ifdef CONFIG_PPC64
1766 unsigned long msr;
1767
1768 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
1769 return;
1770
Balbir Singhc47a9402017-08-29 17:22:36 +10001771 printf("dpdes = %.16lx tir = %.16lx cir = %.8x\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001772 mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
1773
Balbir Singhc47a9402017-08-29 17:22:36 +10001774 printf("fscr = %.16lx tar = %.16lx pspb = %.8x\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001775 mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
1776
1777 msr = mfmsr();
1778 if (msr & MSR_TM) {
1779 /* Only if TM has been enabled in the kernel */
Balbir Singhc47a9402017-08-29 17:22:36 +10001780 printf("tfhar = %.16lx tfiar = %.16lx texasr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001781 mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
1782 mfspr(SPRN_TEXASR));
1783 }
1784
Balbir Singhc47a9402017-08-29 17:22:36 +10001785 printf("mmcr0 = %.16lx mmcr1 = %.16lx mmcr2 = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001786 mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
1787 printf("pmc1 = %.8x pmc2 = %.8x pmc3 = %.8x pmc4 = %.8x\n",
1788 mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
1789 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
Balbir Singhc47a9402017-08-29 17:22:36 +10001790 printf("mmcra = %.16lx siar = %.16lx pmc5 = %.8x\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001791 mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
Balbir Singhc47a9402017-08-29 17:22:36 +10001792 printf("sdar = %.16lx sier = %.16lx pmc6 = %.8x\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001793 mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
Balbir Singhc47a9402017-08-29 17:22:36 +10001794 printf("ebbhr = %.16lx ebbrr = %.16lx bescr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001795 mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
1796
1797 if (!(msr & MSR_HV))
1798 return;
1799
Balbir Singhc47a9402017-08-29 17:22:36 +10001800 printf("hfscr = %.16lx dhdes = %.16lx rpr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001801 mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001802 printf("dawr = %.16lx dawrx = %.16lx ciabr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001803 mfspr(SPRN_DAWR), mfspr(SPRN_DAWRX), mfspr(SPRN_CIABR));
1804#endif
1805}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001807static void dump_one_spr(int spr, bool show_unimplemented)
1808{
1809 unsigned long val;
1810
1811 val = 0xdeadbeef;
1812 if (!read_spr(spr, &val)) {
1813 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1814 return;
1815 }
1816
1817 if (val == 0xdeadbeef) {
1818 /* Looks like read was a nop, confirm */
1819 val = 0x0badcafe;
1820 if (!read_spr(spr, &val)) {
1821 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1822 return;
1823 }
1824
1825 if (val == 0x0badcafe) {
1826 if (show_unimplemented)
1827 printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
1828 return;
1829 }
1830 }
1831
1832 printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
1833}
1834
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001835static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836{
Michael Ellerman13629da2016-07-07 22:54:27 +10001837 static unsigned long regno;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 int cmd;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001839 int spr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840
1841 cmd = skipbl();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001842
1843 switch (cmd) {
1844 case '\n': {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001845 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 asm("mr %0,1" : "=r" (sp) :);
1847 asm("mr %0,2" : "=r" (toc) :);
1848
Michael Ellerman56346ad2016-07-07 22:54:28 +10001849 printf("msr = "REG" sprg0 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001850 mfmsr(), mfspr(SPRN_SPRG0));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001851 printf("pvr = "REG" sprg1 = "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001852 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001853 printf("dec = "REG" sprg2 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001854 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001855 printf("sp = "REG" sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
1856 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
1857
Michael Ellerman18461932016-07-07 22:54:29 +10001858 dump_206_sprs();
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001859 dump_207_sprs();
Michael Ellerman18461932016-07-07 22:54:29 +10001860
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 return;
1862 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001863 case 'w': {
1864 unsigned long val;
1865 scanhex(&regno);
1866 val = 0;
1867 read_spr(regno, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 scanhex(&val);
1869 write_spr(regno, val);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001870 dump_one_spr(regno, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001873 case 'r':
1874 scanhex(&regno);
1875 dump_one_spr(regno, true);
1876 break;
1877 case 'a':
1878 /* dump ALL SPRs */
1879 for (spr = 1; spr < 1024; ++spr)
1880 dump_one_spr(spr, false);
1881 break;
1882 }
1883
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 scannl();
1885}
1886
1887/*
1888 * Stuff for reading and writing memory safely
1889 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001890static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891mread(unsigned long adrs, void *buf, int size)
1892{
1893 volatile int n;
1894 char *p, *q;
1895
1896 n = 0;
1897 if (setjmp(bus_error_jmp) == 0) {
1898 catch_memory_errors = 1;
1899 sync();
1900 p = (char *)adrs;
1901 q = (char *)buf;
1902 switch (size) {
1903 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001904 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 break;
1906 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001907 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 break;
1909 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001910 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 break;
1912 default:
1913 for( ; n < size; ++n) {
1914 *q++ = *p++;
1915 sync();
1916 }
1917 }
1918 sync();
1919 /* wait a little while to see if we get a machine check */
1920 __delay(200);
1921 n = size;
1922 }
1923 catch_memory_errors = 0;
1924 return n;
1925}
1926
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001927static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928mwrite(unsigned long adrs, void *buf, int size)
1929{
1930 volatile int n;
1931 char *p, *q;
1932
1933 n = 0;
1934 if (setjmp(bus_error_jmp) == 0) {
1935 catch_memory_errors = 1;
1936 sync();
1937 p = (char *) adrs;
1938 q = (char *) buf;
1939 switch (size) {
1940 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001941 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 break;
1943 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001944 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 break;
1946 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001947 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 break;
1949 default:
1950 for ( ; n < size; ++n) {
1951 *p++ = *q++;
1952 sync();
1953 }
1954 }
1955 sync();
1956 /* wait a little while to see if we get a machine check */
1957 __delay(200);
1958 n = size;
1959 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10001960 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 }
1962 catch_memory_errors = 0;
1963 return n;
1964}
1965
1966static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001967static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968static char *fault_chars[] = { "--", "**", "##" };
1969
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001970static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001972 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 switch (TRAP(regs)) {
1974 case 0x200:
1975 fault_type = 0;
1976 break;
1977 case 0x300:
1978 case 0x380:
1979 fault_type = 1;
1980 break;
1981 default:
1982 fault_type = 2;
1983 }
1984
1985 longjmp(bus_error_jmp, 1);
1986
1987 return 0;
1988}
1989
1990#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1991
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001992static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993byterev(unsigned char *val, int size)
1994{
1995 int t;
1996
1997 switch (size) {
1998 case 2:
1999 SWAP(val[0], val[1], t);
2000 break;
2001 case 4:
2002 SWAP(val[0], val[3], t);
2003 SWAP(val[1], val[2], t);
2004 break;
2005 case 8: /* is there really any use for this? */
2006 SWAP(val[0], val[7], t);
2007 SWAP(val[1], val[6], t);
2008 SWAP(val[2], val[5], t);
2009 SWAP(val[3], val[4], t);
2010 break;
2011 }
2012}
2013
2014static int brev;
2015static int mnoread;
2016
Michael Ellermane3bc8042012-08-23 22:09:13 +00002017static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 "Memory examine command usage:\n"
2019 "m [addr] [flags] examine/change memory\n"
2020 " addr is optional. will start where left off.\n"
2021 " flags may include chars from this set:\n"
2022 " b modify by bytes (default)\n"
2023 " w modify by words (2 byte)\n"
2024 " l modify by longs (4 byte)\n"
2025 " d modify by doubleword (8 byte)\n"
2026 " r toggle reverse byte order mode\n"
2027 " n do not read memory (for i/o spaces)\n"
2028 " . ok to read (default)\n"
2029 "NOTE: flags are saved as defaults\n"
2030 "";
2031
Michael Ellermane3bc8042012-08-23 22:09:13 +00002032static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 "Memory examine subcommands:\n"
2034 " hexval write this val to current location\n"
2035 " 'string' write chars from string to this location\n"
2036 " ' increment address\n"
2037 " ^ decrement address\n"
2038 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
2039 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
2040 " ` clear no-read flag\n"
2041 " ; stay at this addr\n"
2042 " v change to byte mode\n"
2043 " w change to word (2 byte) mode\n"
2044 " l change to long (4 byte) mode\n"
2045 " u change to doubleword (8 byte) mode\n"
2046 " m addr change current addr\n"
2047 " n toggle no-read flag\n"
2048 " r toggle byte reverse flag\n"
2049 " < count back up count bytes\n"
2050 " > count skip forward count bytes\n"
2051 " x exit this mode\n"
2052 "";
2053
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002054static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055memex(void)
2056{
2057 int cmd, inc, i, nslash;
2058 unsigned long n;
2059 unsigned char val[16];
2060
2061 scanhex((void *)&adrs);
2062 cmd = skipbl();
2063 if (cmd == '?') {
2064 printf(memex_help_string);
2065 return;
2066 } else {
2067 termch = cmd;
2068 }
2069 last_cmd = "m\n";
2070 while ((cmd = skipbl()) != '\n') {
2071 switch( cmd ){
2072 case 'b': size = 1; break;
2073 case 'w': size = 2; break;
2074 case 'l': size = 4; break;
2075 case 'd': size = 8; break;
2076 case 'r': brev = !brev; break;
2077 case 'n': mnoread = 1; break;
2078 case '.': mnoread = 0; break;
2079 }
2080 }
2081 if( size <= 0 )
2082 size = 1;
2083 else if( size > 8 )
2084 size = 8;
2085 for(;;){
2086 if (!mnoread)
2087 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002088 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 if (!mnoread) {
2090 if (brev)
2091 byterev(val, size);
2092 putchar(' ');
2093 for (i = 0; i < n; ++i)
2094 printf("%.2x", val[i]);
2095 for (; i < size; ++i)
2096 printf("%s", fault_chars[fault_type]);
2097 }
2098 putchar(' ');
2099 inc = size;
2100 nslash = 0;
2101 for(;;){
2102 if( scanhex(&n) ){
2103 for (i = 0; i < size; ++i)
2104 val[i] = n >> (i * 8);
2105 if (!brev)
2106 byterev(val, size);
2107 mwrite(adrs, val, size);
2108 inc = size;
2109 }
2110 cmd = skipbl();
2111 if (cmd == '\n')
2112 break;
2113 inc = 0;
2114 switch (cmd) {
2115 case '\'':
2116 for(;;){
2117 n = inchar();
2118 if( n == '\\' )
2119 n = bsesc();
2120 else if( n == '\'' )
2121 break;
2122 for (i = 0; i < size; ++i)
2123 val[i] = n >> (i * 8);
2124 if (!brev)
2125 byterev(val, size);
2126 mwrite(adrs, val, size);
2127 adrs += size;
2128 }
2129 adrs -= size;
2130 inc = size;
2131 break;
2132 case ',':
2133 adrs += size;
2134 break;
2135 case '.':
2136 mnoread = 0;
2137 break;
2138 case ';':
2139 break;
2140 case 'x':
2141 case EOF:
2142 scannl();
2143 return;
2144 case 'b':
2145 case 'v':
2146 size = 1;
2147 break;
2148 case 'w':
2149 size = 2;
2150 break;
2151 case 'l':
2152 size = 4;
2153 break;
2154 case 'u':
2155 size = 8;
2156 break;
2157 case '^':
2158 adrs -= size;
2159 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 case '/':
2161 if (nslash > 0)
2162 adrs -= 1 << nslash;
2163 else
2164 nslash = 0;
2165 nslash += 4;
2166 adrs += 1 << nslash;
2167 break;
2168 case '\\':
2169 if (nslash < 0)
2170 adrs += 1 << -nslash;
2171 else
2172 nslash = 0;
2173 nslash -= 4;
2174 adrs -= 1 << -nslash;
2175 break;
2176 case 'm':
2177 scanhex((void *)&adrs);
2178 break;
2179 case 'n':
2180 mnoread = 1;
2181 break;
2182 case 'r':
2183 brev = !brev;
2184 break;
2185 case '<':
2186 n = size;
2187 scanhex(&n);
2188 adrs -= n;
2189 break;
2190 case '>':
2191 n = size;
2192 scanhex(&n);
2193 adrs += n;
2194 break;
2195 case '?':
2196 printf(memex_subcmd_help_string);
2197 break;
2198 }
2199 }
2200 adrs += inc;
2201 }
2202}
2203
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002204static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205bsesc(void)
2206{
2207 int c;
2208
2209 c = inchar();
2210 switch( c ){
2211 case 'n': c = '\n'; break;
2212 case 'r': c = '\r'; break;
2213 case 'b': c = '\b'; break;
2214 case 't': c = '\t'; break;
2215 }
2216 return c;
2217}
2218
Olaf Hering7e5b5932006-03-08 20:40:28 +01002219static void xmon_rawdump (unsigned long adrs, long ndump)
2220{
2221 long n, m, r, nr;
2222 unsigned char temp[16];
2223
2224 for (n = ndump; n > 0;) {
2225 r = n < 16? n: 16;
2226 nr = mread(adrs, temp, r);
2227 adrs += nr;
2228 for (m = 0; m < r; ++m) {
2229 if (m < nr)
2230 printf("%.2x", temp[m]);
2231 else
2232 printf("%s", fault_chars[fault_type]);
2233 }
2234 n -= r;
2235 if (nr < r)
2236 break;
2237 }
2238 printf("\n");
2239}
2240
Breno Leitao4125d012017-08-02 17:14:05 -03002241static void dump_tracing(void)
2242{
2243 int c;
2244
2245 c = inchar();
2246 if (c == 'c')
2247 ftrace_dump(DUMP_ORIG);
2248 else
2249 ftrace_dump(DUMP_ALL);
Breno Leitao4125d012017-08-02 17:14:05 -03002250}
2251
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002252#ifdef CONFIG_PPC64
2253static void dump_one_paca(int cpu)
2254{
2255 struct paca_struct *p;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002256#ifdef CONFIG_PPC_STD_MMU_64
2257 int i = 0;
2258#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002259
2260 if (setjmp(bus_error_jmp) != 0) {
2261 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2262 return;
2263 }
2264
2265 catch_memory_errors = 1;
2266 sync();
2267
2268 p = &paca[cpu];
2269
2270 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2271
Michael Ellermanad987fc2015-10-14 16:58:36 +11002272 printf(" %-*s = %s\n", 20, "possible", cpu_possible(cpu) ? "yes" : "no");
2273 printf(" %-*s = %s\n", 20, "present", cpu_present(cpu) ? "yes" : "no");
2274 printf(" %-*s = %s\n", 20, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002275
2276#define DUMP(paca, name, format) \
Michael Ellermanad987fc2015-10-14 16:58:36 +11002277 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 20, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002278 offsetof(struct paca_struct, name));
2279
2280 DUMP(p, lock_token, "x");
2281 DUMP(p, paca_index, "x");
2282 DUMP(p, kernel_toc, "lx");
2283 DUMP(p, kernelbase, "lx");
2284 DUMP(p, kernel_msr, "lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002285 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302286#ifdef CONFIG_PPC_BOOK3S_64
Nicholas Pigginb1ee8a32016-12-20 04:30:06 +10002287 DUMP(p, nmi_emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302288 DUMP(p, mc_emergency_sp, "p");
Nicholas Pigginc4f3b522016-12-20 04:30:05 +10002289 DUMP(p, in_nmi, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302290 DUMP(p, in_mce, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002291 DUMP(p, hmi_event_available, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302292#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002293 DUMP(p, data_offset, "lx");
2294 DUMP(p, hw_cpu_id, "x");
2295 DUMP(p, cpu_start, "x");
2296 DUMP(p, kexec_state, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002297#ifdef CONFIG_PPC_STD_MMU_64
2298 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2299 u64 esid, vsid;
2300
2301 if (!p->slb_shadow_ptr)
2302 continue;
2303
2304 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2305 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
2306
2307 if (esid || vsid) {
2308 printf(" slb_shadow[%d]: = 0x%016lx 0x%016lx\n",
2309 i, esid, vsid);
2310 }
2311 }
2312 DUMP(p, vmalloc_sllp, "x");
2313 DUMP(p, slb_cache_ptr, "x");
2314 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2315 printf(" slb_cache[%d]: = 0x%016lx\n", i, p->slb_cache[i]);
2316#endif
2317 DUMP(p, dscr_default, "llx");
2318#ifdef CONFIG_PPC_BOOK3E
2319 DUMP(p, pgd, "p");
2320 DUMP(p, kernel_pgd, "p");
2321 DUMP(p, tcd_ptr, "p");
2322 DUMP(p, mc_kstack, "p");
2323 DUMP(p, crit_kstack, "p");
2324 DUMP(p, dbg_kstack, "p");
2325#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002326 DUMP(p, __current, "p");
2327 DUMP(p, kstack, "lx");
2328 DUMP(p, stab_rr, "lx");
2329 DUMP(p, saved_r1, "lx");
2330 DUMP(p, trap_save, "x");
2331 DUMP(p, soft_enabled, "x");
2332 DUMP(p, irq_happened, "x");
2333 DUMP(p, io_sync, "x");
2334 DUMP(p, irq_work_pending, "x");
2335 DUMP(p, nap_state_lost, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002336 DUMP(p, sprg_vdso, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002337
Michael Ellermanad987fc2015-10-14 16:58:36 +11002338#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
2339 DUMP(p, tm_scratch, "llx");
2340#endif
2341
2342#ifdef CONFIG_PPC_POWERNV
2343 DUMP(p, core_idle_state_ptr, "p");
2344 DUMP(p, thread_idle_state, "x");
2345 DUMP(p, thread_mask, "x");
2346 DUMP(p, subcore_sibling_mask, "x");
2347#endif
2348
Frederic Weisbecker8c8b73c2017-01-05 18:11:45 +01002349 DUMP(p, accounting.utime, "llx");
2350 DUMP(p, accounting.stime, "llx");
2351 DUMP(p, accounting.utime_scaled, "llx");
Christophe Leroyc223c902016-05-17 08:33:46 +02002352 DUMP(p, accounting.starttime, "llx");
2353 DUMP(p, accounting.starttime_user, "llx");
2354 DUMP(p, accounting.startspurr, "llx");
2355 DUMP(p, accounting.utime_sspurr, "llx");
Frederic Weisbeckerf828c3d2017-01-05 18:11:46 +01002356 DUMP(p, accounting.steal_time, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002357#undef DUMP
2358
2359 catch_memory_errors = 0;
2360 sync();
2361}
2362
2363static void dump_all_pacas(void)
2364{
2365 int cpu;
2366
2367 if (num_possible_cpus() == 0) {
2368 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2369 return;
2370 }
2371
2372 for_each_possible_cpu(cpu)
2373 dump_one_paca(cpu);
2374}
2375
2376static void dump_pacas(void)
2377{
2378 unsigned long num;
2379 int c;
2380
2381 c = inchar();
2382 if (c == 'a') {
2383 dump_all_pacas();
2384 return;
2385 }
2386
2387 termch = c; /* Put c back, it wasn't 'a' */
2388
2389 if (scanhex(&num))
2390 dump_one_paca(num);
2391 else
2392 dump_one_paca(xmon_owner);
2393}
2394#endif
2395
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002396#ifdef CONFIG_PPC_POWERNV
2397static void dump_one_xive(int cpu)
2398{
2399 unsigned int hwid = get_hard_smp_processor_id(cpu);
2400
2401 opal_xive_dump(XIVE_DUMP_TM_HYP, hwid);
2402 opal_xive_dump(XIVE_DUMP_TM_POOL, hwid);
2403 opal_xive_dump(XIVE_DUMP_TM_OS, hwid);
2404 opal_xive_dump(XIVE_DUMP_TM_USER, hwid);
2405 opal_xive_dump(XIVE_DUMP_VP, hwid);
2406 opal_xive_dump(XIVE_DUMP_EMU_STATE, hwid);
2407
2408 if (setjmp(bus_error_jmp) != 0) {
2409 catch_memory_errors = 0;
2410 printf("*** Error dumping xive on cpu %d\n", cpu);
2411 return;
2412 }
2413
2414 catch_memory_errors = 1;
2415 sync();
2416 xmon_xive_do_dump(cpu);
2417 sync();
2418 __delay(200);
2419 catch_memory_errors = 0;
2420}
2421
2422static void dump_all_xives(void)
2423{
2424 int cpu;
2425
2426 if (num_possible_cpus() == 0) {
2427 printf("No possible cpus, use 'dx #' to dump individual cpus\n");
2428 return;
2429 }
2430
2431 for_each_possible_cpu(cpu)
2432 dump_one_xive(cpu);
2433}
2434
2435static void dump_one_xive_irq(u32 num)
2436{
2437 s64 rc;
2438 __be64 vp;
2439 u8 prio;
2440 __be32 lirq;
2441
2442 rc = opal_xive_get_irq_config(num, &vp, &prio, &lirq);
2443 xmon_printf("IRQ 0x%x config: vp=0x%llx prio=%d lirq=0x%x (rc=%lld)\n",
2444 num, be64_to_cpu(vp), prio, be32_to_cpu(lirq), rc);
2445}
2446
2447static void dump_xives(void)
2448{
2449 unsigned long num;
2450 int c;
2451
2452 c = inchar();
2453 if (c == 'a') {
2454 dump_all_xives();
2455 return;
2456 } else if (c == 'i') {
2457 if (scanhex(&num))
2458 dump_one_xive_irq(num);
2459 return;
2460 }
2461
2462 termch = c; /* Put c back, it wasn't 'a' */
2463
2464 if (scanhex(&num))
2465 dump_one_xive(num);
2466 else
2467 dump_one_xive(xmon_owner);
2468}
2469#endif /* CONFIG_PPC_POWERNV */
2470
Douglas Miller5e48dc02017-02-07 07:40:44 -06002471static void dump_by_size(unsigned long addr, long count, int size)
2472{
2473 unsigned char temp[16];
2474 int i, j;
2475 u64 val;
2476
2477 count = ALIGN(count, 16);
2478
2479 for (i = 0; i < count; i += 16, addr += 16) {
2480 printf(REG, addr);
2481
2482 if (mread(addr, temp, 16) != 16) {
2483 printf("\nFaulted reading %d bytes from 0x"REG"\n", 16, addr);
2484 return;
2485 }
2486
2487 for (j = 0; j < 16; j += size) {
2488 putchar(' ');
2489 switch (size) {
2490 case 1: val = temp[j]; break;
2491 case 2: val = *(u16 *)&temp[j]; break;
2492 case 4: val = *(u32 *)&temp[j]; break;
2493 case 8: val = *(u64 *)&temp[j]; break;
2494 default: val = 0;
2495 }
2496
2497 printf("%0*lx", size * 2, val);
2498 }
2499 printf("\n");
2500 }
2501}
2502
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002503static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504dump(void)
2505{
Douglas Miller5e48dc02017-02-07 07:40:44 -06002506 static char last[] = { "d?\n" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 int c;
2508
2509 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002510
2511#ifdef CONFIG_PPC64
2512 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002513 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002514 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002515 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002516 return;
2517 }
2518#endif
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002519#ifdef CONFIG_PPC_POWERNV
2520 if (c == 'x') {
2521 xmon_start_pagination();
2522 dump_xives();
2523 xmon_end_pagination();
2524 return;
2525 }
2526#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002527
Breno Leitao4125d012017-08-02 17:14:05 -03002528 if (c == 't') {
2529 dump_tracing();
2530 return;
2531 }
2532
Douglas Miller5e48dc02017-02-07 07:40:44 -06002533 if (c == '\n')
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 termch = c;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002535
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 scanhex((void *)&adrs);
2537 if (termch != '\n')
2538 termch = 0;
2539 if (c == 'i') {
2540 scanhex(&nidump);
2541 if (nidump == 0)
2542 nidump = 16;
2543 else if (nidump > MAX_DUMP)
2544 nidump = MAX_DUMP;
2545 adrs += ppc_inst_dump(adrs, nidump, 1);
2546 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002547 } else if (c == 'l') {
2548 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002549 } else if (c == 'o') {
2550 dump_opal_msglog();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002551 } else if (c == 'r') {
2552 scanhex(&ndump);
2553 if (ndump == 0)
2554 ndump = 64;
2555 xmon_rawdump(adrs, ndump);
2556 adrs += ndump;
2557 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 } else {
2559 scanhex(&ndump);
2560 if (ndump == 0)
2561 ndump = 64;
2562 else if (ndump > MAX_DUMP)
2563 ndump = MAX_DUMP;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002564
2565 switch (c) {
2566 case '8':
2567 case '4':
2568 case '2':
2569 case '1':
2570 ndump = ALIGN(ndump, 16);
2571 dump_by_size(adrs, ndump, c - '0');
2572 last[1] = c;
2573 last_cmd = last;
2574 break;
2575 default:
2576 prdump(adrs, ndump);
2577 last_cmd = "d\n";
2578 }
2579
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 adrs += ndump;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 }
2582}
2583
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002584static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585prdump(unsigned long adrs, long ndump)
2586{
2587 long n, m, c, r, nr;
2588 unsigned char temp[16];
2589
2590 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002591 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 putchar(' ');
2593 r = n < 16? n: 16;
2594 nr = mread(adrs, temp, r);
2595 adrs += nr;
2596 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002597 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002598 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 if (m < nr)
2600 printf("%.2x", temp[m]);
2601 else
2602 printf("%s", fault_chars[fault_type]);
2603 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002604 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002605 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002606 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 printf(" |");
2610 for (m = 0; m < r; ++m) {
2611 if (m < nr) {
2612 c = temp[m];
2613 putchar(' ' <= c && c <= '~'? c: '.');
2614 } else
2615 putchar(' ');
2616 }
2617 n -= r;
2618 for (; m < 16; ++m)
2619 putchar(' ');
2620 printf("|\n");
2621 if (nr < r)
2622 break;
2623 }
2624}
2625
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002626typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2627
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002628static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002629generic_inst_dump(unsigned long adr, long count, int praddr,
2630 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631{
2632 int nr, dotted;
2633 unsigned long first_adr;
2634 unsigned long inst, last_inst = 0;
2635 unsigned char val[4];
2636
2637 dotted = 0;
2638 for (first_adr = adr; count > 0; --count, adr += 4) {
2639 nr = mread(adr, val, 4);
2640 if (nr == 0) {
2641 if (praddr) {
2642 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002643 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 }
2645 break;
2646 }
2647 inst = GETWORD(val);
2648 if (adr > first_adr && inst == last_inst) {
2649 if (!dotted) {
2650 printf(" ...\n");
2651 dotted = 1;
2652 }
2653 continue;
2654 }
2655 dotted = 0;
2656 last_inst = inst;
2657 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002658 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002660 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 printf("\n");
2662 }
2663 return adr - first_adr;
2664}
2665
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002666static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002667ppc_inst_dump(unsigned long adr, long count, int praddr)
2668{
2669 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2670}
2671
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672void
2673print_address(unsigned long addr)
2674{
2675 xmon_print_symbol(addr, "\t# ", "");
2676}
2677
Vinay Sridharf312deb2009-05-14 23:13:07 +00002678void
2679dump_log_buf(void)
2680{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002681 struct kmsg_dumper dumper = { .active = 1 };
2682 unsigned char buf[128];
2683 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002684
Michael Ellermane3bc8042012-08-23 22:09:13 +00002685 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002686 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002687 return;
2688 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002689
Michael Ellermane3bc8042012-08-23 22:09:13 +00002690 catch_memory_errors = 1;
2691 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002692
Michael Ellermanca5dd392012-08-23 22:09:12 +00002693 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002694 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002695 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2696 buf[len] = '\0';
2697 printf("%s", buf);
2698 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002699 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002700
Michael Ellermane3bc8042012-08-23 22:09:13 +00002701 sync();
2702 /* wait a little while to see if we get a machine check */
2703 __delay(200);
2704 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002705}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002707#ifdef CONFIG_PPC_POWERNV
2708static void dump_opal_msglog(void)
2709{
2710 unsigned char buf[128];
2711 ssize_t res;
2712 loff_t pos = 0;
2713
2714 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2715 printf("Machine is not running OPAL firmware.\n");
2716 return;
2717 }
2718
2719 if (setjmp(bus_error_jmp) != 0) {
2720 printf("Error dumping OPAL msglog!\n");
2721 return;
2722 }
2723
2724 catch_memory_errors = 1;
2725 sync();
2726
2727 xmon_start_pagination();
2728 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2729 if (res < 0) {
2730 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2731 break;
2732 }
2733 buf[res] = '\0';
2734 printf("%s", buf);
2735 pos += res;
2736 }
2737 xmon_end_pagination();
2738
2739 sync();
2740 /* wait a little while to see if we get a machine check */
2741 __delay(200);
2742 catch_memory_errors = 0;
2743}
2744#endif
2745
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746/*
2747 * Memory operations - move, set, print differences
2748 */
2749static unsigned long mdest; /* destination address */
2750static unsigned long msrc; /* source address */
2751static unsigned long mval; /* byte value to set memory to */
2752static unsigned long mcount; /* # bytes to affect */
2753static unsigned long mdiffs; /* max # differences to print */
2754
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002755static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756memops(int cmd)
2757{
2758 scanhex((void *)&mdest);
2759 if( termch != '\n' )
2760 termch = 0;
2761 scanhex((void *)(cmd == 's'? &mval: &msrc));
2762 if( termch != '\n' )
2763 termch = 0;
2764 scanhex((void *)&mcount);
2765 switch( cmd ){
2766 case 'm':
2767 memmove((void *)mdest, (void *)msrc, mcount);
2768 break;
2769 case 's':
2770 memset((void *)mdest, mval, mcount);
2771 break;
2772 case 'd':
2773 if( termch != '\n' )
2774 termch = 0;
2775 scanhex((void *)&mdiffs);
2776 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2777 break;
2778 }
2779}
2780
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002781static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2783{
2784 unsigned n, prt;
2785
2786 prt = 0;
2787 for( n = nb; n > 0; --n )
2788 if( *p1++ != *p2++ )
2789 if( ++prt <= maxpr )
2790 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2791 p1[-1], p2 - 1, p2[-1]);
2792 if( prt > maxpr )
2793 printf("Total of %d differences\n", prt);
2794}
2795
2796static unsigned mend;
2797static unsigned mask;
2798
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002799static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800memlocate(void)
2801{
2802 unsigned a, n;
2803 unsigned char val[4];
2804
2805 last_cmd = "ml";
2806 scanhex((void *)&mdest);
2807 if (termch != '\n') {
2808 termch = 0;
2809 scanhex((void *)&mend);
2810 if (termch != '\n') {
2811 termch = 0;
2812 scanhex((void *)&mval);
2813 mask = ~0;
2814 if (termch != '\n') termch = 0;
2815 scanhex((void *)&mask);
2816 }
2817 }
2818 n = 0;
2819 for (a = mdest; a < mend; a += 4) {
2820 if (mread(a, val, 4) == 4
2821 && ((GETWORD(val) ^ mval) & mask) == 0) {
2822 printf("%.16x: %.16x\n", a, GETWORD(val));
2823 if (++n >= 10)
2824 break;
2825 }
2826 }
2827}
2828
2829static unsigned long mskip = 0x1000;
2830static unsigned long mlim = 0xffffffff;
2831
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002832static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833memzcan(void)
2834{
2835 unsigned char v;
2836 unsigned a;
2837 int ok, ook;
2838
2839 scanhex(&mdest);
2840 if (termch != '\n') termch = 0;
2841 scanhex(&mskip);
2842 if (termch != '\n') termch = 0;
2843 scanhex(&mlim);
2844 ook = 0;
2845 for (a = mdest; a < mlim; a += mskip) {
2846 ok = mread(a, &v, 1);
2847 if (ok && !ook) {
2848 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 } else if (!ok && ook)
2850 printf("%.8x\n", a - mskip);
2851 ook = ok;
2852 if (a + mskip < a)
2853 break;
2854 }
2855 if (ook)
2856 printf("%.8x\n", a - mskip);
2857}
2858
Douglas Miller6dfb5402015-11-23 09:01:15 -06002859static void show_task(struct task_struct *tsk)
2860{
2861 char state;
2862
2863 /*
2864 * Cloned from kdb_task_state_char(), which is not entirely
2865 * appropriate for calling from xmon. This could be moved
2866 * to a common, generic, routine used by both.
2867 */
2868 state = (tsk->state == 0) ? 'R' :
2869 (tsk->state < 0) ? 'U' :
2870 (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
2871 (tsk->state & TASK_STOPPED) ? 'T' :
2872 (tsk->state & TASK_TRACED) ? 'C' :
2873 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
2874 (tsk->exit_state & EXIT_DEAD) ? 'E' :
2875 (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
2876
2877 printf("%p %016lx %6d %6d %c %2d %s\n", tsk,
2878 tsk->thread.ksp,
2879 tsk->pid, tsk->parent->pid,
2880 state, task_thread_info(tsk)->cpu,
2881 tsk->comm);
2882}
2883
2884static void show_tasks(void)
2885{
2886 unsigned long tskv;
2887 struct task_struct *tsk = NULL;
2888
2889 printf(" task_struct ->thread.ksp PID PPID S P CMD\n");
2890
2891 if (scanhex(&tskv))
2892 tsk = (struct task_struct *)tskv;
2893
2894 if (setjmp(bus_error_jmp) != 0) {
2895 catch_memory_errors = 0;
2896 printf("*** Error dumping task %p\n", tsk);
2897 return;
2898 }
2899
2900 catch_memory_errors = 1;
2901 sync();
2902
2903 if (tsk)
2904 show_task(tsk);
2905 else
2906 for_each_process(tsk)
2907 show_task(tsk);
2908
2909 sync();
2910 __delay(200);
2911 catch_memory_errors = 0;
2912}
2913
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002914static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002915{
2916 unsigned long args[8];
2917 unsigned long ret;
2918 int i;
2919 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2920 unsigned long, unsigned long, unsigned long,
2921 unsigned long, unsigned long, unsigned long);
2922 callfunc_t func;
2923
2924 if (!scanhex(&adrs))
2925 return;
2926 if (termch != '\n')
2927 termch = 0;
2928 for (i = 0; i < 8; ++i)
2929 args[i] = 0;
2930 for (i = 0; i < 8; ++i) {
2931 if (!scanhex(&args[i]) || termch == '\n')
2932 break;
2933 termch = 0;
2934 }
2935 func = (callfunc_t) adrs;
2936 ret = 0;
2937 if (setjmp(bus_error_jmp) == 0) {
2938 catch_memory_errors = 1;
2939 sync();
2940 ret = func(args[0], args[1], args[2], args[3],
2941 args[4], args[5], args[6], args[7]);
2942 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10002943 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002944 } else {
2945 printf("*** %x exception occurred\n", fault_except);
2946 }
2947 catch_memory_errors = 0;
2948}
2949
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950/* Input scanning routines */
2951int
2952skipbl(void)
2953{
2954 int c;
2955
2956 if( termch != 0 ){
2957 c = termch;
2958 termch = 0;
2959 } else
2960 c = inchar();
2961 while( c == ' ' || c == '\t' )
2962 c = inchar();
2963 return c;
2964}
2965
2966#define N_PTREGS 44
2967static char *regnames[N_PTREGS] = {
2968 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2969 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2970 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2971 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002972 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2973#ifdef CONFIG_PPC64
2974 "softe",
2975#else
2976 "mq",
2977#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 "trap", "dar", "dsisr", "res"
2979};
2980
2981int
2982scanhex(unsigned long *vp)
2983{
2984 int c, d;
2985 unsigned long v;
2986
2987 c = skipbl();
2988 if (c == '%') {
2989 /* parse register name */
2990 char regname[8];
2991 int i;
2992
2993 for (i = 0; i < sizeof(regname) - 1; ++i) {
2994 c = inchar();
2995 if (!isalnum(c)) {
2996 termch = c;
2997 break;
2998 }
2999 regname[i] = c;
3000 }
3001 regname[i] = 0;
3002 for (i = 0; i < N_PTREGS; ++i) {
3003 if (strcmp(regnames[i], regname) == 0) {
3004 if (xmon_regs == NULL) {
3005 printf("regs not available\n");
3006 return 0;
3007 }
3008 *vp = ((unsigned long *)xmon_regs)[i];
3009 return 1;
3010 }
3011 }
3012 printf("invalid register name '%%%s'\n", regname);
3013 return 0;
3014 }
3015
3016 /* skip leading "0x" if any */
3017
3018 if (c == '0') {
3019 c = inchar();
3020 if (c == 'x') {
3021 c = inchar();
3022 } else {
3023 d = hexdigit(c);
3024 if (d == EOF) {
3025 termch = c;
3026 *vp = 0;
3027 return 1;
3028 }
3029 }
3030 } else if (c == '$') {
3031 int i;
3032 for (i=0; i<63; i++) {
3033 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02003034 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 termch = c;
3036 break;
3037 }
3038 tmpstr[i] = c;
3039 }
3040 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07003041 *vp = 0;
3042 if (setjmp(bus_error_jmp) == 0) {
3043 catch_memory_errors = 1;
3044 sync();
3045 *vp = kallsyms_lookup_name(tmpstr);
3046 sync();
3047 }
3048 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 if (!(*vp)) {
3050 printf("unknown symbol '%s'\n", tmpstr);
3051 return 0;
3052 }
3053 return 1;
3054 }
3055
3056 d = hexdigit(c);
3057 if (d == EOF) {
3058 termch = c;
3059 return 0;
3060 }
3061 v = 0;
3062 do {
3063 v = (v << 4) + d;
3064 c = inchar();
3065 d = hexdigit(c);
3066 } while (d != EOF);
3067 termch = c;
3068 *vp = v;
3069 return 1;
3070}
3071
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003072static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073scannl(void)
3074{
3075 int c;
3076
3077 c = termch;
3078 termch = 0;
3079 while( c != '\n' )
3080 c = inchar();
3081}
3082
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003083static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084{
3085 if( '0' <= c && c <= '9' )
3086 return c - '0';
3087 if( 'A' <= c && c <= 'F' )
3088 return c - ('A' - 10);
3089 if( 'a' <= c && c <= 'f' )
3090 return c - ('a' - 10);
3091 return EOF;
3092}
3093
3094void
3095getstring(char *s, int size)
3096{
3097 int c;
3098
3099 c = skipbl();
3100 do {
3101 if( size > 1 ){
3102 *s++ = c;
3103 --size;
3104 }
3105 c = inchar();
3106 } while( c != ' ' && c != '\t' && c != '\n' );
3107 termch = c;
3108 *s = 0;
3109}
3110
3111static char line[256];
3112static char *lineptr;
3113
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003114static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115flush_input(void)
3116{
3117 lineptr = NULL;
3118}
3119
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003120static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121inchar(void)
3122{
3123 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003124 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 lineptr = NULL;
3126 return EOF;
3127 }
3128 lineptr = line;
3129 }
3130 return *lineptr++;
3131}
3132
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003133static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134take_input(char *str)
3135{
3136 lineptr = str;
3137}
3138
3139
3140static void
3141symbol_lookup(void)
3142{
3143 int type = inchar();
3144 unsigned long addr;
3145 static char tmp[64];
3146
3147 switch (type) {
3148 case 'a':
3149 if (scanhex(&addr))
3150 xmon_print_symbol(addr, ": ", "\n");
3151 termch = 0;
3152 break;
3153 case 's':
3154 getstring(tmp, 64);
3155 if (setjmp(bus_error_jmp) == 0) {
3156 catch_memory_errors = 1;
3157 sync();
3158 addr = kallsyms_lookup_name(tmp);
3159 if (addr)
3160 printf("%s: %lx\n", tmp, addr);
3161 else
3162 printf("Symbol '%s' not found.\n", tmp);
3163 sync();
3164 }
3165 catch_memory_errors = 0;
3166 termch = 0;
3167 break;
3168 }
3169}
3170
3171
3172/* Print an address in numeric and symbolic form (if possible) */
3173static void xmon_print_symbol(unsigned long address, const char *mid,
3174 const char *after)
3175{
3176 char *modname;
3177 const char *name = NULL;
3178 unsigned long offset, size;
3179
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003180 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 if (setjmp(bus_error_jmp) == 0) {
3182 catch_memory_errors = 1;
3183 sync();
3184 name = kallsyms_lookup(address, &size, &offset, &modname,
3185 tmpstr);
3186 sync();
3187 /* wait a little while to see if we get a machine check */
3188 __delay(200);
3189 }
3190
3191 catch_memory_errors = 0;
3192
3193 if (name) {
3194 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
3195 if (modname)
3196 printf(" [%s]", modname);
3197 }
3198 printf("%s", after);
3199}
3200
Aneesh Kumar K.Vcaca2852016-04-29 23:26:07 +10003201#ifdef CONFIG_PPC_STD_MMU_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10003202void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203{
3204 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05303205 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11003206 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207
Michael Ellerman736256e2014-05-26 21:02:14 +10003208 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209
Michael Neuling584f8b72007-12-06 17:24:48 +11003210 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11003211 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
3212 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Michael Ellerman85673642017-04-24 10:35:14 +10003213
3214 if (!esid && !vsid)
3215 continue;
3216
3217 printf("%02d %016lx %016lx", i, esid, vsid);
3218
3219 if (!(esid & SLB_ESID_V)) {
3220 printf("\n");
3221 continue;
3222 }
3223
3224 llp = vsid & SLB_VSID_LLP;
3225 if (vsid & SLB_VSID_B_1T) {
3226 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
3227 GET_ESID_1T(esid),
3228 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
3229 llp);
3230 } else {
3231 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
3232 GET_ESID(esid),
3233 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
3234 llp);
will schmidtb3b95952007-12-07 08:22:23 +11003235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 }
3237}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003238#endif
3239
3240#ifdef CONFIG_PPC_STD_MMU_32
3241void dump_segments(void)
3242{
3243 int i;
3244
3245 printf("sr0-15 =");
3246 for (i = 0; i < 16; ++i)
3247 printf(" %x", mfsrin(i));
3248 printf("\n");
3249}
3250#endif
3251
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003252#ifdef CONFIG_44x
3253static void dump_tlb_44x(void)
3254{
3255 int i;
3256
3257 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
3258 unsigned long w0,w1,w2;
3259 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
3260 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
3261 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
3262 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
3263 if (w0 & PPC44x_TLB_VALID) {
3264 printf("V %08x -> %01x%08x %c%c%c%c%c",
3265 w0 & PPC44x_TLB_EPN_MASK,
3266 w1 & PPC44x_TLB_ERPN_MASK,
3267 w1 & PPC44x_TLB_RPN_MASK,
3268 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
3269 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
3270 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
3271 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
3272 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
3273 }
3274 printf("\n");
3275 }
3276}
3277#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003278
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10003279#ifdef CONFIG_PPC_BOOK3E
3280static void dump_tlb_book3e(void)
3281{
3282 u32 mmucfg, pidmask, lpidmask;
3283 u64 ramask;
3284 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3285 int mmu_version;
3286 static const char *pgsz_names[] = {
3287 " 1K",
3288 " 2K",
3289 " 4K",
3290 " 8K",
3291 " 16K",
3292 " 32K",
3293 " 64K",
3294 "128K",
3295 "256K",
3296 "512K",
3297 " 1M",
3298 " 2M",
3299 " 4M",
3300 " 8M",
3301 " 16M",
3302 " 32M",
3303 " 64M",
3304 "128M",
3305 "256M",
3306 "512M",
3307 " 1G",
3308 " 2G",
3309 " 4G",
3310 " 8G",
3311 " 16G",
3312 " 32G",
3313 " 64G",
3314 "128G",
3315 "256G",
3316 "512G",
3317 " 1T",
3318 " 2T",
3319 };
3320
3321 /* Gather some infos about the MMU */
3322 mmucfg = mfspr(SPRN_MMUCFG);
3323 mmu_version = (mmucfg & 3) + 1;
3324 ntlbs = ((mmucfg >> 2) & 3) + 1;
3325 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3326 lpidsz = (mmucfg >> 24) & 0xf;
3327 rasz = (mmucfg >> 16) & 0x7f;
3328 if ((mmu_version > 1) && (mmucfg & 0x10000))
3329 lrat = 1;
3330 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3331 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3332 pidmask = (1ul << pidsz) - 1;
3333 lpidmask = (1ul << lpidsz) - 1;
3334 ramask = (1ull << rasz) - 1;
3335
3336 for (tlb = 0; tlb < ntlbs; tlb++) {
3337 u32 tlbcfg;
3338 int nent, assoc, new_cc = 1;
3339 printf("TLB %d:\n------\n", tlb);
3340 switch(tlb) {
3341 case 0:
3342 tlbcfg = mfspr(SPRN_TLB0CFG);
3343 break;
3344 case 1:
3345 tlbcfg = mfspr(SPRN_TLB1CFG);
3346 break;
3347 case 2:
3348 tlbcfg = mfspr(SPRN_TLB2CFG);
3349 break;
3350 case 3:
3351 tlbcfg = mfspr(SPRN_TLB3CFG);
3352 break;
3353 default:
3354 printf("Unsupported TLB number !\n");
3355 continue;
3356 }
3357 nent = tlbcfg & 0xfff;
3358 assoc = (tlbcfg >> 24) & 0xff;
3359 for (i = 0; i < nent; i++) {
3360 u32 mas0 = MAS0_TLBSEL(tlb);
3361 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3362 u64 mas2 = 0;
3363 u64 mas7_mas3;
3364 int esel = i, cc = i;
3365
3366 if (assoc != 0) {
3367 cc = i / assoc;
3368 esel = i % assoc;
3369 mas2 = cc * 0x1000;
3370 }
3371
3372 mas0 |= MAS0_ESEL(esel);
3373 mtspr(SPRN_MAS0, mas0);
3374 mtspr(SPRN_MAS1, mas1);
3375 mtspr(SPRN_MAS2, mas2);
3376 asm volatile("tlbre 0,0,0" : : : "memory");
3377 mas1 = mfspr(SPRN_MAS1);
3378 mas2 = mfspr(SPRN_MAS2);
3379 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3380 if (assoc && (i % assoc) == 0)
3381 new_cc = 1;
3382 if (!(mas1 & MAS1_VALID))
3383 continue;
3384 if (assoc == 0)
3385 printf("%04x- ", i);
3386 else if (new_cc)
3387 printf("%04x-%c", cc, 'A' + esel);
3388 else
3389 printf(" |%c", 'A' + esel);
3390 new_cc = 0;
3391 printf(" %016llx %04x %s %c%c AS%c",
3392 mas2 & ~0x3ffull,
3393 (mas1 >> 16) & 0x3fff,
3394 pgsz_names[(mas1 >> 7) & 0x1f],
3395 mas1 & MAS1_IND ? 'I' : ' ',
3396 mas1 & MAS1_IPROT ? 'P' : ' ',
3397 mas1 & MAS1_TS ? '1' : '0');
3398 printf(" %c%c%c%c%c%c%c",
3399 mas2 & MAS2_X0 ? 'a' : ' ',
3400 mas2 & MAS2_X1 ? 'v' : ' ',
3401 mas2 & MAS2_W ? 'w' : ' ',
3402 mas2 & MAS2_I ? 'i' : ' ',
3403 mas2 & MAS2_M ? 'm' : ' ',
3404 mas2 & MAS2_G ? 'g' : ' ',
3405 mas2 & MAS2_E ? 'e' : ' ');
3406 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3407 if (mas1 & MAS1_IND)
3408 printf(" %s\n",
3409 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3410 else
3411 printf(" U%c%c%c S%c%c%c\n",
3412 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3413 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3414 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3415 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3416 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3417 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3418 }
3419 }
3420}
3421#endif /* CONFIG_PPC_BOOK3E */
3422
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003423static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003425 if (enable) {
3426 __debugger = xmon;
3427 __debugger_ipi = xmon_ipi;
3428 __debugger_bpt = xmon_bpt;
3429 __debugger_sstep = xmon_sstep;
3430 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003431 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003432 __debugger_fault_handler = xmon_fault_handler;
3433 } else {
3434 __debugger = NULL;
3435 __debugger_ipi = NULL;
3436 __debugger_bpt = NULL;
3437 __debugger_sstep = NULL;
3438 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003439 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003440 __debugger_fault_handler = NULL;
3441 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003443
3444#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003445static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003446{
3447 /* ensure xmon is enabled */
3448 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003449 debugger(get_irq_regs());
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003450 if (!xmon_on)
3451 xmon_init(0);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003452}
3453
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003454static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003455 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003456 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003457 .action_msg = "Entering xmon",
3458};
3459
3460static int __init setup_xmon_sysrq(void)
3461{
3462 register_sysrq_key('x', &sysrq_xmon_op);
3463 return 0;
3464}
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003465device_initcall(setup_xmon_sysrq);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003466#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003467
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003468#ifdef CONFIG_DEBUG_FS
3469static int xmon_dbgfs_set(void *data, u64 val)
3470{
3471 xmon_on = !!val;
3472 xmon_init(xmon_on);
3473
3474 return 0;
3475}
3476
3477static int xmon_dbgfs_get(void *data, u64 *val)
3478{
3479 *val = xmon_on;
3480 return 0;
3481}
3482
3483DEFINE_SIMPLE_ATTRIBUTE(xmon_dbgfs_ops, xmon_dbgfs_get,
3484 xmon_dbgfs_set, "%llu\n");
3485
3486static int __init setup_xmon_dbgfs(void)
3487{
3488 debugfs_create_file("xmon", 0600, powerpc_debugfs_root, NULL,
3489 &xmon_dbgfs_ops);
3490 return 0;
3491}
3492device_initcall(setup_xmon_dbgfs);
3493#endif /* CONFIG_DEBUG_FS */
3494
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003495static int xmon_early __initdata;
Michael Ellerman476792832006-10-03 14:12:08 +10003496
3497static int __init early_parse_xmon(char *p)
3498{
3499 if (!p || strncmp(p, "early", 5) == 0) {
3500 /* just "xmon" is equivalent to "xmon=early" */
3501 xmon_init(1);
3502 xmon_early = 1;
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003503 xmon_on = 1;
3504 } else if (strncmp(p, "on", 2) == 0) {
Michael Ellerman476792832006-10-03 14:12:08 +10003505 xmon_init(1);
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003506 xmon_on = 1;
3507 } else if (strncmp(p, "off", 3) == 0)
3508 xmon_on = 0;
Michael Ellerman476792832006-10-03 14:12:08 +10003509 else
3510 return 1;
3511
3512 return 0;
3513}
3514early_param("xmon", early_parse_xmon);
3515
3516void __init xmon_setup(void)
3517{
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003518 if (xmon_on)
Michael Ellerman476792832006-10-03 14:12:08 +10003519 xmon_init(1);
Michael Ellerman476792832006-10-03 14:12:08 +10003520 if (xmon_early)
3521 debugger(NULL);
3522}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003523
Arnd Bergmanne0555952006-11-27 19:18:55 +01003524#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003525
3526struct spu_info {
3527 struct spu *spu;
3528 u64 saved_mfc_sr1_RW;
3529 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003530 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003531 u8 stopped_ok;
3532};
3533
3534#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3535
3536static struct spu_info spu_info[XMON_NUM_SPUS];
3537
3538void xmon_register_spus(struct list_head *list)
3539{
3540 struct spu *spu;
3541
3542 list_for_each_entry(spu, list, full_list) {
3543 if (spu->number >= XMON_NUM_SPUS) {
3544 WARN_ON(1);
3545 continue;
3546 }
3547
3548 spu_info[spu->number].spu = spu;
3549 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003550 spu_info[spu->number].dump_addr = (unsigned long)
3551 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003552 }
3553}
3554
3555static void stop_spus(void)
3556{
3557 struct spu *spu;
3558 int i;
3559 u64 tmp;
3560
3561 for (i = 0; i < XMON_NUM_SPUS; i++) {
3562 if (!spu_info[i].spu)
3563 continue;
3564
3565 if (setjmp(bus_error_jmp) == 0) {
3566 catch_memory_errors = 1;
3567 sync();
3568
3569 spu = spu_info[i].spu;
3570
3571 spu_info[i].saved_spu_runcntl_RW =
3572 in_be32(&spu->problem->spu_runcntl_RW);
3573
3574 tmp = spu_mfc_sr1_get(spu);
3575 spu_info[i].saved_mfc_sr1_RW = tmp;
3576
3577 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3578 spu_mfc_sr1_set(spu, tmp);
3579
3580 sync();
3581 __delay(200);
3582
3583 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003584
3585 printf("Stopped spu %.2d (was %s)\n", i,
3586 spu_info[i].saved_spu_runcntl_RW ?
3587 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003588 } else {
3589 catch_memory_errors = 0;
3590 printf("*** Error stopping spu %.2d\n", i);
3591 }
3592 catch_memory_errors = 0;
3593 }
3594}
3595
3596static void restart_spus(void)
3597{
3598 struct spu *spu;
3599 int i;
3600
3601 for (i = 0; i < XMON_NUM_SPUS; i++) {
3602 if (!spu_info[i].spu)
3603 continue;
3604
3605 if (!spu_info[i].stopped_ok) {
3606 printf("*** Error, spu %d was not successfully stopped"
3607 ", not restarting\n", i);
3608 continue;
3609 }
3610
3611 if (setjmp(bus_error_jmp) == 0) {
3612 catch_memory_errors = 1;
3613 sync();
3614
3615 spu = spu_info[i].spu;
3616 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3617 out_be32(&spu->problem->spu_runcntl_RW,
3618 spu_info[i].saved_spu_runcntl_RW);
3619
3620 sync();
3621 __delay(200);
3622
3623 printf("Restarted spu %.2d\n", i);
3624 } else {
3625 catch_memory_errors = 0;
3626 printf("*** Error restarting spu %.2d\n", i);
3627 }
3628 catch_memory_errors = 0;
3629 }
3630}
3631
Michael Ellermana8984972006-10-24 18:31:28 +02003632#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003633#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003634do { \
3635 if (setjmp(bus_error_jmp) == 0) { \
3636 catch_memory_errors = 1; \
3637 sync(); \
3638 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003639 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003640 sync(); \
3641 __delay(200); \
3642 } else { \
3643 catch_memory_errors = 0; \
3644 printf(" %-*s = *** Error reading field.\n", \
3645 DUMP_WIDTH, #field); \
3646 } \
3647 catch_memory_errors = 0; \
3648} while (0)
3649
Michael Ellerman437a0702006-11-23 00:46:39 +01003650#define DUMP_FIELD(obj, format, field) \
3651 DUMP_VALUE(format, field, obj->field)
3652
Michael Ellermana8984972006-10-24 18:31:28 +02003653static void dump_spu_fields(struct spu *spu)
3654{
3655 printf("Dumping spu fields at address %p:\n", spu);
3656
3657 DUMP_FIELD(spu, "0x%x", number);
3658 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003659 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3660 DUMP_FIELD(spu, "0x%p", local_store);
3661 DUMP_FIELD(spu, "0x%lx", ls_size);
3662 DUMP_FIELD(spu, "0x%x", node);
3663 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003664 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003665 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003666 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3667 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003668 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3669 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3670 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3671 DUMP_FIELD(spu, "0x%x", slb_replace);
3672 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003673 DUMP_FIELD(spu, "0x%p", mm);
3674 DUMP_FIELD(spu, "0x%p", ctx);
3675 DUMP_FIELD(spu, "0x%p", rq);
3676 DUMP_FIELD(spu, "0x%p", timestamp);
3677 DUMP_FIELD(spu, "0x%lx", problem_phys);
3678 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003679 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3680 in_be32(&spu->problem->spu_runcntl_RW));
3681 DUMP_VALUE("0x%x", problem->spu_status_R,
3682 in_be32(&spu->problem->spu_status_R));
3683 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3684 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003685 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003686 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003687}
3688
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003689int
3690spu_inst_dump(unsigned long adr, long count, int praddr)
3691{
3692 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3693}
3694
3695static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003696{
3697 unsigned long offset, addr, ls_addr;
3698
3699 if (setjmp(bus_error_jmp) == 0) {
3700 catch_memory_errors = 1;
3701 sync();
3702 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3703 sync();
3704 __delay(200);
3705 } else {
3706 catch_memory_errors = 0;
3707 printf("*** Error: accessing spu info for spu %d\n", num);
3708 return;
3709 }
3710 catch_memory_errors = 0;
3711
3712 if (scanhex(&offset))
3713 addr = ls_addr + offset;
3714 else
3715 addr = spu_info[num].dump_addr;
3716
3717 if (addr >= ls_addr + LS_SIZE) {
3718 printf("*** Error: address outside of local store\n");
3719 return;
3720 }
3721
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003722 switch (subcmd) {
3723 case 'i':
3724 addr += spu_inst_dump(addr, 16, 1);
3725 last_cmd = "sdi\n";
3726 break;
3727 default:
3728 prdump(addr, 64);
3729 addr += 64;
3730 last_cmd = "sd\n";
3731 break;
3732 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003733
3734 spu_info[num].dump_addr = addr;
3735}
3736
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003737static int do_spu_cmd(void)
3738{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003739 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003740 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003741
3742 cmd = inchar();
3743 switch (cmd) {
3744 case 's':
3745 stop_spus();
3746 break;
3747 case 'r':
3748 restart_spus();
3749 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003750 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003751 subcmd = inchar();
3752 if (isxdigit(subcmd) || subcmd == '\n')
3753 termch = subcmd;
3754 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003755 scanhex(&num);
3756 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003757 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003758 return 0;
3759 }
3760
3761 switch (cmd) {
3762 case 'f':
3763 dump_spu_fields(spu_info[num].spu);
3764 break;
3765 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003766 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003767 break;
3768 }
3769
Michael Ellermana8984972006-10-24 18:31:28 +02003770 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003771 default:
3772 return -1;
3773 }
3774
3775 return 0;
3776}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003777#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003778static int do_spu_cmd(void)
3779{
3780 return -1;
3781}
3782#endif