blob: b3bb5beec54a7abccfc037239aa16e5d88d7f9a7 [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>
Balbir Singh80eff6c2017-10-30 22:01:12 +110031#include <linux/highmem.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
Michael Ellerman7644d582017-02-10 12:04:56 +110033#include <asm/debugfs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <asm/ptrace.h>
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +100035#include <asm/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/string.h>
37#include <asm/prom.h>
38#include <asm/machdep.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100039#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <asm/processor.h>
41#include <asm/pgtable.h>
42#include <asm/mmu.h>
43#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <asm/cputable.h>
45#include <asm/rtas.h>
46#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100047#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020048#include <asm/spu.h>
49#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110050#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000051#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010052#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000053#include <asm/hw_breakpoint.h>
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +100054#include <asm/xive.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110055#include <asm/opal.h>
56#include <asm/firmware.h>
Balbir Singhefe4fbb2017-06-27 17:48:58 +100057#include <asm/code-patching.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110058
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100059#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100061#include <asm/paca.h>
62#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Anshuman Khandual1ad7d702014-11-28 10:06:42 +053064#if defined(CONFIG_PPC_SPLPAR)
65#include <asm/plpar_wrappers.h>
66#else
67static inline long plapr_set_ciabr(unsigned long ciabr) {return 0; };
68#endif
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010071#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100074static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075static unsigned long xmon_taken = 1;
76static int xmon_owner;
77static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000078#else
79#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#endif /* CONFIG_SMP */
81
Anton Blanchard5be34922010-01-12 00:50:14 +000082static unsigned long in_xmon __read_mostly = 0;
Pan Xinhui3b5bf422017-03-22 16:27:49 -030083static int xmon_on = IS_ENABLED(CONFIG_XMON_DEFAULT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85static unsigned long adrs;
86static int size = 1;
87#define MAX_DUMP (128 * 1024)
88static unsigned long ndump = 64;
89static unsigned long nidump = 16;
90static unsigned long ncsum = 4096;
91static int termch;
92static char tmpstr[128];
Breno Leitaoed49f7f2017-08-02 17:14:06 -030093static int tracing_enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Linus Torvalds1da177e2005-04-16 15:20:36 -070095static long bus_error_jmp[JMP_BUF_LEN];
96static int catch_memory_errors;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +100097static int catch_spr_faults;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
100/* Breakpoint stuff */
101struct bpt {
102 unsigned long address;
103 unsigned int instr[2];
104 atomic_t ref_count;
105 int enabled;
106 unsigned long pad;
107};
108
109/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100110#define BP_CIABR 1
111#define BP_TRAP 2
112#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
114#define NBPTS 256
115static struct bpt bpts[NBPTS];
116static struct bpt dabr;
117static struct bpt *iabr;
118static unsigned bpinstr = 0x7fe00008; /* trap */
119
120#define BP_NUM(bp) ((bp) - bpts + 1)
121
122/* Prototypes */
123static int cmds(struct pt_regs *);
124static int mread(unsigned long, void *, int);
125static int mwrite(unsigned long, void *, int);
126static int handle_fault(struct pt_regs *);
127static void byterev(unsigned char *, int);
128static void memex(void);
129static int bsesc(void);
130static void dump(void);
Balbir Singh80eff6c2017-10-30 22:01:12 +1100131static void show_pte(unsigned long);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132static void prdump(unsigned long, long);
133static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000134static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100135
136#ifdef CONFIG_PPC_POWERNV
137static void dump_opal_msglog(void);
138#else
139static inline void dump_opal_msglog(void)
140{
141 printf("Machine is not running OPAL firmware.\n");
142}
143#endif
144
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145static void backtrace(struct pt_regs *);
146static void excprint(struct pt_regs *);
147static void prregs(struct pt_regs *);
148static void memops(int);
149static void memlocate(void);
150static void memzcan(void);
151static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
152int skipbl(void);
153int scanhex(unsigned long *valp);
154static void scannl(void);
155static int hexdigit(int);
156void getstring(char *, int);
157static void flush_input(void);
158static int inchar(void);
159static void take_input(char *);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000160static int read_spr(int, unsigned long *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161static void write_spr(int, unsigned long);
162static void super_regs(void);
163static void remove_bpts(void);
164static void insert_bpts(void);
165static void remove_cpu_bpts(void);
166static void insert_cpu_bpts(void);
167static struct bpt *at_breakpoint(unsigned long pc);
168static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
169static int do_step(struct pt_regs *);
170static void bpt_cmds(void);
171static void cacheflush(void);
172static int cpu_cmd(void);
173static void csum(void);
174static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000175static void proccall(void);
Douglas Miller6dfb5402015-11-23 09:01:15 -0600176static void show_tasks(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177void dump_segments(void);
178static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200179static void xmon_show_stack(unsigned long sp, unsigned long lr,
180 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181static void xmon_print_symbol(unsigned long address, const char *mid,
182 const char *after);
183static const char *getvecname(unsigned long vec);
184
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200185static int do_spu_cmd(void);
186
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100187#ifdef CONFIG_44x
188static void dump_tlb_44x(void);
189#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000190#ifdef CONFIG_PPC_BOOK3E
191static void dump_tlb_book3e(void);
192#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100193
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000194#ifdef CONFIG_PPC64
195#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000196#else
197#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000198#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100200#ifdef __LITTLE_ENDIAN__
201#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
202#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100204#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206static char *help_string = "\
207Commands:\n\
208 b show breakpoints\n\
209 bd set data breakpoint\n\
210 bi set instruction breakpoint\n\
211 bc clear breakpoint\n"
212#ifdef CONFIG_SMP
213 "\
214 c print cpus stopped in xmon\n\
215 c# try to switch to cpu number h (in hex)\n"
216#endif
217 "\
218 C checksum\n\
219 d dump bytes\n\
Douglas Miller5e48dc02017-02-07 07:40:44 -0600220 d1 dump 1 byte values\n\
221 d2 dump 2 byte values\n\
222 d4 dump 4 byte values\n\
223 d8 dump 8 byte values\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 di dump instructions\n\
225 df dump float values\n\
226 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000227 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100228#ifdef CONFIG_PPC_POWERNV
229 "\
230 do dump the OPAL message log\n"
231#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000232#ifdef CONFIG_PPC64
233 "\
234 dp[#] dump paca for current cpu, or cpu #\n\
235 dpa dump paca for all possible cpus\n"
236#endif
237 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100238 dr dump stream of raw bytes\n\
Balbir Singh80eff6c2017-10-30 22:01:12 +1100239 dv dump virtual address translation \n\
Michael Ellerman56144ec2015-11-06 13:21:17 +1100240 dt dump the tracing buffers (uses printk)\n\
Breno Leitao4125d012017-08-02 17:14:05 -0300241 dtc dump the tracing buffers for current CPU (uses printk)\n\
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +1000242"
243#ifdef CONFIG_PPC_POWERNV
244" dx# dump xive on CPU #\n\
245 dxi# dump xive irq state #\n\
246 dxa dump xive on all CPUs\n"
247#endif
248" e print exception information\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 f flush cache\n\
250 la lookup symbol+offset of specified address\n\
251 ls lookup address of specified symbol\n\
252 m examine/change memory\n\
253 mm move a block of memory\n\
254 ms set a block of memory\n\
255 md compare two blocks of memory\n\
256 ml locate a block of memory\n\
257 mz zero a block of memory\n\
258 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000259 p call a procedure\n\
Douglas Miller6dfb5402015-11-23 09:01:15 -0600260 P list processes/tasks\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200262 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100263#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200264" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200265 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100266 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900267 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100268 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200269#endif
270" S print special registers\n\
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000271 Sa print all SPRs\n\
272 Sr # read SPR #\n\
273 Sw #v write v to SPR #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100276 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000277#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000278" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000279#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000280" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000281#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100282" u dump TLB\n"
283#endif
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300284" U show uptime information\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000285" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100286" # n limit output to n lines per page (for dp, dpa, dl)\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000287" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 zh halt\n"
289;
290
291static struct pt_regs *xmon_regs;
292
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000293static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294{
295 asm volatile("sync; isync");
296}
297
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000298static inline void store_inst(void *p)
299{
300 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
301}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000303static inline void cflush(void *p)
304{
305 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
306}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000308static inline void cinval(void *p)
309{
310 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
311}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530313/**
314 * write_ciabr() - write the CIABR SPR
315 * @ciabr: The value to write.
316 *
317 * This function writes a value to the CIARB register either directly
318 * through mtspr instruction if the kernel is in HV privilege mode or
319 * call a hypervisor function to achieve the same in case the kernel
320 * is in supervisor privilege mode.
321 */
322static void write_ciabr(unsigned long ciabr)
323{
324 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
325 return;
326
327 if (cpu_has_feature(CPU_FTR_HVMODE)) {
328 mtspr(SPRN_CIABR, ciabr);
329 return;
330 }
331 plapr_set_ciabr(ciabr);
332}
333
334/**
335 * set_ciabr() - set the CIABR
336 * @addr: The value to set.
337 *
338 * This function sets the correct privilege value into the the HW
339 * breakpoint address before writing it up in the CIABR register.
340 */
341static void set_ciabr(unsigned long addr)
342{
343 addr &= ~CIABR_PRIV;
344
345 if (cpu_has_feature(CPU_FTR_HVMODE))
346 addr |= CIABR_PRIV_HYPER;
347 else
348 addr |= CIABR_PRIV_SUPER;
349 write_ciabr(addr);
350}
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352/*
353 * Disable surveillance (the service processor watchdog function)
354 * while we are in xmon.
355 * XXX we should re-enable it when we leave. :)
356 */
357#define SURVEILLANCE_TOKEN 9000
358
359static inline void disable_surveillance(void)
360{
361#ifdef CONFIG_PPC_PSERIES
362 /* Since this can't be a module, args should end up below 4GB. */
363 static struct rtas_args args;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100364 int token;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 /*
367 * At this point we have got all the cpus we can into
368 * xmon, so there is hopefully no other cpu calling RTAS
369 * at the moment, even though we don't take rtas.lock.
370 * If we did try to take rtas.lock there would be a
371 * real possibility of deadlock.
372 */
Michael Ellerman08eb1052015-11-24 22:26:09 +1100373 token = rtas_token("set-indicator");
374 if (token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100376
377 rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0);
378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379#endif /* CONFIG_PPC_PSERIES */
380}
381
382#ifdef CONFIG_SMP
383static int xmon_speaker;
384
385static void get_output_lock(void)
386{
387 int me = smp_processor_id() + 0x100;
388 int last_speaker = 0, prev;
389 long timeout;
390
391 if (xmon_speaker == me)
392 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100393
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100395 last_speaker = cmpxchg(&xmon_speaker, 0, me);
396 if (last_speaker == 0)
397 return;
398
Michael Ellerman15075892013-12-23 23:46:05 +1100399 /*
400 * Wait a full second for the lock, we might be on a slow
401 * console, but check every 100us.
402 */
403 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100405 if (--timeout > 0) {
406 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100408 }
409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 /* hostile takeover */
411 prev = cmpxchg(&xmon_speaker, last_speaker, me);
412 if (prev == last_speaker)
413 return;
414 break;
415 }
416 }
417}
418
419static void release_output_lock(void)
420{
421 xmon_speaker = 0;
422}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000423
424int cpus_are_in_xmon(void)
425{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000426 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000427}
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000428
429static bool wait_for_other_cpus(int ncpus)
430{
431 unsigned long timeout;
432
433 /* We wait for 2s, which is a metric "little while" */
434 for (timeout = 20000; timeout != 0; --timeout) {
435 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
436 return true;
437 udelay(100);
438 barrier();
439 }
440
441 return false;
442}
443#endif /* CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444
Josh Boyerdaf8f402009-09-23 03:51:04 +0000445static inline int unrecoverable_excp(struct pt_regs *regs)
446{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000447#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000448 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000449 return 0;
450#else
451 return ((regs->msr & MSR_RI) == 0);
452#endif
453}
454
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000455static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456{
457 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 struct bpt *bp;
459 long recurse_jmp[JMP_BUF_LEN];
460 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100461 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462#ifdef CONFIG_SMP
463 int cpu;
464 int secondary;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465#endif
466
Anton Blanchardf13659e2007-03-21 01:48:34 +1100467 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000468 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Breno Leitaoed49f7f2017-08-02 17:14:06 -0300470 tracing_enabled = tracing_is_on();
471 tracing_off();
472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 bp = in_breakpoint_table(regs->nip, &offset);
474 if (bp != NULL) {
475 regs->nip = bp->address + offset;
476 atomic_dec(&bp->ref_count);
477 }
478
479 remove_cpu_bpts();
480
481#ifdef CONFIG_SMP
482 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000483 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000484 /*
485 * We catch SPR read/write faults here because the 0x700, 0xf60
486 * etc. handlers don't call debugger_fault_handler().
487 */
488 if (catch_spr_faults)
489 longjmp(bus_error_jmp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 get_output_lock();
491 excprint(regs);
492 printf("cpu 0x%x: Exception %lx %s in xmon, "
493 "returning to main loop\n",
494 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000495 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 longjmp(xmon_fault_jmp[cpu], 1);
497 }
498
499 if (setjmp(recurse_jmp) != 0) {
500 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000501 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 printf("xmon: WARNING: bad recursive fault "
503 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000504 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 goto waiting;
506 }
507 secondary = !(xmon_taken && cpu == xmon_owner);
508 goto cmdloop;
509 }
510
511 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000514 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000516 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 fromipi = 0;
518
519 if (!fromipi) {
520 get_output_lock();
521 excprint(regs);
522 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000523 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 cpu, BP_NUM(bp));
525 xmon_print_symbol(regs->nip, " ", ")\n");
526 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000527 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 printf("WARNING: exception is not recoverable, "
529 "can't continue\n");
530 release_output_lock();
531 }
532
Michael Ellermand2b496e2013-12-23 23:46:06 +1100533 cpumask_set_cpu(cpu, &cpus_in_xmon);
534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 waiting:
536 secondary = 1;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000537 spin_begin();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 while (secondary && !xmon_gate) {
539 if (in_xmon == 0) {
Nicholas Piggin064996d2017-09-29 13:29:40 +1000540 if (fromipi) {
541 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 goto leave;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 secondary = test_and_set_bit(0, &in_xmon);
545 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000546 spin_cpu_relax();
547 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000549 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
551 if (!secondary && !xmon_gate) {
552 /* we are the first cpu to come in */
553 /* interrupt other cpu(s) */
554 int ncpus = num_online_cpus();
555
556 xmon_owner = cpu;
557 mb();
558 if (ncpus > 1) {
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000559 /*
560 * A system reset (trap == 0x100) can be triggered on
561 * all CPUs, so when we come in via 0x100 try waiting
562 * for the other CPUs to come in before we send the
563 * debugger break (IPI). This is similar to
564 * crash_kexec_secondary().
565 */
566 if (TRAP(regs) != 0x100 || !wait_for_other_cpus(ncpus))
567 smp_send_debugger_break();
568
569 wait_for_other_cpus(ncpus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 }
571 remove_bpts();
572 disable_surveillance();
573 /* for breakpoint or single step, print the current instr. */
574 if (bp || TRAP(regs) == 0xd00)
575 ppc_inst_dump(regs->nip, 1, 0);
576 printf("enter ? for help\n");
577 mb();
578 xmon_gate = 1;
579 barrier();
Nicholas Piggin064996d2017-09-29 13:29:40 +1000580 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 }
582
583 cmdloop:
584 while (in_xmon) {
585 if (secondary) {
Nicholas Piggin064996d2017-09-29 13:29:40 +1000586 spin_begin();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 if (cpu == xmon_owner) {
588 if (!test_and_set_bit(0, &xmon_taken)) {
589 secondary = 0;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000590 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 continue;
592 }
593 /* missed it */
594 while (cpu == xmon_owner)
Nicholas Piggin064996d2017-09-29 13:29:40 +1000595 spin_cpu_relax();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000597 spin_cpu_relax();
598 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 } else {
600 cmd = cmds(regs);
601 if (cmd != 0) {
602 /* exiting xmon */
603 insert_bpts();
604 xmon_gate = 0;
605 wmb();
606 in_xmon = 0;
607 break;
608 }
609 /* have switched to some other cpu */
610 secondary = 1;
611 }
612 }
613 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000614 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616#else
617 /* UP is simple... */
618 if (in_xmon) {
619 printf("Exception %lx %s in xmon, returning to main loop\n",
620 regs->trap, getvecname(TRAP(regs)));
621 longjmp(xmon_fault_jmp[0], 1);
622 }
623 if (setjmp(recurse_jmp) == 0) {
624 xmon_fault_jmp[0] = recurse_jmp;
625 in_xmon = 1;
626
627 excprint(regs);
628 bp = at_breakpoint(regs->nip);
629 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000630 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 xmon_print_symbol(regs->nip, " ", ")\n");
632 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000633 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 printf("WARNING: exception is not recoverable, "
635 "can't continue\n");
636 remove_bpts();
637 disable_surveillance();
638 /* for breakpoint or single step, print the current instr. */
639 if (bp || TRAP(regs) == 0xd00)
640 ppc_inst_dump(regs->nip, 1, 0);
641 printf("enter ? for help\n");
642 }
643
644 cmd = cmds(regs);
645
646 insert_bpts();
647 in_xmon = 0;
648#endif
649
Josh Boyercdd39042009-10-05 04:46:05 +0000650#ifdef CONFIG_BOOKE
651 if (regs->msr & MSR_DE) {
652 bp = at_breakpoint(regs->nip);
653 if (bp != NULL) {
654 regs->nip = (unsigned long) &bp->instr[0];
655 atomic_inc(&bp->ref_count);
656 }
657 }
658#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000659 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 bp = at_breakpoint(regs->nip);
661 if (bp != NULL) {
662 int stepped = emulate_step(regs, bp->instr[0]);
663 if (stepped == 0) {
664 regs->nip = (unsigned long) &bp->instr[0];
665 atomic_inc(&bp->ref_count);
666 } else if (stepped < 0) {
667 printf("Couldn't single-step %s instruction\n",
668 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
669 }
670 }
671 }
Josh Boyercdd39042009-10-05 04:46:05 +0000672#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 insert_cpu_bpts();
674
Anton Blancharda71d64b2014-08-05 14:55:00 +1000675 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100676 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000678 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679}
680
681int xmon(struct pt_regs *excp)
682{
683 struct pt_regs regs;
684
685 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000686 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 excp = &regs;
688 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200689
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 return xmon_core(excp, 0);
691}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000692EXPORT_SYMBOL(xmon);
693
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000694irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000695{
696 unsigned long flags;
697 local_irq_save(flags);
698 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000699 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000700 local_irq_restore(flags);
701 return IRQ_HANDLED;
702}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000704static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705{
706 struct bpt *bp;
707 unsigned long offset;
708
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000709 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 return 0;
711
712 /* Are we at the trap at bp->instr[1] for some bp? */
713 bp = in_breakpoint_table(regs->nip, &offset);
714 if (bp != NULL && offset == 4) {
715 regs->nip = bp->address + 4;
716 atomic_dec(&bp->ref_count);
717 return 1;
718 }
719
720 /* Are we at a breakpoint? */
721 bp = at_breakpoint(regs->nip);
722 if (!bp)
723 return 0;
724
725 xmon_core(regs, 0);
726
727 return 1;
728}
729
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000730static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731{
732 if (user_mode(regs))
733 return 0;
734 xmon_core(regs, 0);
735 return 1;
736}
737
Michael Neuling9422de32012-12-20 14:06:44 +0000738static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000740 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000742 if (dabr.enabled == 0)
743 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 xmon_core(regs, 0);
745 return 1;
746}
747
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000748static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000750 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000752 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 return 0;
754 xmon_core(regs, 0);
755 return 1;
756}
757
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000758static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
760#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000761 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 xmon_core(regs, 1);
763#endif
764 return 0;
765}
766
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000767static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768{
769 struct bpt *bp;
770 unsigned long offset;
771
772 if (in_xmon && catch_memory_errors)
773 handle_fault(regs); /* doesn't return */
774
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000775 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 bp = in_breakpoint_table(regs->nip, &offset);
777 if (bp != NULL) {
778 regs->nip = bp->address + offset;
779 atomic_dec(&bp->ref_count);
780 }
781 }
782
783 return 0;
784}
785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786static struct bpt *at_breakpoint(unsigned long pc)
787{
788 int i;
789 struct bpt *bp;
790
791 bp = bpts;
792 for (i = 0; i < NBPTS; ++i, ++bp)
793 if (bp->enabled && pc == bp->address)
794 return bp;
795 return NULL;
796}
797
798static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
799{
800 unsigned long off;
801
802 off = nip - (unsigned long) bpts;
803 if (off >= sizeof(bpts))
804 return NULL;
805 off %= sizeof(struct bpt);
806 if (off != offsetof(struct bpt, instr[0])
807 && off != offsetof(struct bpt, instr[1]))
808 return NULL;
809 *offp = off - offsetof(struct bpt, instr[0]);
810 return (struct bpt *) (nip - off);
811}
812
813static struct bpt *new_breakpoint(unsigned long a)
814{
815 struct bpt *bp;
816
817 a &= ~3UL;
818 bp = at_breakpoint(a);
819 if (bp)
820 return bp;
821
822 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
823 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
824 bp->address = a;
825 bp->instr[1] = bpinstr;
826 store_inst(&bp->instr[1]);
827 return bp;
828 }
829 }
830
831 printf("Sorry, no free breakpoints. Please clear one first.\n");
832 return NULL;
833}
834
835static void insert_bpts(void)
836{
837 int i;
838 struct bpt *bp;
839
840 bp = bpts;
841 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100842 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 continue;
844 if (mread(bp->address, &bp->instr[0], 4) != 4) {
845 printf("Couldn't read instruction at %lx, "
846 "disabling breakpoint there\n", bp->address);
847 bp->enabled = 0;
848 continue;
849 }
850 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
851 printf("Breakpoint at %lx is on an mtmsrd or rfid "
852 "instruction, disabling it\n", bp->address);
853 bp->enabled = 0;
854 continue;
855 }
856 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100857 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 continue;
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000859 if (patch_instruction((unsigned int *)bp->address,
860 bpinstr) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 printf("Couldn't write instruction at %lx, "
862 "disabling breakpoint there\n", bp->address);
863 bp->enabled &= ~BP_TRAP;
864 continue;
865 }
866 store_inst((void *)bp->address);
867 }
868}
869
870static void insert_cpu_bpts(void)
871{
Michael Neuling9422de32012-12-20 14:06:44 +0000872 struct arch_hw_breakpoint brk;
873
874 if (dabr.enabled) {
875 brk.address = dabr.address;
876 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
877 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400878 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000879 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530880
881 if (iabr)
882 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883}
884
885static void remove_bpts(void)
886{
887 int i;
888 struct bpt *bp;
889 unsigned instr;
890
891 bp = bpts;
892 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100893 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 continue;
895 if (mread(bp->address, &instr, 4) == 4
896 && instr == bpinstr
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000897 && patch_instruction(
898 (unsigned int *)bp->address, bp->instr[0]) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 printf("Couldn't remove breakpoint at %lx\n",
900 bp->address);
901 else
902 store_inst((void *)bp->address);
903 }
904}
905
906static void remove_cpu_bpts(void)
907{
Michael Neuling9422de32012-12-20 14:06:44 +0000908 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530909 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910}
911
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300912/* Based on uptime_proc_show(). */
913static void
914show_uptime(void)
915{
916 struct timespec uptime;
917
918 if (setjmp(bus_error_jmp) == 0) {
919 catch_memory_errors = 1;
920 sync();
921
922 get_monotonic_boottime(&uptime);
923 printf("Uptime: %lu.%.2lu seconds\n", (unsigned long)uptime.tv_sec,
924 ((unsigned long)uptime.tv_nsec / (NSEC_PER_SEC/100)));
925
926 sync();
927 __delay(200); \
928 }
929 catch_memory_errors = 0;
930}
931
Sam bobroff958b7c82015-10-08 11:50:23 +1100932static void set_lpp_cmd(void)
933{
934 unsigned long lpp;
935
936 if (!scanhex(&lpp)) {
937 printf("Invalid number.\n");
938 lpp = 0;
939 }
940 xmon_set_pagination_lpp(lpp);
941}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942/* Command interpreting routine */
943static char *last_cmd;
944
945static int
946cmds(struct pt_regs *excp)
947{
948 int cmd = 0;
949
950 last_cmd = NULL;
951 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200952
Guilherme G. Piccolib5617832017-03-22 16:27:50 -0300953 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
Olaf Hering26c8af52006-09-08 16:29:21 +0200954
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 for(;;) {
956#ifdef CONFIG_SMP
957 printf("%x:", smp_processor_id());
958#endif /* CONFIG_SMP */
959 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 flush_input();
961 termch = 0;
962 cmd = skipbl();
963 if( cmd == '\n' ) {
964 if (last_cmd == NULL)
965 continue;
966 take_input(last_cmd);
967 last_cmd = NULL;
968 cmd = inchar();
969 }
970 switch (cmd) {
971 case 'm':
972 cmd = inchar();
973 switch (cmd) {
974 case 'm':
975 case 's':
976 case 'd':
977 memops(cmd);
978 break;
979 case 'l':
980 memlocate();
981 break;
982 case 'z':
983 memzcan();
984 break;
985 case 'i':
Michal Hocko9af744d2017-02-22 15:46:16 -0800986 show_mem(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 break;
988 default:
989 termch = cmd;
990 memex();
991 }
992 break;
993 case 'd':
994 dump();
995 break;
996 case 'l':
997 symbol_lookup();
998 break;
999 case 'r':
1000 prregs(excp); /* print regs */
1001 break;
1002 case 'e':
1003 excprint(excp);
1004 break;
1005 case 'S':
1006 super_regs();
1007 break;
1008 case 't':
1009 backtrace(excp);
1010 break;
1011 case 'f':
1012 cacheflush();
1013 break;
1014 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +02001015 if (do_spu_cmd() == 0)
1016 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (do_step(excp))
1018 return cmd;
1019 break;
1020 case 'x':
1021 case 'X':
Breno Leitaoed49f7f2017-08-02 17:14:06 -03001022 if (tracing_enabled)
1023 tracing_on();
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001024 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001026 printf(" <no input ...>\n");
1027 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 return cmd;
1029 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +10001030 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 break;
Sam bobroff958b7c82015-10-08 11:50:23 +11001032 case '#':
1033 set_lpp_cmd();
1034 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 case 'b':
1036 bpt_cmds();
1037 break;
1038 case 'C':
1039 csum();
1040 break;
1041 case 'c':
1042 if (cpu_cmd())
1043 return 0;
1044 break;
1045 case 'z':
1046 bootcmds();
1047 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001048 case 'p':
1049 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -06001051 case 'P':
1052 show_tasks();
1053 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001054#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 case 'u':
1056 dump_segments();
1057 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +11001058#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11001059 case 'u':
1060 dump_tlb_44x();
1061 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +00001062#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10001063 case 'u':
1064 dump_tlb_book3e();
1065 break;
1066#endif
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -03001067 case 'U':
1068 show_uptime();
1069 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 default:
1071 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +00001072 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 if (' ' < cmd && cmd <= '~')
1074 putchar(cmd);
1075 else
1076 printf("\\x%x", cmd);
1077 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +00001078 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 printf(" (type ? for help)\n");
1080 break;
1081 }
1082 }
1083}
1084
Josh Boyercdd39042009-10-05 04:46:05 +00001085#ifdef CONFIG_BOOKE
1086static int do_step(struct pt_regs *regs)
1087{
1088 regs->msr |= MSR_DE;
1089 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1090 return 1;
1091}
1092#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093/*
1094 * Step a single instruction.
1095 * Some instructions we emulate, others we execute with MSR_SE set.
1096 */
1097static int do_step(struct pt_regs *regs)
1098{
1099 unsigned int instr;
1100 int stepped;
1101
1102 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001103 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 if (mread(regs->nip, &instr, 4) == 4) {
1105 stepped = emulate_step(regs, instr);
1106 if (stepped < 0) {
1107 printf("Couldn't single-step %s instruction\n",
1108 (IS_RFID(instr)? "rfid": "mtmsrd"));
1109 return 0;
1110 }
1111 if (stepped > 0) {
1112 regs->trap = 0xd00 | (regs->trap & 1);
1113 printf("stepped to ");
1114 xmon_print_symbol(regs->nip, " ", "\n");
1115 ppc_inst_dump(regs->nip, 1, 0);
1116 return 0;
1117 }
1118 }
1119 }
1120 regs->msr |= MSR_SE;
1121 return 1;
1122}
Josh Boyercdd39042009-10-05 04:46:05 +00001123#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
1125static void bootcmds(void)
1126{
1127 int cmd;
1128
1129 cmd = inchar();
1130 if (cmd == 'r')
1131 ppc_md.restart(NULL);
1132 else if (cmd == 'h')
1133 ppc_md.halt();
1134 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001135 if (pm_power_off)
1136 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137}
1138
1139static int cpu_cmd(void)
1140{
1141#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001142 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
1145 if (!scanhex(&cpu)) {
1146 /* print cpus waiting or in xmon */
1147 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001148 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001149 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001150 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001151 if (cpu == last_cpu + 1) {
1152 last_cpu = cpu;
1153 } else {
1154 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001155 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001156 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001157 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 }
1160 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001161 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001162 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 printf("\n");
1164 return 0;
1165 }
1166 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001167 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 printf("cpu 0x%x isn't in xmon\n", cpu);
1169 return 0;
1170 }
1171 xmon_taken = 0;
1172 mb();
1173 xmon_owner = cpu;
1174 timeout = 10000000;
1175 while (!xmon_taken) {
1176 if (--timeout == 0) {
1177 if (test_and_set_bit(0, &xmon_taken))
1178 break;
1179 /* take control back */
1180 mb();
1181 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001182 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 return 0;
1184 }
1185 barrier();
1186 }
1187 return 1;
1188#else
1189 return 0;
1190#endif /* CONFIG_SMP */
1191}
1192
1193static unsigned short fcstab[256] = {
1194 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1195 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1196 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1197 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1198 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1199 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1200 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1201 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1202 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1203 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1204 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1205 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1206 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1207 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1208 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1209 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1210 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1211 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1212 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1213 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1214 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1215 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1216 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1217 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1218 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1219 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1220 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1221 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1222 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1223 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1224 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1225 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1226};
1227
1228#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1229
1230static void
1231csum(void)
1232{
1233 unsigned int i;
1234 unsigned short fcs;
1235 unsigned char v;
1236
1237 if (!scanhex(&adrs))
1238 return;
1239 if (!scanhex(&ncsum))
1240 return;
1241 fcs = 0xffff;
1242 for (i = 0; i < ncsum; ++i) {
1243 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001244 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 break;
1246 }
1247 fcs = FCS(fcs, v);
1248 }
1249 printf("%x\n", fcs);
1250}
1251
1252/*
1253 * Check if this is a suitable place to put a breakpoint.
1254 */
1255static long check_bp_loc(unsigned long addr)
1256{
1257 unsigned int instr;
1258
1259 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001260 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 printf("Breakpoints may only be placed at kernel addresses\n");
1262 return 0;
1263 }
1264 if (!mread(addr, &instr, sizeof(instr))) {
1265 printf("Can't read instruction at address %lx\n", addr);
1266 return 0;
1267 }
1268 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1269 printf("Breakpoints may not be placed on mtmsrd or rfid "
1270 "instructions\n");
1271 return 0;
1272 }
1273 return 1;
1274}
1275
Michael Ellermane3bc8042012-08-23 22:09:13 +00001276static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 "Breakpoint command usage:\n"
1278 "b show breakpoints\n"
1279 "b <addr> [cnt] set breakpoint at given instr addr\n"
1280 "bc clear all breakpoints\n"
1281 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301282 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 "bd <addr> [cnt] set hardware data breakpoint\n"
1284 "";
1285
1286static void
1287bpt_cmds(void)
1288{
1289 int cmd;
1290 unsigned long a;
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001291 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 struct bpt *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
1294 cmd = inchar();
1295 switch (cmd) {
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001296#ifndef CONFIG_PPC_8xx
1297 static const char badaddr[] = "Only kernel addresses are permitted for breakpoints\n";
1298 int mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 case 'd': /* bd - hardware data breakpoint */
1300 mode = 7;
1301 cmd = inchar();
1302 if (cmd == 'r')
1303 mode = 5;
1304 else if (cmd == 'w')
1305 mode = 6;
1306 else
1307 termch = cmd;
1308 dabr.address = 0;
1309 dabr.enabled = 0;
1310 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001311 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 printf(badaddr);
1313 break;
1314 }
Michael Neuling9422de32012-12-20 14:06:44 +00001315 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 dabr.enabled = mode | BP_DABR;
1317 }
1318 break;
1319
1320 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301321 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 printf("Hardware instruction breakpoint "
1323 "not supported on this cpu\n");
1324 break;
1325 }
1326 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001327 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 iabr = NULL;
1329 }
1330 if (!scanhex(&a))
1331 break;
1332 if (!check_bp_loc(a))
1333 break;
1334 bp = new_breakpoint(a);
1335 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001336 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 iabr = bp;
1338 }
1339 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001340#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
1342 case 'c':
1343 if (!scanhex(&a)) {
1344 /* clear all breakpoints */
1345 for (i = 0; i < NBPTS; ++i)
1346 bpts[i].enabled = 0;
1347 iabr = NULL;
1348 dabr.enabled = 0;
1349 printf("All breakpoints cleared\n");
1350 break;
1351 }
1352
1353 if (a <= NBPTS && a >= 1) {
1354 /* assume a breakpoint number */
1355 bp = &bpts[a-1]; /* bp nums are 1 based */
1356 } else {
1357 /* assume a breakpoint address */
1358 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001359 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001360 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 break;
1362 }
1363 }
1364
Michael Ellerman736256e2014-05-26 21:02:14 +10001365 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 xmon_print_symbol(bp->address, " ", ")\n");
1367 bp->enabled = 0;
1368 break;
1369
1370 default:
1371 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001372 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 if (cmd == '?') {
1374 printf(breakpoint_help_string);
1375 break;
1376 }
1377 termch = cmd;
1378 if (!scanhex(&a)) {
1379 /* print all breakpoints */
1380 printf(" type address\n");
1381 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001382 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 if (dabr.enabled & 1)
1384 printf("r");
1385 if (dabr.enabled & 2)
1386 printf("w");
1387 printf("]\n");
1388 }
1389 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1390 if (!bp->enabled)
1391 continue;
1392 printf("%2x %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001393 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 xmon_print_symbol(bp->address, " ", "\n");
1395 }
1396 break;
1397 }
1398
1399 if (!check_bp_loc(a))
1400 break;
1401 bp = new_breakpoint(a);
1402 if (bp != NULL)
1403 bp->enabled |= BP_TRAP;
1404 break;
1405 }
1406}
1407
1408/* Very cheap human name for vector lookup. */
1409static
1410const char *getvecname(unsigned long vec)
1411{
1412 char *ret;
1413
1414 switch (vec) {
1415 case 0x100: ret = "(System Reset)"; break;
1416 case 0x200: ret = "(Machine Check)"; break;
1417 case 0x300: ret = "(Data Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001418 case 0x380:
1419 if (radix_enabled())
1420 ret = "(Data Access Out of Range)";
1421 else
1422 ret = "(Data SLB Access)";
1423 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 case 0x400: ret = "(Instruction Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001425 case 0x480:
1426 if (radix_enabled())
1427 ret = "(Instruction Access Out of Range)";
1428 else
1429 ret = "(Instruction SLB Access)";
1430 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 case 0x500: ret = "(Hardware Interrupt)"; break;
1432 case 0x600: ret = "(Alignment)"; break;
1433 case 0x700: ret = "(Program Check)"; break;
1434 case 0x800: ret = "(FPU Unavailable)"; break;
1435 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001436 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1437 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 case 0xc00: ret = "(System Call)"; break;
1439 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001440 case 0xe40: ret = "(Emulation Assist)"; break;
1441 case 0xe60: ret = "(HMI)"; break;
1442 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 case 0xf00: ret = "(Performance Monitor)"; break;
1444 case 0xf20: ret = "(Altivec Unavailable)"; break;
1445 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001446 case 0x1500: ret = "(Denormalisation)"; break;
1447 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 default: ret = "";
1449 }
1450 return ret;
1451}
1452
1453static void get_function_bounds(unsigned long pc, unsigned long *startp,
1454 unsigned long *endp)
1455{
1456 unsigned long size, offset;
1457 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
1459 *startp = *endp = 0;
1460 if (pc == 0)
1461 return;
1462 if (setjmp(bus_error_jmp) == 0) {
1463 catch_memory_errors = 1;
1464 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001465 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 if (name != NULL) {
1467 *startp = pc - offset;
1468 *endp = pc - offset + size;
1469 }
1470 sync();
1471 }
1472 catch_memory_errors = 0;
1473}
1474
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001475#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1476#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1477
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478static void xmon_show_stack(unsigned long sp, unsigned long lr,
1479 unsigned long pc)
1480{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001481 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 unsigned long ip;
1483 unsigned long newsp;
1484 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 struct pt_regs regs;
1486
Michael Ellerman0104cd62012-10-09 04:20:36 +00001487 while (max_to_print--) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301488 if (!is_kernel_addr(sp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 if (sp != 0)
1490 printf("SP (%lx) is in userspace\n", sp);
1491 break;
1492 }
1493
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001494 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 || !mread(sp, &newsp, sizeof(unsigned long))) {
1496 printf("Couldn't read stack frame at %lx\n", sp);
1497 break;
1498 }
1499
1500 /*
1501 * For the first stack frame, try to work out if
1502 * LR and/or the saved LR value in the bottommost
1503 * stack frame are valid.
1504 */
1505 if ((pc | lr) != 0) {
1506 unsigned long fnstart, fnend;
1507 unsigned long nextip;
1508 int printip = 1;
1509
1510 get_function_bounds(pc, &fnstart, &fnend);
1511 nextip = 0;
1512 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001513 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 sizeof(unsigned long));
1515 if (lr == ip) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301516 if (!is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 || (fnstart <= lr && lr < fnend))
1518 printip = 0;
1519 } else if (lr == nextip) {
1520 printip = 0;
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301521 } else if (is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 && !(fnstart <= lr && lr < fnend)) {
1523 printf("[link register ] ");
1524 xmon_print_symbol(lr, " ", "\n");
1525 }
1526 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001527 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 xmon_print_symbol(ip, " ", " (unreliable)\n");
1529 }
1530 pc = lr = 0;
1531
1532 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001533 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 xmon_print_symbol(ip, " ", "\n");
1535 }
1536
1537 /* Look for "regshere" marker to see if this is
1538 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001539 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001540 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001541 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 != sizeof(regs)) {
1543 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001544 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 break;
1546 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001547 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 getvecname(TRAP(&regs)));
1549 pc = regs.nip;
1550 lr = regs.link;
1551 xmon_print_symbol(pc, " ", "\n");
1552 }
1553
1554 if (newsp == 0)
1555 break;
1556
1557 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559}
1560
1561static void backtrace(struct pt_regs *excp)
1562{
1563 unsigned long sp;
1564
1565 if (scanhex(&sp))
1566 xmon_show_stack(sp, 0, 0);
1567 else
1568 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1569 scannl();
1570}
1571
1572static void print_bug_trap(struct pt_regs *regs)
1573{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001574#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001575 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 unsigned long addr;
1577
1578 if (regs->msr & MSR_PR)
1579 return; /* not in kernel */
1580 addr = regs->nip; /* address of trap instruction */
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301581 if (!is_kernel_addr(addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 return;
1583 bug = find_bug(regs->nip);
1584 if (bug == NULL)
1585 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001586 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 return;
1588
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001589#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001590 printf("kernel BUG at %s:%u!\n",
1591 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001592#else
Michael Ellermand8104182017-12-06 23:23:28 +11001593 printf("kernel BUG at %px!\n", (void *)bug->bug_addr);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001594#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001595#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596}
1597
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001598static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599{
1600 unsigned long trap;
1601
1602#ifdef CONFIG_SMP
1603 printf("cpu 0x%x: ", smp_processor_id());
1604#endif /* CONFIG_SMP */
1605
1606 trap = TRAP(fp);
1607 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1608 printf(" pc: ");
1609 xmon_print_symbol(fp->nip, ": ", "\n");
1610
1611 printf(" lr: ", fp->link);
1612 xmon_print_symbol(fp->link, ": ", "\n");
1613
1614 printf(" sp: %lx\n", fp->gpr[1]);
1615 printf(" msr: %lx\n", fp->msr);
1616
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001617 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 printf(" dar: %lx\n", fp->dar);
1619 if (trap != 0x380)
1620 printf(" dsisr: %lx\n", fp->dsisr);
1621 }
1622
1623 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001624#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001625 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1626 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001627#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 if (current) {
1629 printf(" pid = %ld, comm = %s\n",
1630 current->pid, current->comm);
1631 }
1632
1633 if (trap == 0x700)
1634 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001635
1636 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637}
1638
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001639static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001641 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 unsigned long base;
1643 struct pt_regs regs;
1644
1645 if (scanhex(&base)) {
1646 if (setjmp(bus_error_jmp) == 0) {
1647 catch_memory_errors = 1;
1648 sync();
1649 regs = *(struct pt_regs *)base;
1650 sync();
1651 __delay(200);
1652 } else {
1653 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001654 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 base);
1656 return;
1657 }
1658 catch_memory_errors = 0;
1659 fp = &regs;
1660 }
1661
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001662#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 if (FULL_REGS(fp)) {
1664 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001665 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1667 } else {
1668 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001669 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1671 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001672#else
1673 for (n = 0; n < 32; ++n) {
1674 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1675 (n & 3) == 3? "\n": " ");
1676 if (n == 12 && !FULL_REGS(fp)) {
1677 printf("\n");
1678 break;
1679 }
1680 }
1681#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 printf("pc = ");
1683 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001684 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1685 printf("cfar= ");
1686 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 printf("lr = ");
1689 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001690 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1691 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001693 trap = TRAP(fp);
1694 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1695 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696}
1697
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001698static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699{
1700 int cmd;
1701 unsigned long nflush;
1702
1703 cmd = inchar();
1704 if (cmd != 'i')
1705 termch = cmd;
1706 scanhex((void *)&adrs);
1707 if (termch != '\n')
1708 termch = 0;
1709 nflush = 1;
1710 scanhex(&nflush);
1711 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1712 if (setjmp(bus_error_jmp) == 0) {
1713 catch_memory_errors = 1;
1714 sync();
1715
1716 if (cmd != 'i') {
1717 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1718 cflush((void *) adrs);
1719 } else {
1720 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1721 cinval((void *) adrs);
1722 }
1723 sync();
1724 /* wait a little while to see if we get a machine check */
1725 __delay(200);
1726 }
1727 catch_memory_errors = 0;
1728}
1729
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001730extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1731extern void xmon_mtspr(int spr, unsigned long value);
1732
1733static int
1734read_spr(int n, unsigned long *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 unsigned long ret = -1UL;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001737 int ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
1739 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001740 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 sync();
1742
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001743 ret = xmon_mfspr(n, *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744
1745 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001746 *vp = ret;
1747 ok = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001749 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001751 return ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752}
1753
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001754static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755write_spr(int n, unsigned long val)
1756{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001758 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 sync();
1760
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001761 xmon_mtspr(n, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762
1763 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001764 } else {
1765 printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001767 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768}
1769
Michael Ellerman18461932016-07-07 22:54:29 +10001770static void dump_206_sprs(void)
1771{
1772#ifdef CONFIG_PPC64
1773 if (!cpu_has_feature(CPU_FTR_ARCH_206))
1774 return;
1775
1776 /* Actually some of these pre-date 2.06, but whatevs */
1777
Balbir Singhc47a9402017-08-29 17:22:36 +10001778 printf("srr0 = %.16lx srr1 = %.16lx dsisr = %.8x\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001779 mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001780 printf("dscr = %.16lx ppr = %.16lx pir = %.8x\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001781 mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001782 printf("amr = %.16lx uamor = %.16lx\n",
1783 mfspr(SPRN_AMR), mfspr(SPRN_UAMOR));
Michael Ellerman18461932016-07-07 22:54:29 +10001784
1785 if (!(mfmsr() & MSR_HV))
1786 return;
1787
Balbir Singhc47a9402017-08-29 17:22:36 +10001788 printf("sdr1 = %.16lx hdar = %.16lx hdsisr = %.8x\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001789 mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001790 printf("hsrr0 = %.16lx hsrr1 = %.16lx hdec = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001791 mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001792 printf("lpcr = %.16lx pcr = %.16lx lpidr = %.8x\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001793 mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001794 printf("hsprg0 = %.16lx hsprg1 = %.16lx amor = %.16lx\n",
1795 mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1), mfspr(SPRN_AMOR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001796 printf("dabr = %.16lx dabrx = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001797 mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
1798#endif
1799}
1800
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001801static void dump_207_sprs(void)
1802{
1803#ifdef CONFIG_PPC64
1804 unsigned long msr;
1805
1806 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
1807 return;
1808
Balbir Singhc47a9402017-08-29 17:22:36 +10001809 printf("dpdes = %.16lx tir = %.16lx cir = %.8x\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001810 mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
1811
Balbir Singhc47a9402017-08-29 17:22:36 +10001812 printf("fscr = %.16lx tar = %.16lx pspb = %.8x\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001813 mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
1814
1815 msr = mfmsr();
1816 if (msr & MSR_TM) {
1817 /* Only if TM has been enabled in the kernel */
Balbir Singhc47a9402017-08-29 17:22:36 +10001818 printf("tfhar = %.16lx tfiar = %.16lx texasr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001819 mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
1820 mfspr(SPRN_TEXASR));
1821 }
1822
Balbir Singhc47a9402017-08-29 17:22:36 +10001823 printf("mmcr0 = %.16lx mmcr1 = %.16lx mmcr2 = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001824 mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
1825 printf("pmc1 = %.8x pmc2 = %.8x pmc3 = %.8x pmc4 = %.8x\n",
1826 mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
1827 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
Balbir Singhc47a9402017-08-29 17:22:36 +10001828 printf("mmcra = %.16lx siar = %.16lx pmc5 = %.8x\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001829 mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
Balbir Singhc47a9402017-08-29 17:22:36 +10001830 printf("sdar = %.16lx sier = %.16lx pmc6 = %.8x\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001831 mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
Balbir Singhc47a9402017-08-29 17:22:36 +10001832 printf("ebbhr = %.16lx ebbrr = %.16lx bescr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001833 mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001834 printf("iamr = %.16lx\n", mfspr(SPRN_IAMR));
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001835
1836 if (!(msr & MSR_HV))
1837 return;
1838
Balbir Singhc47a9402017-08-29 17:22:36 +10001839 printf("hfscr = %.16lx dhdes = %.16lx rpr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001840 mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001841 printf("dawr = %.16lx dawrx = %.16lx ciabr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001842 mfspr(SPRN_DAWR), mfspr(SPRN_DAWRX), mfspr(SPRN_CIABR));
1843#endif
1844}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
Balbir Singhd1e1b352017-08-30 21:45:09 +10001846static void dump_300_sprs(void)
1847{
1848#ifdef CONFIG_PPC64
1849 bool hv = mfmsr() & MSR_HV;
1850
1851 if (!cpu_has_feature(CPU_FTR_ARCH_300))
1852 return;
1853
1854 printf("pidr = %.16lx tidr = %.16lx\n",
1855 mfspr(SPRN_PID), mfspr(SPRN_TIDR));
1856 printf("asdr = %.16lx psscr = %.16lx\n",
1857 mfspr(SPRN_ASDR), hv ? mfspr(SPRN_PSSCR)
1858 : mfspr(SPRN_PSSCR_PR));
1859
1860 if (!hv)
1861 return;
1862
1863 printf("ptcr = %.16lx\n",
1864 mfspr(SPRN_PTCR));
1865#endif
1866}
1867
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001868static void dump_one_spr(int spr, bool show_unimplemented)
1869{
1870 unsigned long val;
1871
1872 val = 0xdeadbeef;
1873 if (!read_spr(spr, &val)) {
1874 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1875 return;
1876 }
1877
1878 if (val == 0xdeadbeef) {
1879 /* Looks like read was a nop, confirm */
1880 val = 0x0badcafe;
1881 if (!read_spr(spr, &val)) {
1882 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1883 return;
1884 }
1885
1886 if (val == 0x0badcafe) {
1887 if (show_unimplemented)
1888 printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
1889 return;
1890 }
1891 }
1892
1893 printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
1894}
1895
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001896static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897{
Michael Ellerman13629da2016-07-07 22:54:27 +10001898 static unsigned long regno;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 int cmd;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001900 int spr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901
1902 cmd = skipbl();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001903
1904 switch (cmd) {
1905 case '\n': {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001906 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 asm("mr %0,1" : "=r" (sp) :);
1908 asm("mr %0,2" : "=r" (toc) :);
1909
Michael Ellerman56346ad2016-07-07 22:54:28 +10001910 printf("msr = "REG" sprg0 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001911 mfmsr(), mfspr(SPRN_SPRG0));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001912 printf("pvr = "REG" sprg1 = "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001913 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001914 printf("dec = "REG" sprg2 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001915 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001916 printf("sp = "REG" sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
1917 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
1918
Michael Ellerman18461932016-07-07 22:54:29 +10001919 dump_206_sprs();
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001920 dump_207_sprs();
Balbir Singhd1e1b352017-08-30 21:45:09 +10001921 dump_300_sprs();
Michael Ellerman18461932016-07-07 22:54:29 +10001922
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 return;
1924 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001925 case 'w': {
1926 unsigned long val;
1927 scanhex(&regno);
1928 val = 0;
1929 read_spr(regno, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 scanhex(&val);
1931 write_spr(regno, val);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001932 dump_one_spr(regno, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001935 case 'r':
1936 scanhex(&regno);
1937 dump_one_spr(regno, true);
1938 break;
1939 case 'a':
1940 /* dump ALL SPRs */
1941 for (spr = 1; spr < 1024; ++spr)
1942 dump_one_spr(spr, false);
1943 break;
1944 }
1945
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 scannl();
1947}
1948
1949/*
1950 * Stuff for reading and writing memory safely
1951 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001952static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953mread(unsigned long adrs, void *buf, int size)
1954{
1955 volatile int n;
1956 char *p, *q;
1957
1958 n = 0;
1959 if (setjmp(bus_error_jmp) == 0) {
1960 catch_memory_errors = 1;
1961 sync();
1962 p = (char *)adrs;
1963 q = (char *)buf;
1964 switch (size) {
1965 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001966 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 break;
1968 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001969 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 break;
1971 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001972 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 break;
1974 default:
1975 for( ; n < size; ++n) {
1976 *q++ = *p++;
1977 sync();
1978 }
1979 }
1980 sync();
1981 /* wait a little while to see if we get a machine check */
1982 __delay(200);
1983 n = size;
1984 }
1985 catch_memory_errors = 0;
1986 return n;
1987}
1988
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001989static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990mwrite(unsigned long adrs, void *buf, int size)
1991{
1992 volatile int n;
1993 char *p, *q;
1994
1995 n = 0;
1996 if (setjmp(bus_error_jmp) == 0) {
1997 catch_memory_errors = 1;
1998 sync();
1999 p = (char *) adrs;
2000 q = (char *) buf;
2001 switch (size) {
2002 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002003 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 break;
2005 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002006 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 break;
2008 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002009 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 break;
2011 default:
2012 for ( ; n < size; ++n) {
2013 *p++ = *q++;
2014 sync();
2015 }
2016 }
2017 sync();
2018 /* wait a little while to see if we get a machine check */
2019 __delay(200);
2020 n = size;
2021 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10002022 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 }
2024 catch_memory_errors = 0;
2025 return n;
2026}
2027
2028static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002029static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030static char *fault_chars[] = { "--", "**", "##" };
2031
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002032static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002034 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 switch (TRAP(regs)) {
2036 case 0x200:
2037 fault_type = 0;
2038 break;
2039 case 0x300:
2040 case 0x380:
2041 fault_type = 1;
2042 break;
2043 default:
2044 fault_type = 2;
2045 }
2046
2047 longjmp(bus_error_jmp, 1);
2048
2049 return 0;
2050}
2051
2052#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
2053
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002054static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055byterev(unsigned char *val, int size)
2056{
2057 int t;
2058
2059 switch (size) {
2060 case 2:
2061 SWAP(val[0], val[1], t);
2062 break;
2063 case 4:
2064 SWAP(val[0], val[3], t);
2065 SWAP(val[1], val[2], t);
2066 break;
2067 case 8: /* is there really any use for this? */
2068 SWAP(val[0], val[7], t);
2069 SWAP(val[1], val[6], t);
2070 SWAP(val[2], val[5], t);
2071 SWAP(val[3], val[4], t);
2072 break;
2073 }
2074}
2075
2076static int brev;
2077static int mnoread;
2078
Michael Ellermane3bc8042012-08-23 22:09:13 +00002079static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 "Memory examine command usage:\n"
2081 "m [addr] [flags] examine/change memory\n"
2082 " addr is optional. will start where left off.\n"
2083 " flags may include chars from this set:\n"
2084 " b modify by bytes (default)\n"
2085 " w modify by words (2 byte)\n"
2086 " l modify by longs (4 byte)\n"
2087 " d modify by doubleword (8 byte)\n"
2088 " r toggle reverse byte order mode\n"
2089 " n do not read memory (for i/o spaces)\n"
2090 " . ok to read (default)\n"
2091 "NOTE: flags are saved as defaults\n"
2092 "";
2093
Michael Ellermane3bc8042012-08-23 22:09:13 +00002094static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 "Memory examine subcommands:\n"
2096 " hexval write this val to current location\n"
2097 " 'string' write chars from string to this location\n"
2098 " ' increment address\n"
2099 " ^ decrement address\n"
2100 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
2101 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
2102 " ` clear no-read flag\n"
2103 " ; stay at this addr\n"
2104 " v change to byte mode\n"
2105 " w change to word (2 byte) mode\n"
2106 " l change to long (4 byte) mode\n"
2107 " u change to doubleword (8 byte) mode\n"
2108 " m addr change current addr\n"
2109 " n toggle no-read flag\n"
2110 " r toggle byte reverse flag\n"
2111 " < count back up count bytes\n"
2112 " > count skip forward count bytes\n"
2113 " x exit this mode\n"
2114 "";
2115
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002116static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117memex(void)
2118{
2119 int cmd, inc, i, nslash;
2120 unsigned long n;
2121 unsigned char val[16];
2122
2123 scanhex((void *)&adrs);
2124 cmd = skipbl();
2125 if (cmd == '?') {
2126 printf(memex_help_string);
2127 return;
2128 } else {
2129 termch = cmd;
2130 }
2131 last_cmd = "m\n";
2132 while ((cmd = skipbl()) != '\n') {
2133 switch( cmd ){
2134 case 'b': size = 1; break;
2135 case 'w': size = 2; break;
2136 case 'l': size = 4; break;
2137 case 'd': size = 8; break;
2138 case 'r': brev = !brev; break;
2139 case 'n': mnoread = 1; break;
2140 case '.': mnoread = 0; break;
2141 }
2142 }
2143 if( size <= 0 )
2144 size = 1;
2145 else if( size > 8 )
2146 size = 8;
2147 for(;;){
2148 if (!mnoread)
2149 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002150 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 if (!mnoread) {
2152 if (brev)
2153 byterev(val, size);
2154 putchar(' ');
2155 for (i = 0; i < n; ++i)
2156 printf("%.2x", val[i]);
2157 for (; i < size; ++i)
2158 printf("%s", fault_chars[fault_type]);
2159 }
2160 putchar(' ');
2161 inc = size;
2162 nslash = 0;
2163 for(;;){
2164 if( scanhex(&n) ){
2165 for (i = 0; i < size; ++i)
2166 val[i] = n >> (i * 8);
2167 if (!brev)
2168 byterev(val, size);
2169 mwrite(adrs, val, size);
2170 inc = size;
2171 }
2172 cmd = skipbl();
2173 if (cmd == '\n')
2174 break;
2175 inc = 0;
2176 switch (cmd) {
2177 case '\'':
2178 for(;;){
2179 n = inchar();
2180 if( n == '\\' )
2181 n = bsesc();
2182 else if( n == '\'' )
2183 break;
2184 for (i = 0; i < size; ++i)
2185 val[i] = n >> (i * 8);
2186 if (!brev)
2187 byterev(val, size);
2188 mwrite(adrs, val, size);
2189 adrs += size;
2190 }
2191 adrs -= size;
2192 inc = size;
2193 break;
2194 case ',':
2195 adrs += size;
2196 break;
2197 case '.':
2198 mnoread = 0;
2199 break;
2200 case ';':
2201 break;
2202 case 'x':
2203 case EOF:
2204 scannl();
2205 return;
2206 case 'b':
2207 case 'v':
2208 size = 1;
2209 break;
2210 case 'w':
2211 size = 2;
2212 break;
2213 case 'l':
2214 size = 4;
2215 break;
2216 case 'u':
2217 size = 8;
2218 break;
2219 case '^':
2220 adrs -= size;
2221 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 case '/':
2223 if (nslash > 0)
2224 adrs -= 1 << nslash;
2225 else
2226 nslash = 0;
2227 nslash += 4;
2228 adrs += 1 << nslash;
2229 break;
2230 case '\\':
2231 if (nslash < 0)
2232 adrs += 1 << -nslash;
2233 else
2234 nslash = 0;
2235 nslash -= 4;
2236 adrs -= 1 << -nslash;
2237 break;
2238 case 'm':
2239 scanhex((void *)&adrs);
2240 break;
2241 case 'n':
2242 mnoread = 1;
2243 break;
2244 case 'r':
2245 brev = !brev;
2246 break;
2247 case '<':
2248 n = size;
2249 scanhex(&n);
2250 adrs -= n;
2251 break;
2252 case '>':
2253 n = size;
2254 scanhex(&n);
2255 adrs += n;
2256 break;
2257 case '?':
2258 printf(memex_subcmd_help_string);
2259 break;
2260 }
2261 }
2262 adrs += inc;
2263 }
2264}
2265
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002266static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267bsesc(void)
2268{
2269 int c;
2270
2271 c = inchar();
2272 switch( c ){
2273 case 'n': c = '\n'; break;
2274 case 'r': c = '\r'; break;
2275 case 'b': c = '\b'; break;
2276 case 't': c = '\t'; break;
2277 }
2278 return c;
2279}
2280
Olaf Hering7e5b5932006-03-08 20:40:28 +01002281static void xmon_rawdump (unsigned long adrs, long ndump)
2282{
2283 long n, m, r, nr;
2284 unsigned char temp[16];
2285
2286 for (n = ndump; n > 0;) {
2287 r = n < 16? n: 16;
2288 nr = mread(adrs, temp, r);
2289 adrs += nr;
2290 for (m = 0; m < r; ++m) {
2291 if (m < nr)
2292 printf("%.2x", temp[m]);
2293 else
2294 printf("%s", fault_chars[fault_type]);
2295 }
2296 n -= r;
2297 if (nr < r)
2298 break;
2299 }
2300 printf("\n");
2301}
2302
Breno Leitao4125d012017-08-02 17:14:05 -03002303static void dump_tracing(void)
2304{
2305 int c;
2306
2307 c = inchar();
2308 if (c == 'c')
2309 ftrace_dump(DUMP_ORIG);
2310 else
2311 ftrace_dump(DUMP_ALL);
Breno Leitao4125d012017-08-02 17:14:05 -03002312}
2313
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002314#ifdef CONFIG_PPC64
2315static void dump_one_paca(int cpu)
2316{
2317 struct paca_struct *p;
Michael Ellerman4e003742017-10-19 15:08:43 +11002318#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellermanad987fc2015-10-14 16:58:36 +11002319 int i = 0;
2320#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002321
2322 if (setjmp(bus_error_jmp) != 0) {
2323 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2324 return;
2325 }
2326
2327 catch_memory_errors = 1;
2328 sync();
2329
2330 p = &paca[cpu];
2331
Michael Ellermand8104182017-12-06 23:23:28 +11002332 printf("paca for cpu 0x%x @ %px:\n", cpu, p);
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002333
Michael Ellermanad987fc2015-10-14 16:58:36 +11002334 printf(" %-*s = %s\n", 20, "possible", cpu_possible(cpu) ? "yes" : "no");
2335 printf(" %-*s = %s\n", 20, "present", cpu_present(cpu) ? "yes" : "no");
2336 printf(" %-*s = %s\n", 20, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002337
2338#define DUMP(paca, name, format) \
Michael Ellermanad987fc2015-10-14 16:58:36 +11002339 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 20, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002340 offsetof(struct paca_struct, name));
2341
2342 DUMP(p, lock_token, "x");
2343 DUMP(p, paca_index, "x");
2344 DUMP(p, kernel_toc, "lx");
2345 DUMP(p, kernelbase, "lx");
2346 DUMP(p, kernel_msr, "lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002347 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302348#ifdef CONFIG_PPC_BOOK3S_64
Nicholas Pigginb1ee8a32016-12-20 04:30:06 +10002349 DUMP(p, nmi_emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302350 DUMP(p, mc_emergency_sp, "p");
Nicholas Pigginc4f3b522016-12-20 04:30:05 +10002351 DUMP(p, in_nmi, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302352 DUMP(p, in_mce, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002353 DUMP(p, hmi_event_available, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302354#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002355 DUMP(p, data_offset, "lx");
2356 DUMP(p, hw_cpu_id, "x");
2357 DUMP(p, cpu_start, "x");
2358 DUMP(p, kexec_state, "x");
Michael Ellerman4e003742017-10-19 15:08:43 +11002359#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellermanad987fc2015-10-14 16:58:36 +11002360 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2361 u64 esid, vsid;
2362
2363 if (!p->slb_shadow_ptr)
2364 continue;
2365
2366 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2367 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
2368
2369 if (esid || vsid) {
2370 printf(" slb_shadow[%d]: = 0x%016lx 0x%016lx\n",
2371 i, esid, vsid);
2372 }
2373 }
2374 DUMP(p, vmalloc_sllp, "x");
2375 DUMP(p, slb_cache_ptr, "x");
2376 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2377 printf(" slb_cache[%d]: = 0x%016lx\n", i, p->slb_cache[i]);
Michael Ellerman274920a2018-01-10 23:49:12 +11002378
2379 DUMP(p, rfi_flush_fallback_area, "px");
2380 DUMP(p, l1d_flush_congruence, "llx");
2381 DUMP(p, l1d_flush_sets, "llx");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002382#endif
2383 DUMP(p, dscr_default, "llx");
2384#ifdef CONFIG_PPC_BOOK3E
2385 DUMP(p, pgd, "p");
2386 DUMP(p, kernel_pgd, "p");
2387 DUMP(p, tcd_ptr, "p");
2388 DUMP(p, mc_kstack, "p");
2389 DUMP(p, crit_kstack, "p");
2390 DUMP(p, dbg_kstack, "p");
2391#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002392 DUMP(p, __current, "p");
2393 DUMP(p, kstack, "lx");
Michael Ellerman90d64732017-10-09 21:59:32 +11002394 printf(" kstack_base = 0x%016lx\n", p->kstack & ~(THREAD_SIZE - 1));
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002395 DUMP(p, stab_rr, "lx");
2396 DUMP(p, saved_r1, "lx");
2397 DUMP(p, trap_save, "x");
2398 DUMP(p, soft_enabled, "x");
2399 DUMP(p, irq_happened, "x");
2400 DUMP(p, io_sync, "x");
2401 DUMP(p, irq_work_pending, "x");
2402 DUMP(p, nap_state_lost, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002403 DUMP(p, sprg_vdso, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002404
Michael Ellermanad987fc2015-10-14 16:58:36 +11002405#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
2406 DUMP(p, tm_scratch, "llx");
2407#endif
2408
2409#ifdef CONFIG_PPC_POWERNV
2410 DUMP(p, core_idle_state_ptr, "p");
2411 DUMP(p, thread_idle_state, "x");
2412 DUMP(p, thread_mask, "x");
2413 DUMP(p, subcore_sibling_mask, "x");
2414#endif
2415
Frederic Weisbecker8c8b73c2017-01-05 18:11:45 +01002416 DUMP(p, accounting.utime, "llx");
2417 DUMP(p, accounting.stime, "llx");
2418 DUMP(p, accounting.utime_scaled, "llx");
Christophe Leroyc223c902016-05-17 08:33:46 +02002419 DUMP(p, accounting.starttime, "llx");
2420 DUMP(p, accounting.starttime_user, "llx");
2421 DUMP(p, accounting.startspurr, "llx");
2422 DUMP(p, accounting.utime_sspurr, "llx");
Frederic Weisbeckerf828c3d2017-01-05 18:11:46 +01002423 DUMP(p, accounting.steal_time, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002424#undef DUMP
2425
2426 catch_memory_errors = 0;
2427 sync();
2428}
2429
2430static void dump_all_pacas(void)
2431{
2432 int cpu;
2433
2434 if (num_possible_cpus() == 0) {
2435 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2436 return;
2437 }
2438
2439 for_each_possible_cpu(cpu)
2440 dump_one_paca(cpu);
2441}
2442
2443static void dump_pacas(void)
2444{
2445 unsigned long num;
2446 int c;
2447
2448 c = inchar();
2449 if (c == 'a') {
2450 dump_all_pacas();
2451 return;
2452 }
2453
2454 termch = c; /* Put c back, it wasn't 'a' */
2455
2456 if (scanhex(&num))
2457 dump_one_paca(num);
2458 else
2459 dump_one_paca(xmon_owner);
2460}
2461#endif
2462
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002463#ifdef CONFIG_PPC_POWERNV
2464static void dump_one_xive(int cpu)
2465{
2466 unsigned int hwid = get_hard_smp_processor_id(cpu);
2467
2468 opal_xive_dump(XIVE_DUMP_TM_HYP, hwid);
2469 opal_xive_dump(XIVE_DUMP_TM_POOL, hwid);
2470 opal_xive_dump(XIVE_DUMP_TM_OS, hwid);
2471 opal_xive_dump(XIVE_DUMP_TM_USER, hwid);
2472 opal_xive_dump(XIVE_DUMP_VP, hwid);
2473 opal_xive_dump(XIVE_DUMP_EMU_STATE, hwid);
2474
2475 if (setjmp(bus_error_jmp) != 0) {
2476 catch_memory_errors = 0;
2477 printf("*** Error dumping xive on cpu %d\n", cpu);
2478 return;
2479 }
2480
2481 catch_memory_errors = 1;
2482 sync();
2483 xmon_xive_do_dump(cpu);
2484 sync();
2485 __delay(200);
2486 catch_memory_errors = 0;
2487}
2488
2489static void dump_all_xives(void)
2490{
2491 int cpu;
2492
2493 if (num_possible_cpus() == 0) {
2494 printf("No possible cpus, use 'dx #' to dump individual cpus\n");
2495 return;
2496 }
2497
2498 for_each_possible_cpu(cpu)
2499 dump_one_xive(cpu);
2500}
2501
2502static void dump_one_xive_irq(u32 num)
2503{
2504 s64 rc;
2505 __be64 vp;
2506 u8 prio;
2507 __be32 lirq;
2508
2509 rc = opal_xive_get_irq_config(num, &vp, &prio, &lirq);
2510 xmon_printf("IRQ 0x%x config: vp=0x%llx prio=%d lirq=0x%x (rc=%lld)\n",
2511 num, be64_to_cpu(vp), prio, be32_to_cpu(lirq), rc);
2512}
2513
2514static void dump_xives(void)
2515{
2516 unsigned long num;
2517 int c;
2518
Breno Leitao402e1722017-10-17 16:20:18 -02002519 if (!xive_enabled()) {
2520 printf("Xive disabled on this system\n");
2521 return;
2522 }
2523
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002524 c = inchar();
2525 if (c == 'a') {
2526 dump_all_xives();
2527 return;
2528 } else if (c == 'i') {
2529 if (scanhex(&num))
2530 dump_one_xive_irq(num);
2531 return;
2532 }
2533
2534 termch = c; /* Put c back, it wasn't 'a' */
2535
2536 if (scanhex(&num))
2537 dump_one_xive(num);
2538 else
2539 dump_one_xive(xmon_owner);
2540}
2541#endif /* CONFIG_PPC_POWERNV */
2542
Douglas Miller5e48dc02017-02-07 07:40:44 -06002543static void dump_by_size(unsigned long addr, long count, int size)
2544{
2545 unsigned char temp[16];
2546 int i, j;
2547 u64 val;
2548
2549 count = ALIGN(count, 16);
2550
2551 for (i = 0; i < count; i += 16, addr += 16) {
2552 printf(REG, addr);
2553
2554 if (mread(addr, temp, 16) != 16) {
2555 printf("\nFaulted reading %d bytes from 0x"REG"\n", 16, addr);
2556 return;
2557 }
2558
2559 for (j = 0; j < 16; j += size) {
2560 putchar(' ');
2561 switch (size) {
2562 case 1: val = temp[j]; break;
2563 case 2: val = *(u16 *)&temp[j]; break;
2564 case 4: val = *(u32 *)&temp[j]; break;
2565 case 8: val = *(u64 *)&temp[j]; break;
2566 default: val = 0;
2567 }
2568
2569 printf("%0*lx", size * 2, val);
2570 }
2571 printf("\n");
2572 }
2573}
2574
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002575static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576dump(void)
2577{
Douglas Miller5e48dc02017-02-07 07:40:44 -06002578 static char last[] = { "d?\n" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 int c;
2580
2581 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002582
2583#ifdef CONFIG_PPC64
2584 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002585 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002586 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002587 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002588 return;
2589 }
2590#endif
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002591#ifdef CONFIG_PPC_POWERNV
2592 if (c == 'x') {
2593 xmon_start_pagination();
2594 dump_xives();
2595 xmon_end_pagination();
2596 return;
2597 }
2598#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002599
Breno Leitao4125d012017-08-02 17:14:05 -03002600 if (c == 't') {
2601 dump_tracing();
2602 return;
2603 }
2604
Douglas Miller5e48dc02017-02-07 07:40:44 -06002605 if (c == '\n')
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 termch = c;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002607
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 scanhex((void *)&adrs);
2609 if (termch != '\n')
2610 termch = 0;
2611 if (c == 'i') {
2612 scanhex(&nidump);
2613 if (nidump == 0)
2614 nidump = 16;
2615 else if (nidump > MAX_DUMP)
2616 nidump = MAX_DUMP;
2617 adrs += ppc_inst_dump(adrs, nidump, 1);
2618 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002619 } else if (c == 'l') {
2620 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002621 } else if (c == 'o') {
2622 dump_opal_msglog();
Balbir Singh80eff6c2017-10-30 22:01:12 +11002623 } else if (c == 'v') {
2624 /* dump virtual to physical translation */
2625 show_pte(adrs);
Olaf Hering7e5b5932006-03-08 20:40:28 +01002626 } else if (c == 'r') {
2627 scanhex(&ndump);
2628 if (ndump == 0)
2629 ndump = 64;
2630 xmon_rawdump(adrs, ndump);
2631 adrs += ndump;
2632 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 } else {
2634 scanhex(&ndump);
2635 if (ndump == 0)
2636 ndump = 64;
2637 else if (ndump > MAX_DUMP)
2638 ndump = MAX_DUMP;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002639
2640 switch (c) {
2641 case '8':
2642 case '4':
2643 case '2':
2644 case '1':
2645 ndump = ALIGN(ndump, 16);
2646 dump_by_size(adrs, ndump, c - '0');
2647 last[1] = c;
2648 last_cmd = last;
2649 break;
2650 default:
2651 prdump(adrs, ndump);
2652 last_cmd = "d\n";
2653 }
2654
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 adrs += ndump;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 }
2657}
2658
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002659static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660prdump(unsigned long adrs, long ndump)
2661{
2662 long n, m, c, r, nr;
2663 unsigned char temp[16];
2664
2665 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002666 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 putchar(' ');
2668 r = n < 16? n: 16;
2669 nr = mread(adrs, temp, r);
2670 adrs += nr;
2671 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002672 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002673 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 if (m < nr)
2675 printf("%.2x", temp[m]);
2676 else
2677 printf("%s", fault_chars[fault_type]);
2678 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002679 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002680 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002681 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 printf(" |");
2685 for (m = 0; m < r; ++m) {
2686 if (m < nr) {
2687 c = temp[m];
2688 putchar(' ' <= c && c <= '~'? c: '.');
2689 } else
2690 putchar(' ');
2691 }
2692 n -= r;
2693 for (; m < 16; ++m)
2694 putchar(' ');
2695 printf("|\n");
2696 if (nr < r)
2697 break;
2698 }
2699}
2700
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002701typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2702
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002703static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002704generic_inst_dump(unsigned long adr, long count, int praddr,
2705 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706{
2707 int nr, dotted;
2708 unsigned long first_adr;
2709 unsigned long inst, last_inst = 0;
2710 unsigned char val[4];
2711
2712 dotted = 0;
2713 for (first_adr = adr; count > 0; --count, adr += 4) {
2714 nr = mread(adr, val, 4);
2715 if (nr == 0) {
2716 if (praddr) {
2717 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002718 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 }
2720 break;
2721 }
2722 inst = GETWORD(val);
2723 if (adr > first_adr && inst == last_inst) {
2724 if (!dotted) {
2725 printf(" ...\n");
2726 dotted = 1;
2727 }
2728 continue;
2729 }
2730 dotted = 0;
2731 last_inst = inst;
2732 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002733 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002735 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 printf("\n");
2737 }
2738 return adr - first_adr;
2739}
2740
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002741static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002742ppc_inst_dump(unsigned long adr, long count, int praddr)
2743{
2744 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2745}
2746
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747void
2748print_address(unsigned long addr)
2749{
2750 xmon_print_symbol(addr, "\t# ", "");
2751}
2752
Vinay Sridharf312deb2009-05-14 23:13:07 +00002753void
2754dump_log_buf(void)
2755{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002756 struct kmsg_dumper dumper = { .active = 1 };
2757 unsigned char buf[128];
2758 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002759
Michael Ellermane3bc8042012-08-23 22:09:13 +00002760 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002761 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002762 return;
2763 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002764
Michael Ellermane3bc8042012-08-23 22:09:13 +00002765 catch_memory_errors = 1;
2766 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002767
Michael Ellermanca5dd392012-08-23 22:09:12 +00002768 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002769 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002770 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2771 buf[len] = '\0';
2772 printf("%s", buf);
2773 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002774 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002775
Michael Ellermane3bc8042012-08-23 22:09:13 +00002776 sync();
2777 /* wait a little while to see if we get a machine check */
2778 __delay(200);
2779 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002780}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002782#ifdef CONFIG_PPC_POWERNV
2783static void dump_opal_msglog(void)
2784{
2785 unsigned char buf[128];
2786 ssize_t res;
2787 loff_t pos = 0;
2788
2789 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2790 printf("Machine is not running OPAL firmware.\n");
2791 return;
2792 }
2793
2794 if (setjmp(bus_error_jmp) != 0) {
2795 printf("Error dumping OPAL msglog!\n");
2796 return;
2797 }
2798
2799 catch_memory_errors = 1;
2800 sync();
2801
2802 xmon_start_pagination();
2803 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2804 if (res < 0) {
2805 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2806 break;
2807 }
2808 buf[res] = '\0';
2809 printf("%s", buf);
2810 pos += res;
2811 }
2812 xmon_end_pagination();
2813
2814 sync();
2815 /* wait a little while to see if we get a machine check */
2816 __delay(200);
2817 catch_memory_errors = 0;
2818}
2819#endif
2820
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821/*
2822 * Memory operations - move, set, print differences
2823 */
2824static unsigned long mdest; /* destination address */
2825static unsigned long msrc; /* source address */
2826static unsigned long mval; /* byte value to set memory to */
2827static unsigned long mcount; /* # bytes to affect */
2828static unsigned long mdiffs; /* max # differences to print */
2829
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002830static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831memops(int cmd)
2832{
2833 scanhex((void *)&mdest);
2834 if( termch != '\n' )
2835 termch = 0;
2836 scanhex((void *)(cmd == 's'? &mval: &msrc));
2837 if( termch != '\n' )
2838 termch = 0;
2839 scanhex((void *)&mcount);
2840 switch( cmd ){
2841 case 'm':
2842 memmove((void *)mdest, (void *)msrc, mcount);
2843 break;
2844 case 's':
2845 memset((void *)mdest, mval, mcount);
2846 break;
2847 case 'd':
2848 if( termch != '\n' )
2849 termch = 0;
2850 scanhex((void *)&mdiffs);
2851 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2852 break;
2853 }
2854}
2855
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002856static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2858{
2859 unsigned n, prt;
2860
2861 prt = 0;
2862 for( n = nb; n > 0; --n )
2863 if( *p1++ != *p2++ )
2864 if( ++prt <= maxpr )
2865 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2866 p1[-1], p2 - 1, p2[-1]);
2867 if( prt > maxpr )
2868 printf("Total of %d differences\n", prt);
2869}
2870
2871static unsigned mend;
2872static unsigned mask;
2873
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002874static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875memlocate(void)
2876{
2877 unsigned a, n;
2878 unsigned char val[4];
2879
2880 last_cmd = "ml";
2881 scanhex((void *)&mdest);
2882 if (termch != '\n') {
2883 termch = 0;
2884 scanhex((void *)&mend);
2885 if (termch != '\n') {
2886 termch = 0;
2887 scanhex((void *)&mval);
2888 mask = ~0;
2889 if (termch != '\n') termch = 0;
2890 scanhex((void *)&mask);
2891 }
2892 }
2893 n = 0;
2894 for (a = mdest; a < mend; a += 4) {
2895 if (mread(a, val, 4) == 4
2896 && ((GETWORD(val) ^ mval) & mask) == 0) {
2897 printf("%.16x: %.16x\n", a, GETWORD(val));
2898 if (++n >= 10)
2899 break;
2900 }
2901 }
2902}
2903
2904static unsigned long mskip = 0x1000;
2905static unsigned long mlim = 0xffffffff;
2906
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002907static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908memzcan(void)
2909{
2910 unsigned char v;
2911 unsigned a;
2912 int ok, ook;
2913
2914 scanhex(&mdest);
2915 if (termch != '\n') termch = 0;
2916 scanhex(&mskip);
2917 if (termch != '\n') termch = 0;
2918 scanhex(&mlim);
2919 ook = 0;
2920 for (a = mdest; a < mlim; a += mskip) {
2921 ok = mread(a, &v, 1);
2922 if (ok && !ook) {
2923 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 } else if (!ok && ook)
2925 printf("%.8x\n", a - mskip);
2926 ook = ok;
2927 if (a + mskip < a)
2928 break;
2929 }
2930 if (ook)
2931 printf("%.8x\n", a - mskip);
2932}
2933
Douglas Miller6dfb5402015-11-23 09:01:15 -06002934static void show_task(struct task_struct *tsk)
2935{
2936 char state;
2937
2938 /*
2939 * Cloned from kdb_task_state_char(), which is not entirely
2940 * appropriate for calling from xmon. This could be moved
2941 * to a common, generic, routine used by both.
2942 */
2943 state = (tsk->state == 0) ? 'R' :
2944 (tsk->state < 0) ? 'U' :
2945 (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
2946 (tsk->state & TASK_STOPPED) ? 'T' :
2947 (tsk->state & TASK_TRACED) ? 'C' :
2948 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
2949 (tsk->exit_state & EXIT_DEAD) ? 'E' :
2950 (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
2951
Michael Ellermand8104182017-12-06 23:23:28 +11002952 printf("%px %016lx %6d %6d %c %2d %s\n", tsk,
Douglas Miller6dfb5402015-11-23 09:01:15 -06002953 tsk->thread.ksp,
2954 tsk->pid, tsk->parent->pid,
2955 state, task_thread_info(tsk)->cpu,
2956 tsk->comm);
2957}
2958
Balbir Singh80eff6c2017-10-30 22:01:12 +11002959#ifdef CONFIG_PPC_BOOK3S_64
2960void format_pte(void *ptep, unsigned long pte)
2961{
2962 printf("ptep @ 0x%016lx = 0x%016lx\n", (unsigned long)ptep, pte);
2963 printf("Maps physical address = 0x%016lx\n", pte & PTE_RPN_MASK);
2964
2965 printf("Flags = %s%s%s%s%s\n",
2966 (pte & _PAGE_ACCESSED) ? "Accessed " : "",
2967 (pte & _PAGE_DIRTY) ? "Dirty " : "",
2968 (pte & _PAGE_READ) ? "Read " : "",
2969 (pte & _PAGE_WRITE) ? "Write " : "",
2970 (pte & _PAGE_EXEC) ? "Exec " : "");
2971}
2972
2973static void show_pte(unsigned long addr)
2974{
2975 unsigned long tskv = 0;
2976 struct task_struct *tsk = NULL;
2977 struct mm_struct *mm;
2978 pgd_t *pgdp, *pgdir;
2979 pud_t *pudp;
2980 pmd_t *pmdp;
2981 pte_t *ptep;
2982
2983 if (!scanhex(&tskv))
2984 mm = &init_mm;
2985 else
2986 tsk = (struct task_struct *)tskv;
2987
2988 if (tsk == NULL)
2989 mm = &init_mm;
2990 else
2991 mm = tsk->active_mm;
2992
2993 if (setjmp(bus_error_jmp) != 0) {
2994 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11002995 printf("*** Error dumping pte for task %px\n", tsk);
Balbir Singh80eff6c2017-10-30 22:01:12 +11002996 return;
2997 }
2998
2999 catch_memory_errors = 1;
3000 sync();
3001
3002 if (mm == &init_mm) {
3003 pgdp = pgd_offset_k(addr);
3004 pgdir = pgd_offset_k(0);
3005 } else {
3006 pgdp = pgd_offset(mm, addr);
3007 pgdir = pgd_offset(mm, 0);
3008 }
3009
3010 if (pgd_none(*pgdp)) {
3011 printf("no linux page table for address\n");
3012 return;
3013 }
3014
3015 printf("pgd @ 0x%016lx\n", pgdir);
3016
3017 if (pgd_huge(*pgdp)) {
3018 format_pte(pgdp, pgd_val(*pgdp));
3019 return;
3020 }
3021 printf("pgdp @ 0x%016lx = 0x%016lx\n", pgdp, pgd_val(*pgdp));
3022
3023 pudp = pud_offset(pgdp, addr);
3024
3025 if (pud_none(*pudp)) {
3026 printf("No valid PUD\n");
3027 return;
3028 }
3029
3030 if (pud_huge(*pudp)) {
3031 format_pte(pudp, pud_val(*pudp));
3032 return;
3033 }
3034
3035 printf("pudp @ 0x%016lx = 0x%016lx\n", pudp, pud_val(*pudp));
3036
3037 pmdp = pmd_offset(pudp, addr);
3038
3039 if (pmd_none(*pmdp)) {
3040 printf("No valid PMD\n");
3041 return;
3042 }
3043
3044 if (pmd_huge(*pmdp)) {
3045 format_pte(pmdp, pmd_val(*pmdp));
3046 return;
3047 }
3048 printf("pmdp @ 0x%016lx = 0x%016lx\n", pmdp, pmd_val(*pmdp));
3049
3050 ptep = pte_offset_map(pmdp, addr);
3051 if (pte_none(*ptep)) {
3052 printf("no valid PTE\n");
3053 return;
3054 }
3055
3056 format_pte(ptep, pte_val(*ptep));
3057
3058 sync();
3059 __delay(200);
3060 catch_memory_errors = 0;
3061}
3062#else
3063static void show_pte(unsigned long addr)
3064{
3065 printf("show_pte not yet implemented\n");
3066}
3067#endif /* CONFIG_PPC_BOOK3S_64 */
3068
Douglas Miller6dfb5402015-11-23 09:01:15 -06003069static void show_tasks(void)
3070{
3071 unsigned long tskv;
3072 struct task_struct *tsk = NULL;
3073
3074 printf(" task_struct ->thread.ksp PID PPID S P CMD\n");
3075
3076 if (scanhex(&tskv))
3077 tsk = (struct task_struct *)tskv;
3078
3079 if (setjmp(bus_error_jmp) != 0) {
3080 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11003081 printf("*** Error dumping task %px\n", tsk);
Douglas Miller6dfb5402015-11-23 09:01:15 -06003082 return;
3083 }
3084
3085 catch_memory_errors = 1;
3086 sync();
3087
3088 if (tsk)
3089 show_task(tsk);
3090 else
3091 for_each_process(tsk)
3092 show_task(tsk);
3093
3094 sync();
3095 __delay(200);
3096 catch_memory_errors = 0;
3097}
3098
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003099static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003100{
3101 unsigned long args[8];
3102 unsigned long ret;
3103 int i;
3104 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
3105 unsigned long, unsigned long, unsigned long,
3106 unsigned long, unsigned long, unsigned long);
3107 callfunc_t func;
3108
3109 if (!scanhex(&adrs))
3110 return;
3111 if (termch != '\n')
3112 termch = 0;
3113 for (i = 0; i < 8; ++i)
3114 args[i] = 0;
3115 for (i = 0; i < 8; ++i) {
3116 if (!scanhex(&args[i]) || termch == '\n')
3117 break;
3118 termch = 0;
3119 }
3120 func = (callfunc_t) adrs;
3121 ret = 0;
3122 if (setjmp(bus_error_jmp) == 0) {
3123 catch_memory_errors = 1;
3124 sync();
3125 ret = func(args[0], args[1], args[2], args[3],
3126 args[4], args[5], args[6], args[7]);
3127 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10003128 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003129 } else {
3130 printf("*** %x exception occurred\n", fault_except);
3131 }
3132 catch_memory_errors = 0;
3133}
3134
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135/* Input scanning routines */
3136int
3137skipbl(void)
3138{
3139 int c;
3140
3141 if( termch != 0 ){
3142 c = termch;
3143 termch = 0;
3144 } else
3145 c = inchar();
3146 while( c == ' ' || c == '\t' )
3147 c = inchar();
3148 return c;
3149}
3150
3151#define N_PTREGS 44
3152static char *regnames[N_PTREGS] = {
3153 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
3154 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
3155 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
3156 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003157 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
3158#ifdef CONFIG_PPC64
3159 "softe",
3160#else
3161 "mq",
3162#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 "trap", "dar", "dsisr", "res"
3164};
3165
3166int
3167scanhex(unsigned long *vp)
3168{
3169 int c, d;
3170 unsigned long v;
3171
3172 c = skipbl();
3173 if (c == '%') {
3174 /* parse register name */
3175 char regname[8];
3176 int i;
3177
3178 for (i = 0; i < sizeof(regname) - 1; ++i) {
3179 c = inchar();
3180 if (!isalnum(c)) {
3181 termch = c;
3182 break;
3183 }
3184 regname[i] = c;
3185 }
3186 regname[i] = 0;
3187 for (i = 0; i < N_PTREGS; ++i) {
3188 if (strcmp(regnames[i], regname) == 0) {
3189 if (xmon_regs == NULL) {
3190 printf("regs not available\n");
3191 return 0;
3192 }
3193 *vp = ((unsigned long *)xmon_regs)[i];
3194 return 1;
3195 }
3196 }
3197 printf("invalid register name '%%%s'\n", regname);
3198 return 0;
3199 }
3200
3201 /* skip leading "0x" if any */
3202
3203 if (c == '0') {
3204 c = inchar();
3205 if (c == 'x') {
3206 c = inchar();
3207 } else {
3208 d = hexdigit(c);
3209 if (d == EOF) {
3210 termch = c;
3211 *vp = 0;
3212 return 1;
3213 }
3214 }
3215 } else if (c == '$') {
3216 int i;
3217 for (i=0; i<63; i++) {
3218 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02003219 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 termch = c;
3221 break;
3222 }
3223 tmpstr[i] = c;
3224 }
3225 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07003226 *vp = 0;
3227 if (setjmp(bus_error_jmp) == 0) {
3228 catch_memory_errors = 1;
3229 sync();
3230 *vp = kallsyms_lookup_name(tmpstr);
3231 sync();
3232 }
3233 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 if (!(*vp)) {
3235 printf("unknown symbol '%s'\n", tmpstr);
3236 return 0;
3237 }
3238 return 1;
3239 }
3240
3241 d = hexdigit(c);
3242 if (d == EOF) {
3243 termch = c;
3244 return 0;
3245 }
3246 v = 0;
3247 do {
3248 v = (v << 4) + d;
3249 c = inchar();
3250 d = hexdigit(c);
3251 } while (d != EOF);
3252 termch = c;
3253 *vp = v;
3254 return 1;
3255}
3256
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003257static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258scannl(void)
3259{
3260 int c;
3261
3262 c = termch;
3263 termch = 0;
3264 while( c != '\n' )
3265 c = inchar();
3266}
3267
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003268static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269{
3270 if( '0' <= c && c <= '9' )
3271 return c - '0';
3272 if( 'A' <= c && c <= 'F' )
3273 return c - ('A' - 10);
3274 if( 'a' <= c && c <= 'f' )
3275 return c - ('a' - 10);
3276 return EOF;
3277}
3278
3279void
3280getstring(char *s, int size)
3281{
3282 int c;
3283
3284 c = skipbl();
3285 do {
3286 if( size > 1 ){
3287 *s++ = c;
3288 --size;
3289 }
3290 c = inchar();
3291 } while( c != ' ' && c != '\t' && c != '\n' );
3292 termch = c;
3293 *s = 0;
3294}
3295
3296static char line[256];
3297static char *lineptr;
3298
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003299static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300flush_input(void)
3301{
3302 lineptr = NULL;
3303}
3304
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003305static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306inchar(void)
3307{
3308 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003309 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 lineptr = NULL;
3311 return EOF;
3312 }
3313 lineptr = line;
3314 }
3315 return *lineptr++;
3316}
3317
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003318static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319take_input(char *str)
3320{
3321 lineptr = str;
3322}
3323
3324
3325static void
3326symbol_lookup(void)
3327{
3328 int type = inchar();
3329 unsigned long addr;
3330 static char tmp[64];
3331
3332 switch (type) {
3333 case 'a':
3334 if (scanhex(&addr))
3335 xmon_print_symbol(addr, ": ", "\n");
3336 termch = 0;
3337 break;
3338 case 's':
3339 getstring(tmp, 64);
3340 if (setjmp(bus_error_jmp) == 0) {
3341 catch_memory_errors = 1;
3342 sync();
3343 addr = kallsyms_lookup_name(tmp);
3344 if (addr)
3345 printf("%s: %lx\n", tmp, addr);
3346 else
3347 printf("Symbol '%s' not found.\n", tmp);
3348 sync();
3349 }
3350 catch_memory_errors = 0;
3351 termch = 0;
3352 break;
3353 }
3354}
3355
3356
3357/* Print an address in numeric and symbolic form (if possible) */
3358static void xmon_print_symbol(unsigned long address, const char *mid,
3359 const char *after)
3360{
3361 char *modname;
3362 const char *name = NULL;
3363 unsigned long offset, size;
3364
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003365 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 if (setjmp(bus_error_jmp) == 0) {
3367 catch_memory_errors = 1;
3368 sync();
3369 name = kallsyms_lookup(address, &size, &offset, &modname,
3370 tmpstr);
3371 sync();
3372 /* wait a little while to see if we get a machine check */
3373 __delay(200);
3374 }
3375
3376 catch_memory_errors = 0;
3377
3378 if (name) {
3379 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
3380 if (modname)
3381 printf(" [%s]", modname);
3382 }
3383 printf("%s", after);
3384}
3385
Michael Ellerman4e003742017-10-19 15:08:43 +11003386#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10003387void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388{
3389 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05303390 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11003391 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392
Michael Ellerman736256e2014-05-26 21:02:14 +10003393 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394
Michael Neuling584f8b72007-12-06 17:24:48 +11003395 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11003396 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
3397 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Michael Ellerman85673642017-04-24 10:35:14 +10003398
3399 if (!esid && !vsid)
3400 continue;
3401
3402 printf("%02d %016lx %016lx", i, esid, vsid);
3403
3404 if (!(esid & SLB_ESID_V)) {
3405 printf("\n");
3406 continue;
3407 }
3408
3409 llp = vsid & SLB_VSID_LLP;
3410 if (vsid & SLB_VSID_B_1T) {
3411 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
3412 GET_ESID_1T(esid),
3413 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
3414 llp);
3415 } else {
3416 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
3417 GET_ESID(esid),
3418 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
3419 llp);
will schmidtb3b95952007-12-07 08:22:23 +11003420 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 }
3422}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003423#endif
3424
3425#ifdef CONFIG_PPC_STD_MMU_32
3426void dump_segments(void)
3427{
3428 int i;
3429
3430 printf("sr0-15 =");
3431 for (i = 0; i < 16; ++i)
3432 printf(" %x", mfsrin(i));
3433 printf("\n");
3434}
3435#endif
3436
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003437#ifdef CONFIG_44x
3438static void dump_tlb_44x(void)
3439{
3440 int i;
3441
3442 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
3443 unsigned long w0,w1,w2;
3444 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
3445 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
3446 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
3447 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
3448 if (w0 & PPC44x_TLB_VALID) {
3449 printf("V %08x -> %01x%08x %c%c%c%c%c",
3450 w0 & PPC44x_TLB_EPN_MASK,
3451 w1 & PPC44x_TLB_ERPN_MASK,
3452 w1 & PPC44x_TLB_RPN_MASK,
3453 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
3454 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
3455 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
3456 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
3457 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
3458 }
3459 printf("\n");
3460 }
3461}
3462#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003463
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10003464#ifdef CONFIG_PPC_BOOK3E
3465static void dump_tlb_book3e(void)
3466{
3467 u32 mmucfg, pidmask, lpidmask;
3468 u64 ramask;
3469 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3470 int mmu_version;
3471 static const char *pgsz_names[] = {
3472 " 1K",
3473 " 2K",
3474 " 4K",
3475 " 8K",
3476 " 16K",
3477 " 32K",
3478 " 64K",
3479 "128K",
3480 "256K",
3481 "512K",
3482 " 1M",
3483 " 2M",
3484 " 4M",
3485 " 8M",
3486 " 16M",
3487 " 32M",
3488 " 64M",
3489 "128M",
3490 "256M",
3491 "512M",
3492 " 1G",
3493 " 2G",
3494 " 4G",
3495 " 8G",
3496 " 16G",
3497 " 32G",
3498 " 64G",
3499 "128G",
3500 "256G",
3501 "512G",
3502 " 1T",
3503 " 2T",
3504 };
3505
3506 /* Gather some infos about the MMU */
3507 mmucfg = mfspr(SPRN_MMUCFG);
3508 mmu_version = (mmucfg & 3) + 1;
3509 ntlbs = ((mmucfg >> 2) & 3) + 1;
3510 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3511 lpidsz = (mmucfg >> 24) & 0xf;
3512 rasz = (mmucfg >> 16) & 0x7f;
3513 if ((mmu_version > 1) && (mmucfg & 0x10000))
3514 lrat = 1;
3515 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3516 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3517 pidmask = (1ul << pidsz) - 1;
3518 lpidmask = (1ul << lpidsz) - 1;
3519 ramask = (1ull << rasz) - 1;
3520
3521 for (tlb = 0; tlb < ntlbs; tlb++) {
3522 u32 tlbcfg;
3523 int nent, assoc, new_cc = 1;
3524 printf("TLB %d:\n------\n", tlb);
3525 switch(tlb) {
3526 case 0:
3527 tlbcfg = mfspr(SPRN_TLB0CFG);
3528 break;
3529 case 1:
3530 tlbcfg = mfspr(SPRN_TLB1CFG);
3531 break;
3532 case 2:
3533 tlbcfg = mfspr(SPRN_TLB2CFG);
3534 break;
3535 case 3:
3536 tlbcfg = mfspr(SPRN_TLB3CFG);
3537 break;
3538 default:
3539 printf("Unsupported TLB number !\n");
3540 continue;
3541 }
3542 nent = tlbcfg & 0xfff;
3543 assoc = (tlbcfg >> 24) & 0xff;
3544 for (i = 0; i < nent; i++) {
3545 u32 mas0 = MAS0_TLBSEL(tlb);
3546 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3547 u64 mas2 = 0;
3548 u64 mas7_mas3;
3549 int esel = i, cc = i;
3550
3551 if (assoc != 0) {
3552 cc = i / assoc;
3553 esel = i % assoc;
3554 mas2 = cc * 0x1000;
3555 }
3556
3557 mas0 |= MAS0_ESEL(esel);
3558 mtspr(SPRN_MAS0, mas0);
3559 mtspr(SPRN_MAS1, mas1);
3560 mtspr(SPRN_MAS2, mas2);
3561 asm volatile("tlbre 0,0,0" : : : "memory");
3562 mas1 = mfspr(SPRN_MAS1);
3563 mas2 = mfspr(SPRN_MAS2);
3564 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3565 if (assoc && (i % assoc) == 0)
3566 new_cc = 1;
3567 if (!(mas1 & MAS1_VALID))
3568 continue;
3569 if (assoc == 0)
3570 printf("%04x- ", i);
3571 else if (new_cc)
3572 printf("%04x-%c", cc, 'A' + esel);
3573 else
3574 printf(" |%c", 'A' + esel);
3575 new_cc = 0;
3576 printf(" %016llx %04x %s %c%c AS%c",
3577 mas2 & ~0x3ffull,
3578 (mas1 >> 16) & 0x3fff,
3579 pgsz_names[(mas1 >> 7) & 0x1f],
3580 mas1 & MAS1_IND ? 'I' : ' ',
3581 mas1 & MAS1_IPROT ? 'P' : ' ',
3582 mas1 & MAS1_TS ? '1' : '0');
3583 printf(" %c%c%c%c%c%c%c",
3584 mas2 & MAS2_X0 ? 'a' : ' ',
3585 mas2 & MAS2_X1 ? 'v' : ' ',
3586 mas2 & MAS2_W ? 'w' : ' ',
3587 mas2 & MAS2_I ? 'i' : ' ',
3588 mas2 & MAS2_M ? 'm' : ' ',
3589 mas2 & MAS2_G ? 'g' : ' ',
3590 mas2 & MAS2_E ? 'e' : ' ');
3591 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3592 if (mas1 & MAS1_IND)
3593 printf(" %s\n",
3594 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3595 else
3596 printf(" U%c%c%c S%c%c%c\n",
3597 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3598 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3599 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3600 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3601 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3602 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3603 }
3604 }
3605}
3606#endif /* CONFIG_PPC_BOOK3E */
3607
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003608static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003610 if (enable) {
3611 __debugger = xmon;
3612 __debugger_ipi = xmon_ipi;
3613 __debugger_bpt = xmon_bpt;
3614 __debugger_sstep = xmon_sstep;
3615 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003616 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003617 __debugger_fault_handler = xmon_fault_handler;
3618 } else {
3619 __debugger = NULL;
3620 __debugger_ipi = NULL;
3621 __debugger_bpt = NULL;
3622 __debugger_sstep = NULL;
3623 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003624 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003625 __debugger_fault_handler = NULL;
3626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003628
3629#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003630static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003631{
3632 /* ensure xmon is enabled */
3633 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003634 debugger(get_irq_regs());
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003635 if (!xmon_on)
3636 xmon_init(0);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003637}
3638
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003639static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003640 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003641 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003642 .action_msg = "Entering xmon",
3643};
3644
3645static int __init setup_xmon_sysrq(void)
3646{
3647 register_sysrq_key('x', &sysrq_xmon_op);
3648 return 0;
3649}
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003650device_initcall(setup_xmon_sysrq);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003651#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003652
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003653#ifdef CONFIG_DEBUG_FS
3654static int xmon_dbgfs_set(void *data, u64 val)
3655{
3656 xmon_on = !!val;
3657 xmon_init(xmon_on);
3658
3659 return 0;
3660}
3661
3662static int xmon_dbgfs_get(void *data, u64 *val)
3663{
3664 *val = xmon_on;
3665 return 0;
3666}
3667
3668DEFINE_SIMPLE_ATTRIBUTE(xmon_dbgfs_ops, xmon_dbgfs_get,
3669 xmon_dbgfs_set, "%llu\n");
3670
3671static int __init setup_xmon_dbgfs(void)
3672{
3673 debugfs_create_file("xmon", 0600, powerpc_debugfs_root, NULL,
3674 &xmon_dbgfs_ops);
3675 return 0;
3676}
3677device_initcall(setup_xmon_dbgfs);
3678#endif /* CONFIG_DEBUG_FS */
3679
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003680static int xmon_early __initdata;
Michael Ellerman476792832006-10-03 14:12:08 +10003681
3682static int __init early_parse_xmon(char *p)
3683{
3684 if (!p || strncmp(p, "early", 5) == 0) {
3685 /* just "xmon" is equivalent to "xmon=early" */
3686 xmon_init(1);
3687 xmon_early = 1;
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003688 xmon_on = 1;
3689 } else if (strncmp(p, "on", 2) == 0) {
Michael Ellerman476792832006-10-03 14:12:08 +10003690 xmon_init(1);
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003691 xmon_on = 1;
3692 } else if (strncmp(p, "off", 3) == 0)
3693 xmon_on = 0;
Michael Ellerman476792832006-10-03 14:12:08 +10003694 else
3695 return 1;
3696
3697 return 0;
3698}
3699early_param("xmon", early_parse_xmon);
3700
3701void __init xmon_setup(void)
3702{
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003703 if (xmon_on)
Michael Ellerman476792832006-10-03 14:12:08 +10003704 xmon_init(1);
Michael Ellerman476792832006-10-03 14:12:08 +10003705 if (xmon_early)
3706 debugger(NULL);
3707}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003708
Arnd Bergmanne0555952006-11-27 19:18:55 +01003709#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003710
3711struct spu_info {
3712 struct spu *spu;
3713 u64 saved_mfc_sr1_RW;
3714 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003715 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003716 u8 stopped_ok;
3717};
3718
3719#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3720
3721static struct spu_info spu_info[XMON_NUM_SPUS];
3722
3723void xmon_register_spus(struct list_head *list)
3724{
3725 struct spu *spu;
3726
3727 list_for_each_entry(spu, list, full_list) {
3728 if (spu->number >= XMON_NUM_SPUS) {
3729 WARN_ON(1);
3730 continue;
3731 }
3732
3733 spu_info[spu->number].spu = spu;
3734 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003735 spu_info[spu->number].dump_addr = (unsigned long)
3736 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003737 }
3738}
3739
3740static void stop_spus(void)
3741{
3742 struct spu *spu;
3743 int i;
3744 u64 tmp;
3745
3746 for (i = 0; i < XMON_NUM_SPUS; i++) {
3747 if (!spu_info[i].spu)
3748 continue;
3749
3750 if (setjmp(bus_error_jmp) == 0) {
3751 catch_memory_errors = 1;
3752 sync();
3753
3754 spu = spu_info[i].spu;
3755
3756 spu_info[i].saved_spu_runcntl_RW =
3757 in_be32(&spu->problem->spu_runcntl_RW);
3758
3759 tmp = spu_mfc_sr1_get(spu);
3760 spu_info[i].saved_mfc_sr1_RW = tmp;
3761
3762 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3763 spu_mfc_sr1_set(spu, tmp);
3764
3765 sync();
3766 __delay(200);
3767
3768 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003769
3770 printf("Stopped spu %.2d (was %s)\n", i,
3771 spu_info[i].saved_spu_runcntl_RW ?
3772 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003773 } else {
3774 catch_memory_errors = 0;
3775 printf("*** Error stopping spu %.2d\n", i);
3776 }
3777 catch_memory_errors = 0;
3778 }
3779}
3780
3781static void restart_spus(void)
3782{
3783 struct spu *spu;
3784 int i;
3785
3786 for (i = 0; i < XMON_NUM_SPUS; i++) {
3787 if (!spu_info[i].spu)
3788 continue;
3789
3790 if (!spu_info[i].stopped_ok) {
3791 printf("*** Error, spu %d was not successfully stopped"
3792 ", not restarting\n", i);
3793 continue;
3794 }
3795
3796 if (setjmp(bus_error_jmp) == 0) {
3797 catch_memory_errors = 1;
3798 sync();
3799
3800 spu = spu_info[i].spu;
3801 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3802 out_be32(&spu->problem->spu_runcntl_RW,
3803 spu_info[i].saved_spu_runcntl_RW);
3804
3805 sync();
3806 __delay(200);
3807
3808 printf("Restarted spu %.2d\n", i);
3809 } else {
3810 catch_memory_errors = 0;
3811 printf("*** Error restarting spu %.2d\n", i);
3812 }
3813 catch_memory_errors = 0;
3814 }
3815}
3816
Michael Ellermana8984972006-10-24 18:31:28 +02003817#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003818#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003819do { \
3820 if (setjmp(bus_error_jmp) == 0) { \
3821 catch_memory_errors = 1; \
3822 sync(); \
3823 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003824 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003825 sync(); \
3826 __delay(200); \
3827 } else { \
3828 catch_memory_errors = 0; \
3829 printf(" %-*s = *** Error reading field.\n", \
3830 DUMP_WIDTH, #field); \
3831 } \
3832 catch_memory_errors = 0; \
3833} while (0)
3834
Michael Ellerman437a0702006-11-23 00:46:39 +01003835#define DUMP_FIELD(obj, format, field) \
3836 DUMP_VALUE(format, field, obj->field)
3837
Michael Ellermana8984972006-10-24 18:31:28 +02003838static void dump_spu_fields(struct spu *spu)
3839{
3840 printf("Dumping spu fields at address %p:\n", spu);
3841
3842 DUMP_FIELD(spu, "0x%x", number);
3843 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003844 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3845 DUMP_FIELD(spu, "0x%p", local_store);
3846 DUMP_FIELD(spu, "0x%lx", ls_size);
3847 DUMP_FIELD(spu, "0x%x", node);
3848 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003849 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003850 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003851 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3852 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003853 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3854 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3855 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3856 DUMP_FIELD(spu, "0x%x", slb_replace);
3857 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003858 DUMP_FIELD(spu, "0x%p", mm);
3859 DUMP_FIELD(spu, "0x%p", ctx);
3860 DUMP_FIELD(spu, "0x%p", rq);
3861 DUMP_FIELD(spu, "0x%p", timestamp);
3862 DUMP_FIELD(spu, "0x%lx", problem_phys);
3863 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003864 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3865 in_be32(&spu->problem->spu_runcntl_RW));
3866 DUMP_VALUE("0x%x", problem->spu_status_R,
3867 in_be32(&spu->problem->spu_status_R));
3868 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3869 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003870 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003871 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003872}
3873
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003874int
3875spu_inst_dump(unsigned long adr, long count, int praddr)
3876{
3877 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3878}
3879
3880static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003881{
3882 unsigned long offset, addr, ls_addr;
3883
3884 if (setjmp(bus_error_jmp) == 0) {
3885 catch_memory_errors = 1;
3886 sync();
3887 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3888 sync();
3889 __delay(200);
3890 } else {
3891 catch_memory_errors = 0;
3892 printf("*** Error: accessing spu info for spu %d\n", num);
3893 return;
3894 }
3895 catch_memory_errors = 0;
3896
3897 if (scanhex(&offset))
3898 addr = ls_addr + offset;
3899 else
3900 addr = spu_info[num].dump_addr;
3901
3902 if (addr >= ls_addr + LS_SIZE) {
3903 printf("*** Error: address outside of local store\n");
3904 return;
3905 }
3906
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003907 switch (subcmd) {
3908 case 'i':
3909 addr += spu_inst_dump(addr, 16, 1);
3910 last_cmd = "sdi\n";
3911 break;
3912 default:
3913 prdump(addr, 64);
3914 addr += 64;
3915 last_cmd = "sd\n";
3916 break;
3917 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003918
3919 spu_info[num].dump_addr = addr;
3920}
3921
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003922static int do_spu_cmd(void)
3923{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003924 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003925 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003926
3927 cmd = inchar();
3928 switch (cmd) {
3929 case 's':
3930 stop_spus();
3931 break;
3932 case 'r':
3933 restart_spus();
3934 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003935 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003936 subcmd = inchar();
3937 if (isxdigit(subcmd) || subcmd == '\n')
3938 termch = subcmd;
3939 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003940 scanhex(&num);
3941 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003942 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003943 return 0;
3944 }
3945
3946 switch (cmd) {
3947 case 'f':
3948 dump_spu_fields(spu_info[num].spu);
3949 break;
3950 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003951 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003952 break;
3953 }
3954
Michael Ellermana8984972006-10-24 18:31:28 +02003955 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003956 default:
3957 return -1;
3958 }
3959
3960 return 0;
3961}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003962#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003963static int do_spu_cmd(void)
3964{
3965 return -1;
3966}
3967#endif