blob: a06cf6e38978163f8f3a9d2fe747981791398ffe [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>
Michael Ellermanab83dc72018-03-08 13:54:42 +110044#include <asm/plpar_wrappers.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <asm/cputable.h>
46#include <asm/rtas.h>
47#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100048#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020049#include <asm/spu.h>
50#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110051#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000052#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010053#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000054#include <asm/hw_breakpoint.h>
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +100055#include <asm/xive.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110056#include <asm/opal.h>
57#include <asm/firmware.h>
Balbir Singhefe4fbb2017-06-27 17:48:58 +100058#include <asm/code-patching.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110059
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100060#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100062#include <asm/paca.h>
63#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010066#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100069static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static unsigned long xmon_taken = 1;
71static int xmon_owner;
72static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000073#else
74#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#endif /* CONFIG_SMP */
76
Anton Blanchard5be34922010-01-12 00:50:14 +000077static unsigned long in_xmon __read_mostly = 0;
Pan Xinhui3b5bf422017-03-22 16:27:49 -030078static int xmon_on = IS_ENABLED(CONFIG_XMON_DEFAULT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80static unsigned long adrs;
81static int size = 1;
82#define MAX_DUMP (128 * 1024)
83static unsigned long ndump = 64;
84static unsigned long nidump = 16;
85static unsigned long ncsum = 4096;
86static int termch;
87static char tmpstr[128];
Breno Leitaoed49f7f2017-08-02 17:14:06 -030088static int tracing_enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static long bus_error_jmp[JMP_BUF_LEN];
91static int catch_memory_errors;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +100092static int catch_spr_faults;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95/* Breakpoint stuff */
96struct bpt {
97 unsigned long address;
98 unsigned int instr[2];
99 atomic_t ref_count;
100 int enabled;
101 unsigned long pad;
102};
103
104/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100105#define BP_CIABR 1
106#define BP_TRAP 2
107#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
109#define NBPTS 256
110static struct bpt bpts[NBPTS];
111static struct bpt dabr;
112static struct bpt *iabr;
113static unsigned bpinstr = 0x7fe00008; /* trap */
114
115#define BP_NUM(bp) ((bp) - bpts + 1)
116
117/* Prototypes */
118static int cmds(struct pt_regs *);
119static int mread(unsigned long, void *, int);
120static int mwrite(unsigned long, void *, int);
121static int handle_fault(struct pt_regs *);
122static void byterev(unsigned char *, int);
123static void memex(void);
124static int bsesc(void);
125static void dump(void);
Balbir Singh80eff6c2017-10-30 22:01:12 +1100126static void show_pte(unsigned long);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127static void prdump(unsigned long, long);
128static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000129static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100130
131#ifdef CONFIG_PPC_POWERNV
132static void dump_opal_msglog(void);
133#else
134static inline void dump_opal_msglog(void)
135{
136 printf("Machine is not running OPAL firmware.\n");
137}
138#endif
139
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140static void backtrace(struct pt_regs *);
141static void excprint(struct pt_regs *);
142static void prregs(struct pt_regs *);
143static void memops(int);
144static void memlocate(void);
145static void memzcan(void);
146static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
147int skipbl(void);
148int scanhex(unsigned long *valp);
149static void scannl(void);
150static int hexdigit(int);
151void getstring(char *, int);
152static void flush_input(void);
153static int inchar(void);
154static void take_input(char *);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000155static int read_spr(int, unsigned long *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156static void write_spr(int, unsigned long);
157static void super_regs(void);
158static void remove_bpts(void);
159static void insert_bpts(void);
160static void remove_cpu_bpts(void);
161static void insert_cpu_bpts(void);
162static struct bpt *at_breakpoint(unsigned long pc);
163static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
164static int do_step(struct pt_regs *);
165static void bpt_cmds(void);
166static void cacheflush(void);
167static int cpu_cmd(void);
168static void csum(void);
169static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000170static void proccall(void);
Douglas Miller6dfb5402015-11-23 09:01:15 -0600171static void show_tasks(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172void dump_segments(void);
173static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200174static void xmon_show_stack(unsigned long sp, unsigned long lr,
175 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176static void xmon_print_symbol(unsigned long address, const char *mid,
177 const char *after);
178static const char *getvecname(unsigned long vec);
179
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200180static int do_spu_cmd(void);
181
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100182#ifdef CONFIG_44x
183static void dump_tlb_44x(void);
184#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000185#ifdef CONFIG_PPC_BOOK3E
186static void dump_tlb_book3e(void);
187#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100188
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000189#ifdef CONFIG_PPC64
190#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000191#else
192#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000193#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100195#ifdef __LITTLE_ENDIAN__
196#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
197#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100199#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201static char *help_string = "\
202Commands:\n\
203 b show breakpoints\n\
204 bd set data breakpoint\n\
205 bi set instruction breakpoint\n\
206 bc clear breakpoint\n"
207#ifdef CONFIG_SMP
208 "\
209 c print cpus stopped in xmon\n\
210 c# try to switch to cpu number h (in hex)\n"
211#endif
212 "\
213 C checksum\n\
214 d dump bytes\n\
Douglas Miller5e48dc02017-02-07 07:40:44 -0600215 d1 dump 1 byte values\n\
216 d2 dump 2 byte values\n\
217 d4 dump 4 byte values\n\
218 d8 dump 8 byte values\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 di dump instructions\n\
220 df dump float values\n\
221 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000222 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100223#ifdef CONFIG_PPC_POWERNV
224 "\
225 do dump the OPAL message log\n"
226#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000227#ifdef CONFIG_PPC64
228 "\
229 dp[#] dump paca for current cpu, or cpu #\n\
230 dpa dump paca for all possible cpus\n"
231#endif
232 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100233 dr dump stream of raw bytes\n\
Balbir Singh80eff6c2017-10-30 22:01:12 +1100234 dv dump virtual address translation \n\
Michael Ellerman56144ec2015-11-06 13:21:17 +1100235 dt dump the tracing buffers (uses printk)\n\
Breno Leitao4125d012017-08-02 17:14:05 -0300236 dtc dump the tracing buffers for current CPU (uses printk)\n\
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +1000237"
238#ifdef CONFIG_PPC_POWERNV
239" dx# dump xive on CPU #\n\
240 dxi# dump xive irq state #\n\
241 dxa dump xive on all CPUs\n"
242#endif
243" e print exception information\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 f flush cache\n\
245 la lookup symbol+offset of specified address\n\
246 ls lookup address of specified symbol\n\
247 m examine/change memory\n\
248 mm move a block of memory\n\
249 ms set a block of memory\n\
250 md compare two blocks of memory\n\
251 ml locate a block of memory\n\
252 mz zero a block of memory\n\
253 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000254 p call a procedure\n\
Douglas Miller6dfb5402015-11-23 09:01:15 -0600255 P list processes/tasks\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200257 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100258#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200259" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200260 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100261 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900262 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100263 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200264#endif
265" S print special registers\n\
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000266 Sa print all SPRs\n\
267 Sr # read SPR #\n\
268 Sw #v write v to SPR #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100271 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000272#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000273" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000274#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000275" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000276#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100277" u dump TLB\n"
278#endif
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300279" U show uptime information\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000280" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100281" # n limit output to n lines per page (for dp, dpa, dl)\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000282" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 zh halt\n"
284;
285
286static struct pt_regs *xmon_regs;
287
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000288static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
290 asm volatile("sync; isync");
291}
292
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000293static inline void store_inst(void *p)
294{
295 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
296}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000298static inline void cflush(void *p)
299{
300 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
301}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000303static inline void cinval(void *p)
304{
305 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
306}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530308/**
309 * write_ciabr() - write the CIABR SPR
310 * @ciabr: The value to write.
311 *
312 * This function writes a value to the CIARB register either directly
313 * through mtspr instruction if the kernel is in HV privilege mode or
314 * call a hypervisor function to achieve the same in case the kernel
315 * is in supervisor privilege mode.
316 */
317static void write_ciabr(unsigned long ciabr)
318{
319 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
320 return;
321
322 if (cpu_has_feature(CPU_FTR_HVMODE)) {
323 mtspr(SPRN_CIABR, ciabr);
324 return;
325 }
Michael Ellerman7c09c182018-03-08 13:54:41 +1100326 plpar_set_ciabr(ciabr);
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530327}
328
329/**
330 * set_ciabr() - set the CIABR
331 * @addr: The value to set.
332 *
333 * This function sets the correct privilege value into the the HW
334 * breakpoint address before writing it up in the CIABR register.
335 */
336static void set_ciabr(unsigned long addr)
337{
338 addr &= ~CIABR_PRIV;
339
340 if (cpu_has_feature(CPU_FTR_HVMODE))
341 addr |= CIABR_PRIV_HYPER;
342 else
343 addr |= CIABR_PRIV_SUPER;
344 write_ciabr(addr);
345}
346
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347/*
348 * Disable surveillance (the service processor watchdog function)
349 * while we are in xmon.
350 * XXX we should re-enable it when we leave. :)
351 */
352#define SURVEILLANCE_TOKEN 9000
353
354static inline void disable_surveillance(void)
355{
356#ifdef CONFIG_PPC_PSERIES
357 /* Since this can't be a module, args should end up below 4GB. */
358 static struct rtas_args args;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100359 int token;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
361 /*
362 * At this point we have got all the cpus we can into
363 * xmon, so there is hopefully no other cpu calling RTAS
364 * at the moment, even though we don't take rtas.lock.
365 * If we did try to take rtas.lock there would be a
366 * real possibility of deadlock.
367 */
Michael Ellerman08eb1052015-11-24 22:26:09 +1100368 token = rtas_token("set-indicator");
369 if (token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100371
372 rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0);
373
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374#endif /* CONFIG_PPC_PSERIES */
375}
376
377#ifdef CONFIG_SMP
378static int xmon_speaker;
379
380static void get_output_lock(void)
381{
382 int me = smp_processor_id() + 0x100;
383 int last_speaker = 0, prev;
384 long timeout;
385
386 if (xmon_speaker == me)
387 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100390 last_speaker = cmpxchg(&xmon_speaker, 0, me);
391 if (last_speaker == 0)
392 return;
393
Michael Ellerman15075892013-12-23 23:46:05 +1100394 /*
395 * Wait a full second for the lock, we might be on a slow
396 * console, but check every 100us.
397 */
398 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100400 if (--timeout > 0) {
401 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100403 }
404
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 /* hostile takeover */
406 prev = cmpxchg(&xmon_speaker, last_speaker, me);
407 if (prev == last_speaker)
408 return;
409 break;
410 }
411 }
412}
413
414static void release_output_lock(void)
415{
416 xmon_speaker = 0;
417}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000418
419int cpus_are_in_xmon(void)
420{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000421 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000422}
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000423
424static bool wait_for_other_cpus(int ncpus)
425{
426 unsigned long timeout;
427
428 /* We wait for 2s, which is a metric "little while" */
429 for (timeout = 20000; timeout != 0; --timeout) {
430 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
431 return true;
432 udelay(100);
433 barrier();
434 }
435
436 return false;
437}
438#endif /* CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Josh Boyerdaf8f402009-09-23 03:51:04 +0000440static inline int unrecoverable_excp(struct pt_regs *regs)
441{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000442#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000443 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000444 return 0;
445#else
446 return ((regs->msr & MSR_RI) == 0);
447#endif
448}
449
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000450static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
452 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 struct bpt *bp;
454 long recurse_jmp[JMP_BUF_LEN];
455 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100456 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457#ifdef CONFIG_SMP
458 int cpu;
459 int secondary;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460#endif
461
Anton Blanchardf13659e2007-03-21 01:48:34 +1100462 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000463 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Breno Leitaoed49f7f2017-08-02 17:14:06 -0300465 tracing_enabled = tracing_is_on();
466 tracing_off();
467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 bp = in_breakpoint_table(regs->nip, &offset);
469 if (bp != NULL) {
470 regs->nip = bp->address + offset;
471 atomic_dec(&bp->ref_count);
472 }
473
474 remove_cpu_bpts();
475
476#ifdef CONFIG_SMP
477 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000478 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000479 /*
480 * We catch SPR read/write faults here because the 0x700, 0xf60
481 * etc. handlers don't call debugger_fault_handler().
482 */
483 if (catch_spr_faults)
484 longjmp(bus_error_jmp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 get_output_lock();
486 excprint(regs);
487 printf("cpu 0x%x: Exception %lx %s in xmon, "
488 "returning to main loop\n",
489 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000490 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 longjmp(xmon_fault_jmp[cpu], 1);
492 }
493
494 if (setjmp(recurse_jmp) != 0) {
495 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000496 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 printf("xmon: WARNING: bad recursive fault "
498 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000499 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 goto waiting;
501 }
502 secondary = !(xmon_taken && cpu == xmon_owner);
503 goto cmdloop;
504 }
505
506 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000509 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000511 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 fromipi = 0;
513
514 if (!fromipi) {
515 get_output_lock();
516 excprint(regs);
517 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000518 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 cpu, BP_NUM(bp));
520 xmon_print_symbol(regs->nip, " ", ")\n");
521 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000522 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 printf("WARNING: exception is not recoverable, "
524 "can't continue\n");
525 release_output_lock();
526 }
527
Michael Ellermand2b496e2013-12-23 23:46:06 +1100528 cpumask_set_cpu(cpu, &cpus_in_xmon);
529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 waiting:
531 secondary = 1;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000532 spin_begin();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 while (secondary && !xmon_gate) {
534 if (in_xmon == 0) {
Nicholas Piggin064996d2017-09-29 13:29:40 +1000535 if (fromipi) {
536 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 goto leave;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000538 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 secondary = test_and_set_bit(0, &in_xmon);
540 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000541 spin_cpu_relax();
542 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000544 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
546 if (!secondary && !xmon_gate) {
547 /* we are the first cpu to come in */
548 /* interrupt other cpu(s) */
549 int ncpus = num_online_cpus();
550
551 xmon_owner = cpu;
552 mb();
553 if (ncpus > 1) {
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000554 /*
555 * A system reset (trap == 0x100) can be triggered on
556 * all CPUs, so when we come in via 0x100 try waiting
557 * for the other CPUs to come in before we send the
558 * debugger break (IPI). This is similar to
559 * crash_kexec_secondary().
560 */
561 if (TRAP(regs) != 0x100 || !wait_for_other_cpus(ncpus))
562 smp_send_debugger_break();
563
564 wait_for_other_cpus(ncpus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 }
566 remove_bpts();
567 disable_surveillance();
568 /* for breakpoint or single step, print the current instr. */
569 if (bp || TRAP(regs) == 0xd00)
570 ppc_inst_dump(regs->nip, 1, 0);
571 printf("enter ? for help\n");
572 mb();
573 xmon_gate = 1;
574 barrier();
Nicholas Piggin064996d2017-09-29 13:29:40 +1000575 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 }
577
578 cmdloop:
579 while (in_xmon) {
580 if (secondary) {
Nicholas Piggin064996d2017-09-29 13:29:40 +1000581 spin_begin();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 if (cpu == xmon_owner) {
583 if (!test_and_set_bit(0, &xmon_taken)) {
584 secondary = 0;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000585 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 continue;
587 }
588 /* missed it */
589 while (cpu == xmon_owner)
Nicholas Piggin064996d2017-09-29 13:29:40 +1000590 spin_cpu_relax();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000592 spin_cpu_relax();
593 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 } else {
595 cmd = cmds(regs);
596 if (cmd != 0) {
597 /* exiting xmon */
598 insert_bpts();
599 xmon_gate = 0;
600 wmb();
601 in_xmon = 0;
602 break;
603 }
604 /* have switched to some other cpu */
605 secondary = 1;
606 }
607 }
608 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000609 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611#else
612 /* UP is simple... */
613 if (in_xmon) {
614 printf("Exception %lx %s in xmon, returning to main loop\n",
615 regs->trap, getvecname(TRAP(regs)));
616 longjmp(xmon_fault_jmp[0], 1);
617 }
618 if (setjmp(recurse_jmp) == 0) {
619 xmon_fault_jmp[0] = recurse_jmp;
620 in_xmon = 1;
621
622 excprint(regs);
623 bp = at_breakpoint(regs->nip);
624 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000625 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 xmon_print_symbol(regs->nip, " ", ")\n");
627 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000628 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 printf("WARNING: exception is not recoverable, "
630 "can't continue\n");
631 remove_bpts();
632 disable_surveillance();
633 /* for breakpoint or single step, print the current instr. */
634 if (bp || TRAP(regs) == 0xd00)
635 ppc_inst_dump(regs->nip, 1, 0);
636 printf("enter ? for help\n");
637 }
638
639 cmd = cmds(regs);
640
641 insert_bpts();
642 in_xmon = 0;
643#endif
644
Josh Boyercdd39042009-10-05 04:46:05 +0000645#ifdef CONFIG_BOOKE
646 if (regs->msr & MSR_DE) {
647 bp = at_breakpoint(regs->nip);
648 if (bp != NULL) {
649 regs->nip = (unsigned long) &bp->instr[0];
650 atomic_inc(&bp->ref_count);
651 }
652 }
653#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000654 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 bp = at_breakpoint(regs->nip);
656 if (bp != NULL) {
657 int stepped = emulate_step(regs, bp->instr[0]);
658 if (stepped == 0) {
659 regs->nip = (unsigned long) &bp->instr[0];
660 atomic_inc(&bp->ref_count);
661 } else if (stepped < 0) {
662 printf("Couldn't single-step %s instruction\n",
663 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
664 }
665 }
666 }
Josh Boyercdd39042009-10-05 04:46:05 +0000667#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 insert_cpu_bpts();
669
Anton Blancharda71d64b2014-08-05 14:55:00 +1000670 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100671 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000673 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674}
675
676int xmon(struct pt_regs *excp)
677{
678 struct pt_regs regs;
679
680 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000681 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 excp = &regs;
683 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200684
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 return xmon_core(excp, 0);
686}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000687EXPORT_SYMBOL(xmon);
688
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000689irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000690{
691 unsigned long flags;
692 local_irq_save(flags);
693 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000694 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000695 local_irq_restore(flags);
696 return IRQ_HANDLED;
697}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000699static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700{
701 struct bpt *bp;
702 unsigned long offset;
703
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000704 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 return 0;
706
707 /* Are we at the trap at bp->instr[1] for some bp? */
708 bp = in_breakpoint_table(regs->nip, &offset);
709 if (bp != NULL && offset == 4) {
710 regs->nip = bp->address + 4;
711 atomic_dec(&bp->ref_count);
712 return 1;
713 }
714
715 /* Are we at a breakpoint? */
716 bp = at_breakpoint(regs->nip);
717 if (!bp)
718 return 0;
719
720 xmon_core(regs, 0);
721
722 return 1;
723}
724
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000725static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726{
727 if (user_mode(regs))
728 return 0;
729 xmon_core(regs, 0);
730 return 1;
731}
732
Michael Neuling9422de32012-12-20 14:06:44 +0000733static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000735 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000737 if (dabr.enabled == 0)
738 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 xmon_core(regs, 0);
740 return 1;
741}
742
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000743static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000745 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000747 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 return 0;
749 xmon_core(regs, 0);
750 return 1;
751}
752
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000753static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754{
755#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000756 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 xmon_core(regs, 1);
758#endif
759 return 0;
760}
761
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000762static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
764 struct bpt *bp;
765 unsigned long offset;
766
767 if (in_xmon && catch_memory_errors)
768 handle_fault(regs); /* doesn't return */
769
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000770 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 bp = in_breakpoint_table(regs->nip, &offset);
772 if (bp != NULL) {
773 regs->nip = bp->address + offset;
774 atomic_dec(&bp->ref_count);
775 }
776 }
777
778 return 0;
779}
780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781static struct bpt *at_breakpoint(unsigned long pc)
782{
783 int i;
784 struct bpt *bp;
785
786 bp = bpts;
787 for (i = 0; i < NBPTS; ++i, ++bp)
788 if (bp->enabled && pc == bp->address)
789 return bp;
790 return NULL;
791}
792
793static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
794{
795 unsigned long off;
796
797 off = nip - (unsigned long) bpts;
798 if (off >= sizeof(bpts))
799 return NULL;
800 off %= sizeof(struct bpt);
801 if (off != offsetof(struct bpt, instr[0])
802 && off != offsetof(struct bpt, instr[1]))
803 return NULL;
804 *offp = off - offsetof(struct bpt, instr[0]);
805 return (struct bpt *) (nip - off);
806}
807
808static struct bpt *new_breakpoint(unsigned long a)
809{
810 struct bpt *bp;
811
812 a &= ~3UL;
813 bp = at_breakpoint(a);
814 if (bp)
815 return bp;
816
817 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
818 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
819 bp->address = a;
820 bp->instr[1] = bpinstr;
821 store_inst(&bp->instr[1]);
822 return bp;
823 }
824 }
825
826 printf("Sorry, no free breakpoints. Please clear one first.\n");
827 return NULL;
828}
829
830static void insert_bpts(void)
831{
832 int i;
833 struct bpt *bp;
834
835 bp = bpts;
836 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100837 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 continue;
839 if (mread(bp->address, &bp->instr[0], 4) != 4) {
840 printf("Couldn't read instruction at %lx, "
841 "disabling breakpoint there\n", bp->address);
842 bp->enabled = 0;
843 continue;
844 }
845 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
846 printf("Breakpoint at %lx is on an mtmsrd or rfid "
847 "instruction, disabling it\n", bp->address);
848 bp->enabled = 0;
849 continue;
850 }
851 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100852 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 continue;
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000854 if (patch_instruction((unsigned int *)bp->address,
855 bpinstr) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 printf("Couldn't write instruction at %lx, "
857 "disabling breakpoint there\n", bp->address);
858 bp->enabled &= ~BP_TRAP;
859 continue;
860 }
861 store_inst((void *)bp->address);
862 }
863}
864
865static void insert_cpu_bpts(void)
866{
Michael Neuling9422de32012-12-20 14:06:44 +0000867 struct arch_hw_breakpoint brk;
868
869 if (dabr.enabled) {
870 brk.address = dabr.address;
871 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
872 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400873 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000874 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530875
876 if (iabr)
877 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878}
879
880static void remove_bpts(void)
881{
882 int i;
883 struct bpt *bp;
884 unsigned instr;
885
886 bp = bpts;
887 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100888 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 continue;
890 if (mread(bp->address, &instr, 4) == 4
891 && instr == bpinstr
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000892 && patch_instruction(
893 (unsigned int *)bp->address, bp->instr[0]) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 printf("Couldn't remove breakpoint at %lx\n",
895 bp->address);
896 else
897 store_inst((void *)bp->address);
898 }
899}
900
901static void remove_cpu_bpts(void)
902{
Michael Neuling9422de32012-12-20 14:06:44 +0000903 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530904 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905}
906
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300907/* Based on uptime_proc_show(). */
908static void
909show_uptime(void)
910{
911 struct timespec uptime;
912
913 if (setjmp(bus_error_jmp) == 0) {
914 catch_memory_errors = 1;
915 sync();
916
917 get_monotonic_boottime(&uptime);
918 printf("Uptime: %lu.%.2lu seconds\n", (unsigned long)uptime.tv_sec,
919 ((unsigned long)uptime.tv_nsec / (NSEC_PER_SEC/100)));
920
921 sync();
922 __delay(200); \
923 }
924 catch_memory_errors = 0;
925}
926
Sam bobroff958b7c82015-10-08 11:50:23 +1100927static void set_lpp_cmd(void)
928{
929 unsigned long lpp;
930
931 if (!scanhex(&lpp)) {
932 printf("Invalid number.\n");
933 lpp = 0;
934 }
935 xmon_set_pagination_lpp(lpp);
936}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937/* Command interpreting routine */
938static char *last_cmd;
939
940static int
941cmds(struct pt_regs *excp)
942{
943 int cmd = 0;
944
945 last_cmd = NULL;
946 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200947
Guilherme G. Piccolib5617832017-03-22 16:27:50 -0300948 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
Olaf Hering26c8af52006-09-08 16:29:21 +0200949
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 for(;;) {
951#ifdef CONFIG_SMP
952 printf("%x:", smp_processor_id());
953#endif /* CONFIG_SMP */
954 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 flush_input();
956 termch = 0;
957 cmd = skipbl();
958 if( cmd == '\n' ) {
959 if (last_cmd == NULL)
960 continue;
961 take_input(last_cmd);
962 last_cmd = NULL;
963 cmd = inchar();
964 }
965 switch (cmd) {
966 case 'm':
967 cmd = inchar();
968 switch (cmd) {
969 case 'm':
970 case 's':
971 case 'd':
972 memops(cmd);
973 break;
974 case 'l':
975 memlocate();
976 break;
977 case 'z':
978 memzcan();
979 break;
980 case 'i':
Michal Hocko9af744d2017-02-22 15:46:16 -0800981 show_mem(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 break;
983 default:
984 termch = cmd;
985 memex();
986 }
987 break;
988 case 'd':
989 dump();
990 break;
991 case 'l':
992 symbol_lookup();
993 break;
994 case 'r':
995 prregs(excp); /* print regs */
996 break;
997 case 'e':
998 excprint(excp);
999 break;
1000 case 'S':
1001 super_regs();
1002 break;
1003 case 't':
1004 backtrace(excp);
1005 break;
1006 case 'f':
1007 cacheflush();
1008 break;
1009 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +02001010 if (do_spu_cmd() == 0)
1011 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 if (do_step(excp))
1013 return cmd;
1014 break;
1015 case 'x':
1016 case 'X':
Breno Leitaoed49f7f2017-08-02 17:14:06 -03001017 if (tracing_enabled)
1018 tracing_on();
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001019 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001021 printf(" <no input ...>\n");
1022 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 return cmd;
1024 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +10001025 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 break;
Sam bobroff958b7c82015-10-08 11:50:23 +11001027 case '#':
1028 set_lpp_cmd();
1029 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 case 'b':
1031 bpt_cmds();
1032 break;
1033 case 'C':
1034 csum();
1035 break;
1036 case 'c':
1037 if (cpu_cmd())
1038 return 0;
1039 break;
1040 case 'z':
1041 bootcmds();
1042 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001043 case 'p':
1044 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -06001046 case 'P':
1047 show_tasks();
1048 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001049#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 case 'u':
1051 dump_segments();
1052 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +11001053#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11001054 case 'u':
1055 dump_tlb_44x();
1056 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +00001057#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10001058 case 'u':
1059 dump_tlb_book3e();
1060 break;
1061#endif
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -03001062 case 'U':
1063 show_uptime();
1064 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 default:
1066 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +00001067 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 if (' ' < cmd && cmd <= '~')
1069 putchar(cmd);
1070 else
1071 printf("\\x%x", cmd);
1072 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +00001073 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 printf(" (type ? for help)\n");
1075 break;
1076 }
1077 }
1078}
1079
Josh Boyercdd39042009-10-05 04:46:05 +00001080#ifdef CONFIG_BOOKE
1081static int do_step(struct pt_regs *regs)
1082{
1083 regs->msr |= MSR_DE;
1084 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1085 return 1;
1086}
1087#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088/*
1089 * Step a single instruction.
1090 * Some instructions we emulate, others we execute with MSR_SE set.
1091 */
1092static int do_step(struct pt_regs *regs)
1093{
1094 unsigned int instr;
1095 int stepped;
1096
1097 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001098 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 if (mread(regs->nip, &instr, 4) == 4) {
1100 stepped = emulate_step(regs, instr);
1101 if (stepped < 0) {
1102 printf("Couldn't single-step %s instruction\n",
1103 (IS_RFID(instr)? "rfid": "mtmsrd"));
1104 return 0;
1105 }
1106 if (stepped > 0) {
1107 regs->trap = 0xd00 | (regs->trap & 1);
1108 printf("stepped to ");
1109 xmon_print_symbol(regs->nip, " ", "\n");
1110 ppc_inst_dump(regs->nip, 1, 0);
1111 return 0;
1112 }
1113 }
1114 }
1115 regs->msr |= MSR_SE;
1116 return 1;
1117}
Josh Boyercdd39042009-10-05 04:46:05 +00001118#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
1120static void bootcmds(void)
1121{
1122 int cmd;
1123
1124 cmd = inchar();
1125 if (cmd == 'r')
1126 ppc_md.restart(NULL);
1127 else if (cmd == 'h')
1128 ppc_md.halt();
1129 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001130 if (pm_power_off)
1131 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132}
1133
1134static int cpu_cmd(void)
1135{
1136#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001137 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
1140 if (!scanhex(&cpu)) {
1141 /* print cpus waiting or in xmon */
1142 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001143 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001144 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001145 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001146 if (cpu == last_cpu + 1) {
1147 last_cpu = cpu;
1148 } else {
1149 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001150 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001151 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001152 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 }
1155 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001156 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001157 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 printf("\n");
1159 return 0;
1160 }
1161 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001162 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 printf("cpu 0x%x isn't in xmon\n", cpu);
1164 return 0;
1165 }
1166 xmon_taken = 0;
1167 mb();
1168 xmon_owner = cpu;
1169 timeout = 10000000;
1170 while (!xmon_taken) {
1171 if (--timeout == 0) {
1172 if (test_and_set_bit(0, &xmon_taken))
1173 break;
1174 /* take control back */
1175 mb();
1176 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001177 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 return 0;
1179 }
1180 barrier();
1181 }
1182 return 1;
1183#else
1184 return 0;
1185#endif /* CONFIG_SMP */
1186}
1187
1188static unsigned short fcstab[256] = {
1189 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1190 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1191 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1192 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1193 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1194 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1195 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1196 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1197 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1198 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1199 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1200 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1201 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1202 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1203 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1204 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1205 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1206 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1207 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1208 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1209 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1210 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1211 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1212 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1213 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1214 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1215 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1216 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1217 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1218 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1219 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1220 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1221};
1222
1223#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1224
1225static void
1226csum(void)
1227{
1228 unsigned int i;
1229 unsigned short fcs;
1230 unsigned char v;
1231
1232 if (!scanhex(&adrs))
1233 return;
1234 if (!scanhex(&ncsum))
1235 return;
1236 fcs = 0xffff;
1237 for (i = 0; i < ncsum; ++i) {
1238 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001239 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 break;
1241 }
1242 fcs = FCS(fcs, v);
1243 }
1244 printf("%x\n", fcs);
1245}
1246
1247/*
1248 * Check if this is a suitable place to put a breakpoint.
1249 */
1250static long check_bp_loc(unsigned long addr)
1251{
1252 unsigned int instr;
1253
1254 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001255 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 printf("Breakpoints may only be placed at kernel addresses\n");
1257 return 0;
1258 }
1259 if (!mread(addr, &instr, sizeof(instr))) {
1260 printf("Can't read instruction at address %lx\n", addr);
1261 return 0;
1262 }
1263 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1264 printf("Breakpoints may not be placed on mtmsrd or rfid "
1265 "instructions\n");
1266 return 0;
1267 }
1268 return 1;
1269}
1270
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301271/* Force enable xmon if not already enabled */
1272static inline void force_enable_xmon(void)
1273{
1274 /* Enable xmon hooks if needed */
1275 if (!xmon_on) {
1276 printf("xmon: Enabling debugger hooks\n");
1277 xmon_on = 1;
1278 }
1279}
1280
Michael Ellermane3bc8042012-08-23 22:09:13 +00001281static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 "Breakpoint command usage:\n"
1283 "b show breakpoints\n"
1284 "b <addr> [cnt] set breakpoint at given instr addr\n"
1285 "bc clear all breakpoints\n"
1286 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301287 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 "bd <addr> [cnt] set hardware data breakpoint\n"
1289 "";
1290
1291static void
1292bpt_cmds(void)
1293{
1294 int cmd;
1295 unsigned long a;
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001296 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 struct bpt *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
1299 cmd = inchar();
1300 switch (cmd) {
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001301#ifndef CONFIG_PPC_8xx
1302 static const char badaddr[] = "Only kernel addresses are permitted for breakpoints\n";
1303 int mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 case 'd': /* bd - hardware data breakpoint */
1305 mode = 7;
1306 cmd = inchar();
1307 if (cmd == 'r')
1308 mode = 5;
1309 else if (cmd == 'w')
1310 mode = 6;
1311 else
1312 termch = cmd;
1313 dabr.address = 0;
1314 dabr.enabled = 0;
1315 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001316 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 printf(badaddr);
1318 break;
1319 }
Michael Neuling9422de32012-12-20 14:06:44 +00001320 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 dabr.enabled = mode | BP_DABR;
1322 }
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301323
1324 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 break;
1326
1327 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301328 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 printf("Hardware instruction breakpoint "
1330 "not supported on this cpu\n");
1331 break;
1332 }
1333 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001334 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 iabr = NULL;
1336 }
1337 if (!scanhex(&a))
1338 break;
1339 if (!check_bp_loc(a))
1340 break;
1341 bp = new_breakpoint(a);
1342 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001343 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 iabr = bp;
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301345 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 }
1347 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001348#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
1350 case 'c':
1351 if (!scanhex(&a)) {
1352 /* clear all breakpoints */
1353 for (i = 0; i < NBPTS; ++i)
1354 bpts[i].enabled = 0;
1355 iabr = NULL;
1356 dabr.enabled = 0;
1357 printf("All breakpoints cleared\n");
1358 break;
1359 }
1360
1361 if (a <= NBPTS && a >= 1) {
1362 /* assume a breakpoint number */
1363 bp = &bpts[a-1]; /* bp nums are 1 based */
1364 } else {
1365 /* assume a breakpoint address */
1366 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001367 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001368 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 break;
1370 }
1371 }
1372
Michael Ellerman736256e2014-05-26 21:02:14 +10001373 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 xmon_print_symbol(bp->address, " ", ")\n");
1375 bp->enabled = 0;
1376 break;
1377
1378 default:
1379 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001380 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 if (cmd == '?') {
1382 printf(breakpoint_help_string);
1383 break;
1384 }
1385 termch = cmd;
1386 if (!scanhex(&a)) {
1387 /* print all breakpoints */
1388 printf(" type address\n");
1389 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001390 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 if (dabr.enabled & 1)
1392 printf("r");
1393 if (dabr.enabled & 2)
1394 printf("w");
1395 printf("]\n");
1396 }
1397 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1398 if (!bp->enabled)
1399 continue;
1400 printf("%2x %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001401 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 xmon_print_symbol(bp->address, " ", "\n");
1403 }
1404 break;
1405 }
1406
1407 if (!check_bp_loc(a))
1408 break;
1409 bp = new_breakpoint(a);
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301410 if (bp != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 bp->enabled |= BP_TRAP;
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301412 force_enable_xmon();
1413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 break;
1415 }
1416}
1417
1418/* Very cheap human name for vector lookup. */
1419static
1420const char *getvecname(unsigned long vec)
1421{
1422 char *ret;
1423
1424 switch (vec) {
1425 case 0x100: ret = "(System Reset)"; break;
1426 case 0x200: ret = "(Machine Check)"; break;
1427 case 0x300: ret = "(Data Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001428 case 0x380:
1429 if (radix_enabled())
1430 ret = "(Data Access Out of Range)";
1431 else
1432 ret = "(Data SLB Access)";
1433 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 case 0x400: ret = "(Instruction Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001435 case 0x480:
1436 if (radix_enabled())
1437 ret = "(Instruction Access Out of Range)";
1438 else
1439 ret = "(Instruction SLB Access)";
1440 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 case 0x500: ret = "(Hardware Interrupt)"; break;
1442 case 0x600: ret = "(Alignment)"; break;
1443 case 0x700: ret = "(Program Check)"; break;
1444 case 0x800: ret = "(FPU Unavailable)"; break;
1445 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001446 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1447 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 case 0xc00: ret = "(System Call)"; break;
1449 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001450 case 0xe40: ret = "(Emulation Assist)"; break;
1451 case 0xe60: ret = "(HMI)"; break;
1452 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 case 0xf00: ret = "(Performance Monitor)"; break;
1454 case 0xf20: ret = "(Altivec Unavailable)"; break;
1455 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001456 case 0x1500: ret = "(Denormalisation)"; break;
1457 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 default: ret = "";
1459 }
1460 return ret;
1461}
1462
1463static void get_function_bounds(unsigned long pc, unsigned long *startp,
1464 unsigned long *endp)
1465{
1466 unsigned long size, offset;
1467 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
1469 *startp = *endp = 0;
1470 if (pc == 0)
1471 return;
1472 if (setjmp(bus_error_jmp) == 0) {
1473 catch_memory_errors = 1;
1474 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001475 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 if (name != NULL) {
1477 *startp = pc - offset;
1478 *endp = pc - offset + size;
1479 }
1480 sync();
1481 }
1482 catch_memory_errors = 0;
1483}
1484
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001485#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1486#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1487
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488static void xmon_show_stack(unsigned long sp, unsigned long lr,
1489 unsigned long pc)
1490{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001491 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 unsigned long ip;
1493 unsigned long newsp;
1494 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 struct pt_regs regs;
1496
Michael Ellerman0104cd62012-10-09 04:20:36 +00001497 while (max_to_print--) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301498 if (!is_kernel_addr(sp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 if (sp != 0)
1500 printf("SP (%lx) is in userspace\n", sp);
1501 break;
1502 }
1503
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001504 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 || !mread(sp, &newsp, sizeof(unsigned long))) {
1506 printf("Couldn't read stack frame at %lx\n", sp);
1507 break;
1508 }
1509
1510 /*
1511 * For the first stack frame, try to work out if
1512 * LR and/or the saved LR value in the bottommost
1513 * stack frame are valid.
1514 */
1515 if ((pc | lr) != 0) {
1516 unsigned long fnstart, fnend;
1517 unsigned long nextip;
1518 int printip = 1;
1519
1520 get_function_bounds(pc, &fnstart, &fnend);
1521 nextip = 0;
1522 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001523 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 sizeof(unsigned long));
1525 if (lr == ip) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301526 if (!is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 || (fnstart <= lr && lr < fnend))
1528 printip = 0;
1529 } else if (lr == nextip) {
1530 printip = 0;
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301531 } else if (is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 && !(fnstart <= lr && lr < fnend)) {
1533 printf("[link register ] ");
1534 xmon_print_symbol(lr, " ", "\n");
1535 }
1536 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001537 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 xmon_print_symbol(ip, " ", " (unreliable)\n");
1539 }
1540 pc = lr = 0;
1541
1542 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001543 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 xmon_print_symbol(ip, " ", "\n");
1545 }
1546
1547 /* Look for "regshere" marker to see if this is
1548 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001549 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001550 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001551 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 != sizeof(regs)) {
1553 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001554 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 break;
1556 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001557 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 getvecname(TRAP(&regs)));
1559 pc = regs.nip;
1560 lr = regs.link;
1561 xmon_print_symbol(pc, " ", "\n");
1562 }
1563
1564 if (newsp == 0)
1565 break;
1566
1567 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569}
1570
1571static void backtrace(struct pt_regs *excp)
1572{
1573 unsigned long sp;
1574
1575 if (scanhex(&sp))
1576 xmon_show_stack(sp, 0, 0);
1577 else
1578 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1579 scannl();
1580}
1581
1582static void print_bug_trap(struct pt_regs *regs)
1583{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001584#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001585 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 unsigned long addr;
1587
1588 if (regs->msr & MSR_PR)
1589 return; /* not in kernel */
1590 addr = regs->nip; /* address of trap instruction */
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301591 if (!is_kernel_addr(addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 return;
1593 bug = find_bug(regs->nip);
1594 if (bug == NULL)
1595 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001596 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 return;
1598
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001599#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001600 printf("kernel BUG at %s:%u!\n",
1601 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001602#else
Michael Ellermand8104182017-12-06 23:23:28 +11001603 printf("kernel BUG at %px!\n", (void *)bug->bug_addr);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001604#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001605#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606}
1607
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001608static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609{
1610 unsigned long trap;
1611
1612#ifdef CONFIG_SMP
1613 printf("cpu 0x%x: ", smp_processor_id());
1614#endif /* CONFIG_SMP */
1615
1616 trap = TRAP(fp);
1617 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1618 printf(" pc: ");
1619 xmon_print_symbol(fp->nip, ": ", "\n");
1620
1621 printf(" lr: ", fp->link);
1622 xmon_print_symbol(fp->link, ": ", "\n");
1623
1624 printf(" sp: %lx\n", fp->gpr[1]);
1625 printf(" msr: %lx\n", fp->msr);
1626
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001627 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 printf(" dar: %lx\n", fp->dar);
1629 if (trap != 0x380)
1630 printf(" dsisr: %lx\n", fp->dsisr);
1631 }
1632
1633 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001634#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001635 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
Madhavan Srinivasan4e26bc42017-12-20 09:25:50 +05301636 local_paca, local_paca->irq_soft_mask, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001637#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 if (current) {
1639 printf(" pid = %ld, comm = %s\n",
1640 current->pid, current->comm);
1641 }
1642
1643 if (trap == 0x700)
1644 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001645
1646 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647}
1648
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001649static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001651 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 unsigned long base;
1653 struct pt_regs regs;
1654
1655 if (scanhex(&base)) {
1656 if (setjmp(bus_error_jmp) == 0) {
1657 catch_memory_errors = 1;
1658 sync();
1659 regs = *(struct pt_regs *)base;
1660 sync();
1661 __delay(200);
1662 } else {
1663 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001664 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 base);
1666 return;
1667 }
1668 catch_memory_errors = 0;
1669 fp = &regs;
1670 }
1671
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001672#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 if (FULL_REGS(fp)) {
1674 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001675 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1677 } else {
1678 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001679 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1681 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001682#else
1683 for (n = 0; n < 32; ++n) {
1684 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1685 (n & 3) == 3? "\n": " ");
1686 if (n == 12 && !FULL_REGS(fp)) {
1687 printf("\n");
1688 break;
1689 }
1690 }
1691#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 printf("pc = ");
1693 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001694 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1695 printf("cfar= ");
1696 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1697 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 printf("lr = ");
1699 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001700 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1701 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001703 trap = TRAP(fp);
1704 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1705 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706}
1707
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001708static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709{
1710 int cmd;
1711 unsigned long nflush;
1712
1713 cmd = inchar();
1714 if (cmd != 'i')
1715 termch = cmd;
1716 scanhex((void *)&adrs);
1717 if (termch != '\n')
1718 termch = 0;
1719 nflush = 1;
1720 scanhex(&nflush);
1721 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1722 if (setjmp(bus_error_jmp) == 0) {
1723 catch_memory_errors = 1;
1724 sync();
1725
1726 if (cmd != 'i') {
1727 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1728 cflush((void *) adrs);
1729 } else {
1730 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1731 cinval((void *) adrs);
1732 }
1733 sync();
1734 /* wait a little while to see if we get a machine check */
1735 __delay(200);
1736 }
1737 catch_memory_errors = 0;
1738}
1739
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001740extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1741extern void xmon_mtspr(int spr, unsigned long value);
1742
1743static int
1744read_spr(int n, unsigned long *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 unsigned long ret = -1UL;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001747 int ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748
1749 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001750 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 sync();
1752
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001753 ret = xmon_mfspr(n, *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
1755 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001756 *vp = ret;
1757 ok = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001759 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001761 return ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762}
1763
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001764static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765write_spr(int n, unsigned long val)
1766{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001768 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 sync();
1770
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001771 xmon_mtspr(n, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772
1773 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001774 } else {
1775 printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001777 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778}
1779
Michael Ellerman18461932016-07-07 22:54:29 +10001780static void dump_206_sprs(void)
1781{
1782#ifdef CONFIG_PPC64
1783 if (!cpu_has_feature(CPU_FTR_ARCH_206))
1784 return;
1785
1786 /* Actually some of these pre-date 2.06, but whatevs */
1787
Balbir Singhc47a9402017-08-29 17:22:36 +10001788 printf("srr0 = %.16lx srr1 = %.16lx dsisr = %.8x\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001789 mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001790 printf("dscr = %.16lx ppr = %.16lx pir = %.8x\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001791 mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001792 printf("amr = %.16lx uamor = %.16lx\n",
1793 mfspr(SPRN_AMR), mfspr(SPRN_UAMOR));
Michael Ellerman18461932016-07-07 22:54:29 +10001794
1795 if (!(mfmsr() & MSR_HV))
1796 return;
1797
Balbir Singhc47a9402017-08-29 17:22:36 +10001798 printf("sdr1 = %.16lx hdar = %.16lx hdsisr = %.8x\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001799 mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001800 printf("hsrr0 = %.16lx hsrr1 = %.16lx hdec = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001801 mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001802 printf("lpcr = %.16lx pcr = %.16lx lpidr = %.8x\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001803 mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001804 printf("hsprg0 = %.16lx hsprg1 = %.16lx amor = %.16lx\n",
1805 mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1), mfspr(SPRN_AMOR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001806 printf("dabr = %.16lx dabrx = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001807 mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
1808#endif
1809}
1810
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001811static void dump_207_sprs(void)
1812{
1813#ifdef CONFIG_PPC64
1814 unsigned long msr;
1815
1816 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
1817 return;
1818
Balbir Singhc47a9402017-08-29 17:22:36 +10001819 printf("dpdes = %.16lx tir = %.16lx cir = %.8x\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001820 mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
1821
Balbir Singhc47a9402017-08-29 17:22:36 +10001822 printf("fscr = %.16lx tar = %.16lx pspb = %.8x\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001823 mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
1824
1825 msr = mfmsr();
1826 if (msr & MSR_TM) {
1827 /* Only if TM has been enabled in the kernel */
Balbir Singhc47a9402017-08-29 17:22:36 +10001828 printf("tfhar = %.16lx tfiar = %.16lx texasr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001829 mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
1830 mfspr(SPRN_TEXASR));
1831 }
1832
Balbir Singhc47a9402017-08-29 17:22:36 +10001833 printf("mmcr0 = %.16lx mmcr1 = %.16lx mmcr2 = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001834 mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
1835 printf("pmc1 = %.8x pmc2 = %.8x pmc3 = %.8x pmc4 = %.8x\n",
1836 mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
1837 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
Balbir Singhc47a9402017-08-29 17:22:36 +10001838 printf("mmcra = %.16lx siar = %.16lx pmc5 = %.8x\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001839 mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
Balbir Singhc47a9402017-08-29 17:22:36 +10001840 printf("sdar = %.16lx sier = %.16lx pmc6 = %.8x\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001841 mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
Balbir Singhc47a9402017-08-29 17:22:36 +10001842 printf("ebbhr = %.16lx ebbrr = %.16lx bescr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001843 mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001844 printf("iamr = %.16lx\n", mfspr(SPRN_IAMR));
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001845
1846 if (!(msr & MSR_HV))
1847 return;
1848
Balbir Singhc47a9402017-08-29 17:22:36 +10001849 printf("hfscr = %.16lx dhdes = %.16lx rpr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001850 mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001851 printf("dawr = %.16lx dawrx = %.16lx ciabr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001852 mfspr(SPRN_DAWR), mfspr(SPRN_DAWRX), mfspr(SPRN_CIABR));
1853#endif
1854}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855
Balbir Singhd1e1b352017-08-30 21:45:09 +10001856static void dump_300_sprs(void)
1857{
1858#ifdef CONFIG_PPC64
1859 bool hv = mfmsr() & MSR_HV;
1860
1861 if (!cpu_has_feature(CPU_FTR_ARCH_300))
1862 return;
1863
1864 printf("pidr = %.16lx tidr = %.16lx\n",
1865 mfspr(SPRN_PID), mfspr(SPRN_TIDR));
1866 printf("asdr = %.16lx psscr = %.16lx\n",
1867 mfspr(SPRN_ASDR), hv ? mfspr(SPRN_PSSCR)
1868 : mfspr(SPRN_PSSCR_PR));
1869
1870 if (!hv)
1871 return;
1872
1873 printf("ptcr = %.16lx\n",
1874 mfspr(SPRN_PTCR));
1875#endif
1876}
1877
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001878static void dump_one_spr(int spr, bool show_unimplemented)
1879{
1880 unsigned long val;
1881
1882 val = 0xdeadbeef;
1883 if (!read_spr(spr, &val)) {
1884 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1885 return;
1886 }
1887
1888 if (val == 0xdeadbeef) {
1889 /* Looks like read was a nop, confirm */
1890 val = 0x0badcafe;
1891 if (!read_spr(spr, &val)) {
1892 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1893 return;
1894 }
1895
1896 if (val == 0x0badcafe) {
1897 if (show_unimplemented)
1898 printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
1899 return;
1900 }
1901 }
1902
1903 printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
1904}
1905
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001906static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907{
Michael Ellerman13629da2016-07-07 22:54:27 +10001908 static unsigned long regno;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 int cmd;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001910 int spr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911
1912 cmd = skipbl();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001913
1914 switch (cmd) {
1915 case '\n': {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001916 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 asm("mr %0,1" : "=r" (sp) :);
1918 asm("mr %0,2" : "=r" (toc) :);
1919
Michael Ellerman56346ad2016-07-07 22:54:28 +10001920 printf("msr = "REG" sprg0 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001921 mfmsr(), mfspr(SPRN_SPRG0));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001922 printf("pvr = "REG" sprg1 = "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001923 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001924 printf("dec = "REG" sprg2 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001925 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001926 printf("sp = "REG" sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
1927 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
1928
Michael Ellerman18461932016-07-07 22:54:29 +10001929 dump_206_sprs();
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001930 dump_207_sprs();
Balbir Singhd1e1b352017-08-30 21:45:09 +10001931 dump_300_sprs();
Michael Ellerman18461932016-07-07 22:54:29 +10001932
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 return;
1934 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001935 case 'w': {
1936 unsigned long val;
1937 scanhex(&regno);
1938 val = 0;
1939 read_spr(regno, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 scanhex(&val);
1941 write_spr(regno, val);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001942 dump_one_spr(regno, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001945 case 'r':
1946 scanhex(&regno);
1947 dump_one_spr(regno, true);
1948 break;
1949 case 'a':
1950 /* dump ALL SPRs */
1951 for (spr = 1; spr < 1024; ++spr)
1952 dump_one_spr(spr, false);
1953 break;
1954 }
1955
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 scannl();
1957}
1958
1959/*
1960 * Stuff for reading and writing memory safely
1961 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001962static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963mread(unsigned long adrs, void *buf, int size)
1964{
1965 volatile int n;
1966 char *p, *q;
1967
1968 n = 0;
1969 if (setjmp(bus_error_jmp) == 0) {
1970 catch_memory_errors = 1;
1971 sync();
1972 p = (char *)adrs;
1973 q = (char *)buf;
1974 switch (size) {
1975 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001976 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 break;
1978 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001979 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 break;
1981 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001982 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 break;
1984 default:
1985 for( ; n < size; ++n) {
1986 *q++ = *p++;
1987 sync();
1988 }
1989 }
1990 sync();
1991 /* wait a little while to see if we get a machine check */
1992 __delay(200);
1993 n = size;
1994 }
1995 catch_memory_errors = 0;
1996 return n;
1997}
1998
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001999static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000mwrite(unsigned long adrs, void *buf, int size)
2001{
2002 volatile int n;
2003 char *p, *q;
2004
2005 n = 0;
2006 if (setjmp(bus_error_jmp) == 0) {
2007 catch_memory_errors = 1;
2008 sync();
2009 p = (char *) adrs;
2010 q = (char *) buf;
2011 switch (size) {
2012 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002013 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 break;
2015 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002016 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 break;
2018 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002019 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 break;
2021 default:
2022 for ( ; n < size; ++n) {
2023 *p++ = *q++;
2024 sync();
2025 }
2026 }
2027 sync();
2028 /* wait a little while to see if we get a machine check */
2029 __delay(200);
2030 n = size;
2031 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10002032 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 }
2034 catch_memory_errors = 0;
2035 return n;
2036}
2037
2038static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002039static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040static char *fault_chars[] = { "--", "**", "##" };
2041
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002042static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002044 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 switch (TRAP(regs)) {
2046 case 0x200:
2047 fault_type = 0;
2048 break;
2049 case 0x300:
2050 case 0x380:
2051 fault_type = 1;
2052 break;
2053 default:
2054 fault_type = 2;
2055 }
2056
2057 longjmp(bus_error_jmp, 1);
2058
2059 return 0;
2060}
2061
2062#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
2063
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002064static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065byterev(unsigned char *val, int size)
2066{
2067 int t;
2068
2069 switch (size) {
2070 case 2:
2071 SWAP(val[0], val[1], t);
2072 break;
2073 case 4:
2074 SWAP(val[0], val[3], t);
2075 SWAP(val[1], val[2], t);
2076 break;
2077 case 8: /* is there really any use for this? */
2078 SWAP(val[0], val[7], t);
2079 SWAP(val[1], val[6], t);
2080 SWAP(val[2], val[5], t);
2081 SWAP(val[3], val[4], t);
2082 break;
2083 }
2084}
2085
2086static int brev;
2087static int mnoread;
2088
Michael Ellermane3bc8042012-08-23 22:09:13 +00002089static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 "Memory examine command usage:\n"
2091 "m [addr] [flags] examine/change memory\n"
2092 " addr is optional. will start where left off.\n"
2093 " flags may include chars from this set:\n"
2094 " b modify by bytes (default)\n"
2095 " w modify by words (2 byte)\n"
2096 " l modify by longs (4 byte)\n"
2097 " d modify by doubleword (8 byte)\n"
2098 " r toggle reverse byte order mode\n"
2099 " n do not read memory (for i/o spaces)\n"
2100 " . ok to read (default)\n"
2101 "NOTE: flags are saved as defaults\n"
2102 "";
2103
Michael Ellermane3bc8042012-08-23 22:09:13 +00002104static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 "Memory examine subcommands:\n"
2106 " hexval write this val to current location\n"
2107 " 'string' write chars from string to this location\n"
2108 " ' increment address\n"
2109 " ^ decrement address\n"
2110 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
2111 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
2112 " ` clear no-read flag\n"
2113 " ; stay at this addr\n"
2114 " v change to byte mode\n"
2115 " w change to word (2 byte) mode\n"
2116 " l change to long (4 byte) mode\n"
2117 " u change to doubleword (8 byte) mode\n"
2118 " m addr change current addr\n"
2119 " n toggle no-read flag\n"
2120 " r toggle byte reverse flag\n"
2121 " < count back up count bytes\n"
2122 " > count skip forward count bytes\n"
2123 " x exit this mode\n"
2124 "";
2125
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002126static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127memex(void)
2128{
2129 int cmd, inc, i, nslash;
2130 unsigned long n;
2131 unsigned char val[16];
2132
2133 scanhex((void *)&adrs);
2134 cmd = skipbl();
2135 if (cmd == '?') {
2136 printf(memex_help_string);
2137 return;
2138 } else {
2139 termch = cmd;
2140 }
2141 last_cmd = "m\n";
2142 while ((cmd = skipbl()) != '\n') {
2143 switch( cmd ){
2144 case 'b': size = 1; break;
2145 case 'w': size = 2; break;
2146 case 'l': size = 4; break;
2147 case 'd': size = 8; break;
2148 case 'r': brev = !brev; break;
2149 case 'n': mnoread = 1; break;
2150 case '.': mnoread = 0; break;
2151 }
2152 }
2153 if( size <= 0 )
2154 size = 1;
2155 else if( size > 8 )
2156 size = 8;
2157 for(;;){
2158 if (!mnoread)
2159 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002160 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 if (!mnoread) {
2162 if (brev)
2163 byterev(val, size);
2164 putchar(' ');
2165 for (i = 0; i < n; ++i)
2166 printf("%.2x", val[i]);
2167 for (; i < size; ++i)
2168 printf("%s", fault_chars[fault_type]);
2169 }
2170 putchar(' ');
2171 inc = size;
2172 nslash = 0;
2173 for(;;){
2174 if( scanhex(&n) ){
2175 for (i = 0; i < size; ++i)
2176 val[i] = n >> (i * 8);
2177 if (!brev)
2178 byterev(val, size);
2179 mwrite(adrs, val, size);
2180 inc = size;
2181 }
2182 cmd = skipbl();
2183 if (cmd == '\n')
2184 break;
2185 inc = 0;
2186 switch (cmd) {
2187 case '\'':
2188 for(;;){
2189 n = inchar();
2190 if( n == '\\' )
2191 n = bsesc();
2192 else if( n == '\'' )
2193 break;
2194 for (i = 0; i < size; ++i)
2195 val[i] = n >> (i * 8);
2196 if (!brev)
2197 byterev(val, size);
2198 mwrite(adrs, val, size);
2199 adrs += size;
2200 }
2201 adrs -= size;
2202 inc = size;
2203 break;
2204 case ',':
2205 adrs += size;
2206 break;
2207 case '.':
2208 mnoread = 0;
2209 break;
2210 case ';':
2211 break;
2212 case 'x':
2213 case EOF:
2214 scannl();
2215 return;
2216 case 'b':
2217 case 'v':
2218 size = 1;
2219 break;
2220 case 'w':
2221 size = 2;
2222 break;
2223 case 'l':
2224 size = 4;
2225 break;
2226 case 'u':
2227 size = 8;
2228 break;
2229 case '^':
2230 adrs -= size;
2231 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 case '/':
2233 if (nslash > 0)
2234 adrs -= 1 << nslash;
2235 else
2236 nslash = 0;
2237 nslash += 4;
2238 adrs += 1 << nslash;
2239 break;
2240 case '\\':
2241 if (nslash < 0)
2242 adrs += 1 << -nslash;
2243 else
2244 nslash = 0;
2245 nslash -= 4;
2246 adrs -= 1 << -nslash;
2247 break;
2248 case 'm':
2249 scanhex((void *)&adrs);
2250 break;
2251 case 'n':
2252 mnoread = 1;
2253 break;
2254 case 'r':
2255 brev = !brev;
2256 break;
2257 case '<':
2258 n = size;
2259 scanhex(&n);
2260 adrs -= n;
2261 break;
2262 case '>':
2263 n = size;
2264 scanhex(&n);
2265 adrs += n;
2266 break;
2267 case '?':
2268 printf(memex_subcmd_help_string);
2269 break;
2270 }
2271 }
2272 adrs += inc;
2273 }
2274}
2275
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002276static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277bsesc(void)
2278{
2279 int c;
2280
2281 c = inchar();
2282 switch( c ){
2283 case 'n': c = '\n'; break;
2284 case 'r': c = '\r'; break;
2285 case 'b': c = '\b'; break;
2286 case 't': c = '\t'; break;
2287 }
2288 return c;
2289}
2290
Olaf Hering7e5b5932006-03-08 20:40:28 +01002291static void xmon_rawdump (unsigned long adrs, long ndump)
2292{
2293 long n, m, r, nr;
2294 unsigned char temp[16];
2295
2296 for (n = ndump; n > 0;) {
2297 r = n < 16? n: 16;
2298 nr = mread(adrs, temp, r);
2299 adrs += nr;
2300 for (m = 0; m < r; ++m) {
2301 if (m < nr)
2302 printf("%.2x", temp[m]);
2303 else
2304 printf("%s", fault_chars[fault_type]);
2305 }
2306 n -= r;
2307 if (nr < r)
2308 break;
2309 }
2310 printf("\n");
2311}
2312
Breno Leitao4125d012017-08-02 17:14:05 -03002313static void dump_tracing(void)
2314{
2315 int c;
2316
2317 c = inchar();
2318 if (c == 'c')
2319 ftrace_dump(DUMP_ORIG);
2320 else
2321 ftrace_dump(DUMP_ALL);
Breno Leitao4125d012017-08-02 17:14:05 -03002322}
2323
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002324#ifdef CONFIG_PPC64
2325static void dump_one_paca(int cpu)
2326{
2327 struct paca_struct *p;
Michael Ellerman4e003742017-10-19 15:08:43 +11002328#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellermanad987fc2015-10-14 16:58:36 +11002329 int i = 0;
2330#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002331
2332 if (setjmp(bus_error_jmp) != 0) {
2333 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2334 return;
2335 }
2336
2337 catch_memory_errors = 1;
2338 sync();
2339
2340 p = &paca[cpu];
2341
Michael Ellermand8104182017-12-06 23:23:28 +11002342 printf("paca for cpu 0x%x @ %px:\n", cpu, p);
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002343
Michael Ellermanad987fc2015-10-14 16:58:36 +11002344 printf(" %-*s = %s\n", 20, "possible", cpu_possible(cpu) ? "yes" : "no");
2345 printf(" %-*s = %s\n", 20, "present", cpu_present(cpu) ? "yes" : "no");
2346 printf(" %-*s = %s\n", 20, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002347
2348#define DUMP(paca, name, format) \
Michael Ellermanad987fc2015-10-14 16:58:36 +11002349 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 20, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002350 offsetof(struct paca_struct, name));
2351
2352 DUMP(p, lock_token, "x");
2353 DUMP(p, paca_index, "x");
2354 DUMP(p, kernel_toc, "lx");
2355 DUMP(p, kernelbase, "lx");
2356 DUMP(p, kernel_msr, "lx");
Michael Ellerman2248fad2018-01-11 01:17:24 +11002357 DUMP(p, emergency_sp, "px");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302358#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman2248fad2018-01-11 01:17:24 +11002359 DUMP(p, nmi_emergency_sp, "px");
2360 DUMP(p, mc_emergency_sp, "px");
Nicholas Pigginc4f3b522016-12-20 04:30:05 +10002361 DUMP(p, in_nmi, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302362 DUMP(p, in_mce, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002363 DUMP(p, hmi_event_available, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302364#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002365 DUMP(p, data_offset, "lx");
2366 DUMP(p, hw_cpu_id, "x");
2367 DUMP(p, cpu_start, "x");
2368 DUMP(p, kexec_state, "x");
Michael Ellerman4e003742017-10-19 15:08:43 +11002369#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellermanad987fc2015-10-14 16:58:36 +11002370 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2371 u64 esid, vsid;
2372
2373 if (!p->slb_shadow_ptr)
2374 continue;
2375
2376 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2377 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
2378
2379 if (esid || vsid) {
2380 printf(" slb_shadow[%d]: = 0x%016lx 0x%016lx\n",
2381 i, esid, vsid);
2382 }
2383 }
2384 DUMP(p, vmalloc_sllp, "x");
2385 DUMP(p, slb_cache_ptr, "x");
2386 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2387 printf(" slb_cache[%d]: = 0x%016lx\n", i, p->slb_cache[i]);
Michael Ellerman274920a2018-01-10 23:49:12 +11002388
2389 DUMP(p, rfi_flush_fallback_area, "px");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002390#endif
2391 DUMP(p, dscr_default, "llx");
2392#ifdef CONFIG_PPC_BOOK3E
Michael Ellerman2248fad2018-01-11 01:17:24 +11002393 DUMP(p, pgd, "px");
2394 DUMP(p, kernel_pgd, "px");
2395 DUMP(p, tcd_ptr, "px");
2396 DUMP(p, mc_kstack, "px");
2397 DUMP(p, crit_kstack, "px");
2398 DUMP(p, dbg_kstack, "px");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002399#endif
Michael Ellerman2248fad2018-01-11 01:17:24 +11002400 DUMP(p, __current, "px");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002401 DUMP(p, kstack, "lx");
Michael Ellerman90d64732017-10-09 21:59:32 +11002402 printf(" kstack_base = 0x%016lx\n", p->kstack & ~(THREAD_SIZE - 1));
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002403 DUMP(p, stab_rr, "lx");
2404 DUMP(p, saved_r1, "lx");
2405 DUMP(p, trap_save, "x");
Madhavan Srinivasan4e26bc42017-12-20 09:25:50 +05302406 DUMP(p, irq_soft_mask, "x");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002407 DUMP(p, irq_happened, "x");
2408 DUMP(p, io_sync, "x");
2409 DUMP(p, irq_work_pending, "x");
2410 DUMP(p, nap_state_lost, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002411 DUMP(p, sprg_vdso, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002412
Michael Ellermanad987fc2015-10-14 16:58:36 +11002413#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
2414 DUMP(p, tm_scratch, "llx");
2415#endif
2416
2417#ifdef CONFIG_PPC_POWERNV
Michael Ellerman2248fad2018-01-11 01:17:24 +11002418 DUMP(p, core_idle_state_ptr, "px");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002419 DUMP(p, thread_idle_state, "x");
2420 DUMP(p, thread_mask, "x");
2421 DUMP(p, subcore_sibling_mask, "x");
2422#endif
2423
Frederic Weisbecker8c8b73c2017-01-05 18:11:45 +01002424 DUMP(p, accounting.utime, "llx");
2425 DUMP(p, accounting.stime, "llx");
2426 DUMP(p, accounting.utime_scaled, "llx");
Christophe Leroyc223c902016-05-17 08:33:46 +02002427 DUMP(p, accounting.starttime, "llx");
2428 DUMP(p, accounting.starttime_user, "llx");
2429 DUMP(p, accounting.startspurr, "llx");
2430 DUMP(p, accounting.utime_sspurr, "llx");
Frederic Weisbeckerf828c3d2017-01-05 18:11:46 +01002431 DUMP(p, accounting.steal_time, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002432#undef DUMP
2433
2434 catch_memory_errors = 0;
2435 sync();
2436}
2437
2438static void dump_all_pacas(void)
2439{
2440 int cpu;
2441
2442 if (num_possible_cpus() == 0) {
2443 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2444 return;
2445 }
2446
2447 for_each_possible_cpu(cpu)
2448 dump_one_paca(cpu);
2449}
2450
2451static void dump_pacas(void)
2452{
2453 unsigned long num;
2454 int c;
2455
2456 c = inchar();
2457 if (c == 'a') {
2458 dump_all_pacas();
2459 return;
2460 }
2461
2462 termch = c; /* Put c back, it wasn't 'a' */
2463
2464 if (scanhex(&num))
2465 dump_one_paca(num);
2466 else
2467 dump_one_paca(xmon_owner);
2468}
2469#endif
2470
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002471#ifdef CONFIG_PPC_POWERNV
2472static void dump_one_xive(int cpu)
2473{
2474 unsigned int hwid = get_hard_smp_processor_id(cpu);
2475
2476 opal_xive_dump(XIVE_DUMP_TM_HYP, hwid);
2477 opal_xive_dump(XIVE_DUMP_TM_POOL, hwid);
2478 opal_xive_dump(XIVE_DUMP_TM_OS, hwid);
2479 opal_xive_dump(XIVE_DUMP_TM_USER, hwid);
2480 opal_xive_dump(XIVE_DUMP_VP, hwid);
2481 opal_xive_dump(XIVE_DUMP_EMU_STATE, hwid);
2482
2483 if (setjmp(bus_error_jmp) != 0) {
2484 catch_memory_errors = 0;
2485 printf("*** Error dumping xive on cpu %d\n", cpu);
2486 return;
2487 }
2488
2489 catch_memory_errors = 1;
2490 sync();
2491 xmon_xive_do_dump(cpu);
2492 sync();
2493 __delay(200);
2494 catch_memory_errors = 0;
2495}
2496
2497static void dump_all_xives(void)
2498{
2499 int cpu;
2500
2501 if (num_possible_cpus() == 0) {
2502 printf("No possible cpus, use 'dx #' to dump individual cpus\n");
2503 return;
2504 }
2505
2506 for_each_possible_cpu(cpu)
2507 dump_one_xive(cpu);
2508}
2509
2510static void dump_one_xive_irq(u32 num)
2511{
2512 s64 rc;
2513 __be64 vp;
2514 u8 prio;
2515 __be32 lirq;
2516
2517 rc = opal_xive_get_irq_config(num, &vp, &prio, &lirq);
2518 xmon_printf("IRQ 0x%x config: vp=0x%llx prio=%d lirq=0x%x (rc=%lld)\n",
2519 num, be64_to_cpu(vp), prio, be32_to_cpu(lirq), rc);
2520}
2521
2522static void dump_xives(void)
2523{
2524 unsigned long num;
2525 int c;
2526
Breno Leitao402e1722017-10-17 16:20:18 -02002527 if (!xive_enabled()) {
2528 printf("Xive disabled on this system\n");
2529 return;
2530 }
2531
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002532 c = inchar();
2533 if (c == 'a') {
2534 dump_all_xives();
2535 return;
2536 } else if (c == 'i') {
2537 if (scanhex(&num))
2538 dump_one_xive_irq(num);
2539 return;
2540 }
2541
2542 termch = c; /* Put c back, it wasn't 'a' */
2543
2544 if (scanhex(&num))
2545 dump_one_xive(num);
2546 else
2547 dump_one_xive(xmon_owner);
2548}
2549#endif /* CONFIG_PPC_POWERNV */
2550
Douglas Miller5e48dc02017-02-07 07:40:44 -06002551static void dump_by_size(unsigned long addr, long count, int size)
2552{
2553 unsigned char temp[16];
2554 int i, j;
2555 u64 val;
2556
2557 count = ALIGN(count, 16);
2558
2559 for (i = 0; i < count; i += 16, addr += 16) {
2560 printf(REG, addr);
2561
2562 if (mread(addr, temp, 16) != 16) {
2563 printf("\nFaulted reading %d bytes from 0x"REG"\n", 16, addr);
2564 return;
2565 }
2566
2567 for (j = 0; j < 16; j += size) {
2568 putchar(' ');
2569 switch (size) {
2570 case 1: val = temp[j]; break;
2571 case 2: val = *(u16 *)&temp[j]; break;
2572 case 4: val = *(u32 *)&temp[j]; break;
2573 case 8: val = *(u64 *)&temp[j]; break;
2574 default: val = 0;
2575 }
2576
2577 printf("%0*lx", size * 2, val);
2578 }
2579 printf("\n");
2580 }
2581}
2582
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002583static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584dump(void)
2585{
Douglas Miller5e48dc02017-02-07 07:40:44 -06002586 static char last[] = { "d?\n" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 int c;
2588
2589 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002590
2591#ifdef CONFIG_PPC64
2592 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002593 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002594 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002595 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002596 return;
2597 }
2598#endif
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002599#ifdef CONFIG_PPC_POWERNV
2600 if (c == 'x') {
2601 xmon_start_pagination();
2602 dump_xives();
2603 xmon_end_pagination();
2604 return;
2605 }
2606#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002607
Breno Leitao4125d012017-08-02 17:14:05 -03002608 if (c == 't') {
2609 dump_tracing();
2610 return;
2611 }
2612
Douglas Miller5e48dc02017-02-07 07:40:44 -06002613 if (c == '\n')
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 termch = c;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002615
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 scanhex((void *)&adrs);
2617 if (termch != '\n')
2618 termch = 0;
2619 if (c == 'i') {
2620 scanhex(&nidump);
2621 if (nidump == 0)
2622 nidump = 16;
2623 else if (nidump > MAX_DUMP)
2624 nidump = MAX_DUMP;
2625 adrs += ppc_inst_dump(adrs, nidump, 1);
2626 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002627 } else if (c == 'l') {
2628 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002629 } else if (c == 'o') {
2630 dump_opal_msglog();
Balbir Singh80eff6c2017-10-30 22:01:12 +11002631 } else if (c == 'v') {
2632 /* dump virtual to physical translation */
2633 show_pte(adrs);
Olaf Hering7e5b5932006-03-08 20:40:28 +01002634 } else if (c == 'r') {
2635 scanhex(&ndump);
2636 if (ndump == 0)
2637 ndump = 64;
2638 xmon_rawdump(adrs, ndump);
2639 adrs += ndump;
2640 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 } else {
2642 scanhex(&ndump);
2643 if (ndump == 0)
2644 ndump = 64;
2645 else if (ndump > MAX_DUMP)
2646 ndump = MAX_DUMP;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002647
2648 switch (c) {
2649 case '8':
2650 case '4':
2651 case '2':
2652 case '1':
2653 ndump = ALIGN(ndump, 16);
2654 dump_by_size(adrs, ndump, c - '0');
2655 last[1] = c;
2656 last_cmd = last;
2657 break;
2658 default:
2659 prdump(adrs, ndump);
2660 last_cmd = "d\n";
2661 }
2662
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 adrs += ndump;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 }
2665}
2666
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002667static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668prdump(unsigned long adrs, long ndump)
2669{
2670 long n, m, c, r, nr;
2671 unsigned char temp[16];
2672
2673 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002674 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 putchar(' ');
2676 r = n < 16? n: 16;
2677 nr = mread(adrs, temp, r);
2678 adrs += nr;
2679 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002680 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002681 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 if (m < nr)
2683 printf("%.2x", temp[m]);
2684 else
2685 printf("%s", fault_chars[fault_type]);
2686 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002687 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002688 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002689 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 printf(" |");
2693 for (m = 0; m < r; ++m) {
2694 if (m < nr) {
2695 c = temp[m];
2696 putchar(' ' <= c && c <= '~'? c: '.');
2697 } else
2698 putchar(' ');
2699 }
2700 n -= r;
2701 for (; m < 16; ++m)
2702 putchar(' ');
2703 printf("|\n");
2704 if (nr < r)
2705 break;
2706 }
2707}
2708
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002709typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2710
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002711static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002712generic_inst_dump(unsigned long adr, long count, int praddr,
2713 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714{
2715 int nr, dotted;
2716 unsigned long first_adr;
2717 unsigned long inst, last_inst = 0;
2718 unsigned char val[4];
2719
2720 dotted = 0;
2721 for (first_adr = adr; count > 0; --count, adr += 4) {
2722 nr = mread(adr, val, 4);
2723 if (nr == 0) {
2724 if (praddr) {
2725 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002726 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 }
2728 break;
2729 }
2730 inst = GETWORD(val);
2731 if (adr > first_adr && inst == last_inst) {
2732 if (!dotted) {
2733 printf(" ...\n");
2734 dotted = 1;
2735 }
2736 continue;
2737 }
2738 dotted = 0;
2739 last_inst = inst;
2740 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002741 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002743 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 printf("\n");
2745 }
2746 return adr - first_adr;
2747}
2748
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002749static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002750ppc_inst_dump(unsigned long adr, long count, int praddr)
2751{
2752 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2753}
2754
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755void
2756print_address(unsigned long addr)
2757{
2758 xmon_print_symbol(addr, "\t# ", "");
2759}
2760
Vinay Sridharf312deb2009-05-14 23:13:07 +00002761void
2762dump_log_buf(void)
2763{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002764 struct kmsg_dumper dumper = { .active = 1 };
2765 unsigned char buf[128];
2766 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002767
Michael Ellermane3bc8042012-08-23 22:09:13 +00002768 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002769 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002770 return;
2771 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002772
Michael Ellermane3bc8042012-08-23 22:09:13 +00002773 catch_memory_errors = 1;
2774 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002775
Michael Ellermanca5dd392012-08-23 22:09:12 +00002776 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002777 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002778 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2779 buf[len] = '\0';
2780 printf("%s", buf);
2781 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002782 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002783
Michael Ellermane3bc8042012-08-23 22:09:13 +00002784 sync();
2785 /* wait a little while to see if we get a machine check */
2786 __delay(200);
2787 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002788}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002790#ifdef CONFIG_PPC_POWERNV
2791static void dump_opal_msglog(void)
2792{
2793 unsigned char buf[128];
2794 ssize_t res;
2795 loff_t pos = 0;
2796
2797 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2798 printf("Machine is not running OPAL firmware.\n");
2799 return;
2800 }
2801
2802 if (setjmp(bus_error_jmp) != 0) {
2803 printf("Error dumping OPAL msglog!\n");
2804 return;
2805 }
2806
2807 catch_memory_errors = 1;
2808 sync();
2809
2810 xmon_start_pagination();
2811 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2812 if (res < 0) {
2813 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2814 break;
2815 }
2816 buf[res] = '\0';
2817 printf("%s", buf);
2818 pos += res;
2819 }
2820 xmon_end_pagination();
2821
2822 sync();
2823 /* wait a little while to see if we get a machine check */
2824 __delay(200);
2825 catch_memory_errors = 0;
2826}
2827#endif
2828
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829/*
2830 * Memory operations - move, set, print differences
2831 */
2832static unsigned long mdest; /* destination address */
2833static unsigned long msrc; /* source address */
2834static unsigned long mval; /* byte value to set memory to */
2835static unsigned long mcount; /* # bytes to affect */
2836static unsigned long mdiffs; /* max # differences to print */
2837
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002838static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839memops(int cmd)
2840{
2841 scanhex((void *)&mdest);
2842 if( termch != '\n' )
2843 termch = 0;
2844 scanhex((void *)(cmd == 's'? &mval: &msrc));
2845 if( termch != '\n' )
2846 termch = 0;
2847 scanhex((void *)&mcount);
2848 switch( cmd ){
2849 case 'm':
2850 memmove((void *)mdest, (void *)msrc, mcount);
2851 break;
2852 case 's':
2853 memset((void *)mdest, mval, mcount);
2854 break;
2855 case 'd':
2856 if( termch != '\n' )
2857 termch = 0;
2858 scanhex((void *)&mdiffs);
2859 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2860 break;
2861 }
2862}
2863
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002864static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2866{
2867 unsigned n, prt;
2868
2869 prt = 0;
2870 for( n = nb; n > 0; --n )
2871 if( *p1++ != *p2++ )
2872 if( ++prt <= maxpr )
2873 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2874 p1[-1], p2 - 1, p2[-1]);
2875 if( prt > maxpr )
2876 printf("Total of %d differences\n", prt);
2877}
2878
2879static unsigned mend;
2880static unsigned mask;
2881
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002882static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883memlocate(void)
2884{
2885 unsigned a, n;
2886 unsigned char val[4];
2887
2888 last_cmd = "ml";
2889 scanhex((void *)&mdest);
2890 if (termch != '\n') {
2891 termch = 0;
2892 scanhex((void *)&mend);
2893 if (termch != '\n') {
2894 termch = 0;
2895 scanhex((void *)&mval);
2896 mask = ~0;
2897 if (termch != '\n') termch = 0;
2898 scanhex((void *)&mask);
2899 }
2900 }
2901 n = 0;
2902 for (a = mdest; a < mend; a += 4) {
2903 if (mread(a, val, 4) == 4
2904 && ((GETWORD(val) ^ mval) & mask) == 0) {
2905 printf("%.16x: %.16x\n", a, GETWORD(val));
2906 if (++n >= 10)
2907 break;
2908 }
2909 }
2910}
2911
2912static unsigned long mskip = 0x1000;
2913static unsigned long mlim = 0xffffffff;
2914
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002915static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916memzcan(void)
2917{
2918 unsigned char v;
2919 unsigned a;
2920 int ok, ook;
2921
2922 scanhex(&mdest);
2923 if (termch != '\n') termch = 0;
2924 scanhex(&mskip);
2925 if (termch != '\n') termch = 0;
2926 scanhex(&mlim);
2927 ook = 0;
2928 for (a = mdest; a < mlim; a += mskip) {
2929 ok = mread(a, &v, 1);
2930 if (ok && !ook) {
2931 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 } else if (!ok && ook)
2933 printf("%.8x\n", a - mskip);
2934 ook = ok;
2935 if (a + mskip < a)
2936 break;
2937 }
2938 if (ook)
2939 printf("%.8x\n", a - mskip);
2940}
2941
Douglas Miller6dfb5402015-11-23 09:01:15 -06002942static void show_task(struct task_struct *tsk)
2943{
2944 char state;
2945
2946 /*
2947 * Cloned from kdb_task_state_char(), which is not entirely
2948 * appropriate for calling from xmon. This could be moved
2949 * to a common, generic, routine used by both.
2950 */
2951 state = (tsk->state == 0) ? 'R' :
2952 (tsk->state < 0) ? 'U' :
2953 (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
2954 (tsk->state & TASK_STOPPED) ? 'T' :
2955 (tsk->state & TASK_TRACED) ? 'C' :
2956 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
2957 (tsk->exit_state & EXIT_DEAD) ? 'E' :
2958 (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
2959
Michael Ellermand8104182017-12-06 23:23:28 +11002960 printf("%px %016lx %6d %6d %c %2d %s\n", tsk,
Douglas Miller6dfb5402015-11-23 09:01:15 -06002961 tsk->thread.ksp,
2962 tsk->pid, tsk->parent->pid,
2963 state, task_thread_info(tsk)->cpu,
2964 tsk->comm);
2965}
2966
Balbir Singh80eff6c2017-10-30 22:01:12 +11002967#ifdef CONFIG_PPC_BOOK3S_64
2968void format_pte(void *ptep, unsigned long pte)
2969{
2970 printf("ptep @ 0x%016lx = 0x%016lx\n", (unsigned long)ptep, pte);
2971 printf("Maps physical address = 0x%016lx\n", pte & PTE_RPN_MASK);
2972
2973 printf("Flags = %s%s%s%s%s\n",
2974 (pte & _PAGE_ACCESSED) ? "Accessed " : "",
2975 (pte & _PAGE_DIRTY) ? "Dirty " : "",
2976 (pte & _PAGE_READ) ? "Read " : "",
2977 (pte & _PAGE_WRITE) ? "Write " : "",
2978 (pte & _PAGE_EXEC) ? "Exec " : "");
2979}
2980
2981static void show_pte(unsigned long addr)
2982{
2983 unsigned long tskv = 0;
2984 struct task_struct *tsk = NULL;
2985 struct mm_struct *mm;
2986 pgd_t *pgdp, *pgdir;
2987 pud_t *pudp;
2988 pmd_t *pmdp;
2989 pte_t *ptep;
2990
2991 if (!scanhex(&tskv))
2992 mm = &init_mm;
2993 else
2994 tsk = (struct task_struct *)tskv;
2995
2996 if (tsk == NULL)
2997 mm = &init_mm;
2998 else
2999 mm = tsk->active_mm;
3000
3001 if (setjmp(bus_error_jmp) != 0) {
3002 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11003003 printf("*** Error dumping pte for task %px\n", tsk);
Balbir Singh80eff6c2017-10-30 22:01:12 +11003004 return;
3005 }
3006
3007 catch_memory_errors = 1;
3008 sync();
3009
3010 if (mm == &init_mm) {
3011 pgdp = pgd_offset_k(addr);
3012 pgdir = pgd_offset_k(0);
3013 } else {
3014 pgdp = pgd_offset(mm, addr);
3015 pgdir = pgd_offset(mm, 0);
3016 }
3017
3018 if (pgd_none(*pgdp)) {
3019 printf("no linux page table for address\n");
3020 return;
3021 }
3022
3023 printf("pgd @ 0x%016lx\n", pgdir);
3024
3025 if (pgd_huge(*pgdp)) {
3026 format_pte(pgdp, pgd_val(*pgdp));
3027 return;
3028 }
3029 printf("pgdp @ 0x%016lx = 0x%016lx\n", pgdp, pgd_val(*pgdp));
3030
3031 pudp = pud_offset(pgdp, addr);
3032
3033 if (pud_none(*pudp)) {
3034 printf("No valid PUD\n");
3035 return;
3036 }
3037
3038 if (pud_huge(*pudp)) {
3039 format_pte(pudp, pud_val(*pudp));
3040 return;
3041 }
3042
3043 printf("pudp @ 0x%016lx = 0x%016lx\n", pudp, pud_val(*pudp));
3044
3045 pmdp = pmd_offset(pudp, addr);
3046
3047 if (pmd_none(*pmdp)) {
3048 printf("No valid PMD\n");
3049 return;
3050 }
3051
3052 if (pmd_huge(*pmdp)) {
3053 format_pte(pmdp, pmd_val(*pmdp));
3054 return;
3055 }
3056 printf("pmdp @ 0x%016lx = 0x%016lx\n", pmdp, pmd_val(*pmdp));
3057
3058 ptep = pte_offset_map(pmdp, addr);
3059 if (pte_none(*ptep)) {
3060 printf("no valid PTE\n");
3061 return;
3062 }
3063
3064 format_pte(ptep, pte_val(*ptep));
3065
3066 sync();
3067 __delay(200);
3068 catch_memory_errors = 0;
3069}
3070#else
3071static void show_pte(unsigned long addr)
3072{
3073 printf("show_pte not yet implemented\n");
3074}
3075#endif /* CONFIG_PPC_BOOK3S_64 */
3076
Douglas Miller6dfb5402015-11-23 09:01:15 -06003077static void show_tasks(void)
3078{
3079 unsigned long tskv;
3080 struct task_struct *tsk = NULL;
3081
3082 printf(" task_struct ->thread.ksp PID PPID S P CMD\n");
3083
3084 if (scanhex(&tskv))
3085 tsk = (struct task_struct *)tskv;
3086
3087 if (setjmp(bus_error_jmp) != 0) {
3088 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11003089 printf("*** Error dumping task %px\n", tsk);
Douglas Miller6dfb5402015-11-23 09:01:15 -06003090 return;
3091 }
3092
3093 catch_memory_errors = 1;
3094 sync();
3095
3096 if (tsk)
3097 show_task(tsk);
3098 else
3099 for_each_process(tsk)
3100 show_task(tsk);
3101
3102 sync();
3103 __delay(200);
3104 catch_memory_errors = 0;
3105}
3106
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003107static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003108{
3109 unsigned long args[8];
3110 unsigned long ret;
3111 int i;
3112 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
3113 unsigned long, unsigned long, unsigned long,
3114 unsigned long, unsigned long, unsigned long);
3115 callfunc_t func;
3116
3117 if (!scanhex(&adrs))
3118 return;
3119 if (termch != '\n')
3120 termch = 0;
3121 for (i = 0; i < 8; ++i)
3122 args[i] = 0;
3123 for (i = 0; i < 8; ++i) {
3124 if (!scanhex(&args[i]) || termch == '\n')
3125 break;
3126 termch = 0;
3127 }
3128 func = (callfunc_t) adrs;
3129 ret = 0;
3130 if (setjmp(bus_error_jmp) == 0) {
3131 catch_memory_errors = 1;
3132 sync();
3133 ret = func(args[0], args[1], args[2], args[3],
3134 args[4], args[5], args[6], args[7]);
3135 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10003136 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003137 } else {
3138 printf("*** %x exception occurred\n", fault_except);
3139 }
3140 catch_memory_errors = 0;
3141}
3142
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143/* Input scanning routines */
3144int
3145skipbl(void)
3146{
3147 int c;
3148
3149 if( termch != 0 ){
3150 c = termch;
3151 termch = 0;
3152 } else
3153 c = inchar();
3154 while( c == ' ' || c == '\t' )
3155 c = inchar();
3156 return c;
3157}
3158
3159#define N_PTREGS 44
3160static char *regnames[N_PTREGS] = {
3161 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
3162 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
3163 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
3164 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003165 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
3166#ifdef CONFIG_PPC64
3167 "softe",
3168#else
3169 "mq",
3170#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 "trap", "dar", "dsisr", "res"
3172};
3173
3174int
3175scanhex(unsigned long *vp)
3176{
3177 int c, d;
3178 unsigned long v;
3179
3180 c = skipbl();
3181 if (c == '%') {
3182 /* parse register name */
3183 char regname[8];
3184 int i;
3185
3186 for (i = 0; i < sizeof(regname) - 1; ++i) {
3187 c = inchar();
3188 if (!isalnum(c)) {
3189 termch = c;
3190 break;
3191 }
3192 regname[i] = c;
3193 }
3194 regname[i] = 0;
3195 for (i = 0; i < N_PTREGS; ++i) {
3196 if (strcmp(regnames[i], regname) == 0) {
3197 if (xmon_regs == NULL) {
3198 printf("regs not available\n");
3199 return 0;
3200 }
3201 *vp = ((unsigned long *)xmon_regs)[i];
3202 return 1;
3203 }
3204 }
3205 printf("invalid register name '%%%s'\n", regname);
3206 return 0;
3207 }
3208
3209 /* skip leading "0x" if any */
3210
3211 if (c == '0') {
3212 c = inchar();
3213 if (c == 'x') {
3214 c = inchar();
3215 } else {
3216 d = hexdigit(c);
3217 if (d == EOF) {
3218 termch = c;
3219 *vp = 0;
3220 return 1;
3221 }
3222 }
3223 } else if (c == '$') {
3224 int i;
3225 for (i=0; i<63; i++) {
3226 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02003227 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 termch = c;
3229 break;
3230 }
3231 tmpstr[i] = c;
3232 }
3233 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07003234 *vp = 0;
3235 if (setjmp(bus_error_jmp) == 0) {
3236 catch_memory_errors = 1;
3237 sync();
3238 *vp = kallsyms_lookup_name(tmpstr);
3239 sync();
3240 }
3241 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 if (!(*vp)) {
3243 printf("unknown symbol '%s'\n", tmpstr);
3244 return 0;
3245 }
3246 return 1;
3247 }
3248
3249 d = hexdigit(c);
3250 if (d == EOF) {
3251 termch = c;
3252 return 0;
3253 }
3254 v = 0;
3255 do {
3256 v = (v << 4) + d;
3257 c = inchar();
3258 d = hexdigit(c);
3259 } while (d != EOF);
3260 termch = c;
3261 *vp = v;
3262 return 1;
3263}
3264
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003265static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266scannl(void)
3267{
3268 int c;
3269
3270 c = termch;
3271 termch = 0;
3272 while( c != '\n' )
3273 c = inchar();
3274}
3275
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003276static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277{
3278 if( '0' <= c && c <= '9' )
3279 return c - '0';
3280 if( 'A' <= c && c <= 'F' )
3281 return c - ('A' - 10);
3282 if( 'a' <= c && c <= 'f' )
3283 return c - ('a' - 10);
3284 return EOF;
3285}
3286
3287void
3288getstring(char *s, int size)
3289{
3290 int c;
3291
3292 c = skipbl();
3293 do {
3294 if( size > 1 ){
3295 *s++ = c;
3296 --size;
3297 }
3298 c = inchar();
3299 } while( c != ' ' && c != '\t' && c != '\n' );
3300 termch = c;
3301 *s = 0;
3302}
3303
3304static char line[256];
3305static char *lineptr;
3306
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003307static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308flush_input(void)
3309{
3310 lineptr = NULL;
3311}
3312
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003313static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314inchar(void)
3315{
3316 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003317 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 lineptr = NULL;
3319 return EOF;
3320 }
3321 lineptr = line;
3322 }
3323 return *lineptr++;
3324}
3325
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003326static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327take_input(char *str)
3328{
3329 lineptr = str;
3330}
3331
3332
3333static void
3334symbol_lookup(void)
3335{
3336 int type = inchar();
3337 unsigned long addr;
3338 static char tmp[64];
3339
3340 switch (type) {
3341 case 'a':
3342 if (scanhex(&addr))
3343 xmon_print_symbol(addr, ": ", "\n");
3344 termch = 0;
3345 break;
3346 case 's':
3347 getstring(tmp, 64);
3348 if (setjmp(bus_error_jmp) == 0) {
3349 catch_memory_errors = 1;
3350 sync();
3351 addr = kallsyms_lookup_name(tmp);
3352 if (addr)
3353 printf("%s: %lx\n", tmp, addr);
3354 else
3355 printf("Symbol '%s' not found.\n", tmp);
3356 sync();
3357 }
3358 catch_memory_errors = 0;
3359 termch = 0;
3360 break;
3361 }
3362}
3363
3364
3365/* Print an address in numeric and symbolic form (if possible) */
3366static void xmon_print_symbol(unsigned long address, const char *mid,
3367 const char *after)
3368{
3369 char *modname;
3370 const char *name = NULL;
3371 unsigned long offset, size;
3372
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003373 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 if (setjmp(bus_error_jmp) == 0) {
3375 catch_memory_errors = 1;
3376 sync();
3377 name = kallsyms_lookup(address, &size, &offset, &modname,
3378 tmpstr);
3379 sync();
3380 /* wait a little while to see if we get a machine check */
3381 __delay(200);
3382 }
3383
3384 catch_memory_errors = 0;
3385
3386 if (name) {
3387 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
3388 if (modname)
3389 printf(" [%s]", modname);
3390 }
3391 printf("%s", after);
3392}
3393
Michael Ellerman4e003742017-10-19 15:08:43 +11003394#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10003395void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396{
3397 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05303398 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11003399 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400
Michael Ellerman736256e2014-05-26 21:02:14 +10003401 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402
Michael Neuling584f8b72007-12-06 17:24:48 +11003403 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11003404 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
3405 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Michael Ellerman85673642017-04-24 10:35:14 +10003406
3407 if (!esid && !vsid)
3408 continue;
3409
3410 printf("%02d %016lx %016lx", i, esid, vsid);
3411
3412 if (!(esid & SLB_ESID_V)) {
3413 printf("\n");
3414 continue;
3415 }
3416
3417 llp = vsid & SLB_VSID_LLP;
3418 if (vsid & SLB_VSID_B_1T) {
3419 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
3420 GET_ESID_1T(esid),
3421 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
3422 llp);
3423 } else {
3424 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
3425 GET_ESID(esid),
3426 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
3427 llp);
will schmidtb3b95952007-12-07 08:22:23 +11003428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 }
3430}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003431#endif
3432
3433#ifdef CONFIG_PPC_STD_MMU_32
3434void dump_segments(void)
3435{
3436 int i;
3437
3438 printf("sr0-15 =");
3439 for (i = 0; i < 16; ++i)
3440 printf(" %x", mfsrin(i));
3441 printf("\n");
3442}
3443#endif
3444
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003445#ifdef CONFIG_44x
3446static void dump_tlb_44x(void)
3447{
3448 int i;
3449
3450 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
3451 unsigned long w0,w1,w2;
3452 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
3453 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
3454 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
3455 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
3456 if (w0 & PPC44x_TLB_VALID) {
3457 printf("V %08x -> %01x%08x %c%c%c%c%c",
3458 w0 & PPC44x_TLB_EPN_MASK,
3459 w1 & PPC44x_TLB_ERPN_MASK,
3460 w1 & PPC44x_TLB_RPN_MASK,
3461 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
3462 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
3463 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
3464 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
3465 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
3466 }
3467 printf("\n");
3468 }
3469}
3470#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003471
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10003472#ifdef CONFIG_PPC_BOOK3E
3473static void dump_tlb_book3e(void)
3474{
3475 u32 mmucfg, pidmask, lpidmask;
3476 u64 ramask;
3477 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3478 int mmu_version;
3479 static const char *pgsz_names[] = {
3480 " 1K",
3481 " 2K",
3482 " 4K",
3483 " 8K",
3484 " 16K",
3485 " 32K",
3486 " 64K",
3487 "128K",
3488 "256K",
3489 "512K",
3490 " 1M",
3491 " 2M",
3492 " 4M",
3493 " 8M",
3494 " 16M",
3495 " 32M",
3496 " 64M",
3497 "128M",
3498 "256M",
3499 "512M",
3500 " 1G",
3501 " 2G",
3502 " 4G",
3503 " 8G",
3504 " 16G",
3505 " 32G",
3506 " 64G",
3507 "128G",
3508 "256G",
3509 "512G",
3510 " 1T",
3511 " 2T",
3512 };
3513
3514 /* Gather some infos about the MMU */
3515 mmucfg = mfspr(SPRN_MMUCFG);
3516 mmu_version = (mmucfg & 3) + 1;
3517 ntlbs = ((mmucfg >> 2) & 3) + 1;
3518 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3519 lpidsz = (mmucfg >> 24) & 0xf;
3520 rasz = (mmucfg >> 16) & 0x7f;
3521 if ((mmu_version > 1) && (mmucfg & 0x10000))
3522 lrat = 1;
3523 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3524 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3525 pidmask = (1ul << pidsz) - 1;
3526 lpidmask = (1ul << lpidsz) - 1;
3527 ramask = (1ull << rasz) - 1;
3528
3529 for (tlb = 0; tlb < ntlbs; tlb++) {
3530 u32 tlbcfg;
3531 int nent, assoc, new_cc = 1;
3532 printf("TLB %d:\n------\n", tlb);
3533 switch(tlb) {
3534 case 0:
3535 tlbcfg = mfspr(SPRN_TLB0CFG);
3536 break;
3537 case 1:
3538 tlbcfg = mfspr(SPRN_TLB1CFG);
3539 break;
3540 case 2:
3541 tlbcfg = mfspr(SPRN_TLB2CFG);
3542 break;
3543 case 3:
3544 tlbcfg = mfspr(SPRN_TLB3CFG);
3545 break;
3546 default:
3547 printf("Unsupported TLB number !\n");
3548 continue;
3549 }
3550 nent = tlbcfg & 0xfff;
3551 assoc = (tlbcfg >> 24) & 0xff;
3552 for (i = 0; i < nent; i++) {
3553 u32 mas0 = MAS0_TLBSEL(tlb);
3554 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3555 u64 mas2 = 0;
3556 u64 mas7_mas3;
3557 int esel = i, cc = i;
3558
3559 if (assoc != 0) {
3560 cc = i / assoc;
3561 esel = i % assoc;
3562 mas2 = cc * 0x1000;
3563 }
3564
3565 mas0 |= MAS0_ESEL(esel);
3566 mtspr(SPRN_MAS0, mas0);
3567 mtspr(SPRN_MAS1, mas1);
3568 mtspr(SPRN_MAS2, mas2);
3569 asm volatile("tlbre 0,0,0" : : : "memory");
3570 mas1 = mfspr(SPRN_MAS1);
3571 mas2 = mfspr(SPRN_MAS2);
3572 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3573 if (assoc && (i % assoc) == 0)
3574 new_cc = 1;
3575 if (!(mas1 & MAS1_VALID))
3576 continue;
3577 if (assoc == 0)
3578 printf("%04x- ", i);
3579 else if (new_cc)
3580 printf("%04x-%c", cc, 'A' + esel);
3581 else
3582 printf(" |%c", 'A' + esel);
3583 new_cc = 0;
3584 printf(" %016llx %04x %s %c%c AS%c",
3585 mas2 & ~0x3ffull,
3586 (mas1 >> 16) & 0x3fff,
3587 pgsz_names[(mas1 >> 7) & 0x1f],
3588 mas1 & MAS1_IND ? 'I' : ' ',
3589 mas1 & MAS1_IPROT ? 'P' : ' ',
3590 mas1 & MAS1_TS ? '1' : '0');
3591 printf(" %c%c%c%c%c%c%c",
3592 mas2 & MAS2_X0 ? 'a' : ' ',
3593 mas2 & MAS2_X1 ? 'v' : ' ',
3594 mas2 & MAS2_W ? 'w' : ' ',
3595 mas2 & MAS2_I ? 'i' : ' ',
3596 mas2 & MAS2_M ? 'm' : ' ',
3597 mas2 & MAS2_G ? 'g' : ' ',
3598 mas2 & MAS2_E ? 'e' : ' ');
3599 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3600 if (mas1 & MAS1_IND)
3601 printf(" %s\n",
3602 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3603 else
3604 printf(" U%c%c%c S%c%c%c\n",
3605 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3606 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3607 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3608 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3609 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3610 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3611 }
3612 }
3613}
3614#endif /* CONFIG_PPC_BOOK3E */
3615
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003616static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003618 if (enable) {
3619 __debugger = xmon;
3620 __debugger_ipi = xmon_ipi;
3621 __debugger_bpt = xmon_bpt;
3622 __debugger_sstep = xmon_sstep;
3623 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003624 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003625 __debugger_fault_handler = xmon_fault_handler;
3626 } else {
3627 __debugger = NULL;
3628 __debugger_ipi = NULL;
3629 __debugger_bpt = NULL;
3630 __debugger_sstep = NULL;
3631 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003632 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003633 __debugger_fault_handler = NULL;
3634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003636
3637#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003638static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003639{
3640 /* ensure xmon is enabled */
3641 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003642 debugger(get_irq_regs());
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003643 if (!xmon_on)
3644 xmon_init(0);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003645}
3646
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003647static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003648 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003649 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003650 .action_msg = "Entering xmon",
3651};
3652
3653static int __init setup_xmon_sysrq(void)
3654{
3655 register_sysrq_key('x', &sysrq_xmon_op);
3656 return 0;
3657}
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003658device_initcall(setup_xmon_sysrq);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003659#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003660
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003661#ifdef CONFIG_DEBUG_FS
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05303662static void clear_all_bpt(void)
3663{
3664 int i;
3665
3666 /* clear/unpatch all breakpoints */
3667 remove_bpts();
3668 remove_cpu_bpts();
3669
3670 /* Disable all breakpoints */
3671 for (i = 0; i < NBPTS; ++i)
3672 bpts[i].enabled = 0;
3673
3674 /* Clear any data or iabr breakpoints */
3675 if (iabr || dabr.enabled) {
3676 iabr = NULL;
3677 dabr.enabled = 0;
3678 }
3679
3680 printf("xmon: All breakpoints cleared\n");
3681}
3682
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003683static int xmon_dbgfs_set(void *data, u64 val)
3684{
3685 xmon_on = !!val;
3686 xmon_init(xmon_on);
3687
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05303688 /* make sure all breakpoints removed when disabling */
3689 if (!xmon_on)
3690 clear_all_bpt();
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003691 return 0;
3692}
3693
3694static int xmon_dbgfs_get(void *data, u64 *val)
3695{
3696 *val = xmon_on;
3697 return 0;
3698}
3699
3700DEFINE_SIMPLE_ATTRIBUTE(xmon_dbgfs_ops, xmon_dbgfs_get,
3701 xmon_dbgfs_set, "%llu\n");
3702
3703static int __init setup_xmon_dbgfs(void)
3704{
3705 debugfs_create_file("xmon", 0600, powerpc_debugfs_root, NULL,
3706 &xmon_dbgfs_ops);
3707 return 0;
3708}
3709device_initcall(setup_xmon_dbgfs);
3710#endif /* CONFIG_DEBUG_FS */
3711
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003712static int xmon_early __initdata;
Michael Ellerman476792832006-10-03 14:12:08 +10003713
3714static int __init early_parse_xmon(char *p)
3715{
3716 if (!p || strncmp(p, "early", 5) == 0) {
3717 /* just "xmon" is equivalent to "xmon=early" */
3718 xmon_init(1);
3719 xmon_early = 1;
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003720 xmon_on = 1;
3721 } else if (strncmp(p, "on", 2) == 0) {
Michael Ellerman476792832006-10-03 14:12:08 +10003722 xmon_init(1);
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003723 xmon_on = 1;
3724 } else if (strncmp(p, "off", 3) == 0)
3725 xmon_on = 0;
Michael Ellerman476792832006-10-03 14:12:08 +10003726 else
3727 return 1;
3728
3729 return 0;
3730}
3731early_param("xmon", early_parse_xmon);
3732
3733void __init xmon_setup(void)
3734{
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003735 if (xmon_on)
Michael Ellerman476792832006-10-03 14:12:08 +10003736 xmon_init(1);
Michael Ellerman476792832006-10-03 14:12:08 +10003737 if (xmon_early)
3738 debugger(NULL);
3739}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003740
Arnd Bergmanne0555952006-11-27 19:18:55 +01003741#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003742
3743struct spu_info {
3744 struct spu *spu;
3745 u64 saved_mfc_sr1_RW;
3746 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003747 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003748 u8 stopped_ok;
3749};
3750
3751#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3752
3753static struct spu_info spu_info[XMON_NUM_SPUS];
3754
3755void xmon_register_spus(struct list_head *list)
3756{
3757 struct spu *spu;
3758
3759 list_for_each_entry(spu, list, full_list) {
3760 if (spu->number >= XMON_NUM_SPUS) {
3761 WARN_ON(1);
3762 continue;
3763 }
3764
3765 spu_info[spu->number].spu = spu;
3766 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003767 spu_info[spu->number].dump_addr = (unsigned long)
3768 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003769 }
3770}
3771
3772static void stop_spus(void)
3773{
3774 struct spu *spu;
3775 int i;
3776 u64 tmp;
3777
3778 for (i = 0; i < XMON_NUM_SPUS; i++) {
3779 if (!spu_info[i].spu)
3780 continue;
3781
3782 if (setjmp(bus_error_jmp) == 0) {
3783 catch_memory_errors = 1;
3784 sync();
3785
3786 spu = spu_info[i].spu;
3787
3788 spu_info[i].saved_spu_runcntl_RW =
3789 in_be32(&spu->problem->spu_runcntl_RW);
3790
3791 tmp = spu_mfc_sr1_get(spu);
3792 spu_info[i].saved_mfc_sr1_RW = tmp;
3793
3794 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3795 spu_mfc_sr1_set(spu, tmp);
3796
3797 sync();
3798 __delay(200);
3799
3800 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003801
3802 printf("Stopped spu %.2d (was %s)\n", i,
3803 spu_info[i].saved_spu_runcntl_RW ?
3804 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003805 } else {
3806 catch_memory_errors = 0;
3807 printf("*** Error stopping spu %.2d\n", i);
3808 }
3809 catch_memory_errors = 0;
3810 }
3811}
3812
3813static void restart_spus(void)
3814{
3815 struct spu *spu;
3816 int i;
3817
3818 for (i = 0; i < XMON_NUM_SPUS; i++) {
3819 if (!spu_info[i].spu)
3820 continue;
3821
3822 if (!spu_info[i].stopped_ok) {
3823 printf("*** Error, spu %d was not successfully stopped"
3824 ", not restarting\n", i);
3825 continue;
3826 }
3827
3828 if (setjmp(bus_error_jmp) == 0) {
3829 catch_memory_errors = 1;
3830 sync();
3831
3832 spu = spu_info[i].spu;
3833 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3834 out_be32(&spu->problem->spu_runcntl_RW,
3835 spu_info[i].saved_spu_runcntl_RW);
3836
3837 sync();
3838 __delay(200);
3839
3840 printf("Restarted spu %.2d\n", i);
3841 } else {
3842 catch_memory_errors = 0;
3843 printf("*** Error restarting spu %.2d\n", i);
3844 }
3845 catch_memory_errors = 0;
3846 }
3847}
3848
Michael Ellermana8984972006-10-24 18:31:28 +02003849#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003850#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003851do { \
3852 if (setjmp(bus_error_jmp) == 0) { \
3853 catch_memory_errors = 1; \
3854 sync(); \
3855 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003856 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003857 sync(); \
3858 __delay(200); \
3859 } else { \
3860 catch_memory_errors = 0; \
3861 printf(" %-*s = *** Error reading field.\n", \
3862 DUMP_WIDTH, #field); \
3863 } \
3864 catch_memory_errors = 0; \
3865} while (0)
3866
Michael Ellerman437a0702006-11-23 00:46:39 +01003867#define DUMP_FIELD(obj, format, field) \
3868 DUMP_VALUE(format, field, obj->field)
3869
Michael Ellermana8984972006-10-24 18:31:28 +02003870static void dump_spu_fields(struct spu *spu)
3871{
3872 printf("Dumping spu fields at address %p:\n", spu);
3873
3874 DUMP_FIELD(spu, "0x%x", number);
3875 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003876 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3877 DUMP_FIELD(spu, "0x%p", local_store);
3878 DUMP_FIELD(spu, "0x%lx", ls_size);
3879 DUMP_FIELD(spu, "0x%x", node);
3880 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003881 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003882 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003883 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3884 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003885 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3886 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3887 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3888 DUMP_FIELD(spu, "0x%x", slb_replace);
3889 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003890 DUMP_FIELD(spu, "0x%p", mm);
3891 DUMP_FIELD(spu, "0x%p", ctx);
3892 DUMP_FIELD(spu, "0x%p", rq);
3893 DUMP_FIELD(spu, "0x%p", timestamp);
3894 DUMP_FIELD(spu, "0x%lx", problem_phys);
3895 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003896 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3897 in_be32(&spu->problem->spu_runcntl_RW));
3898 DUMP_VALUE("0x%x", problem->spu_status_R,
3899 in_be32(&spu->problem->spu_status_R));
3900 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3901 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003902 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003903 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003904}
3905
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003906int
3907spu_inst_dump(unsigned long adr, long count, int praddr)
3908{
3909 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3910}
3911
3912static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003913{
3914 unsigned long offset, addr, ls_addr;
3915
3916 if (setjmp(bus_error_jmp) == 0) {
3917 catch_memory_errors = 1;
3918 sync();
3919 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3920 sync();
3921 __delay(200);
3922 } else {
3923 catch_memory_errors = 0;
3924 printf("*** Error: accessing spu info for spu %d\n", num);
3925 return;
3926 }
3927 catch_memory_errors = 0;
3928
3929 if (scanhex(&offset))
3930 addr = ls_addr + offset;
3931 else
3932 addr = spu_info[num].dump_addr;
3933
3934 if (addr >= ls_addr + LS_SIZE) {
3935 printf("*** Error: address outside of local store\n");
3936 return;
3937 }
3938
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003939 switch (subcmd) {
3940 case 'i':
3941 addr += spu_inst_dump(addr, 16, 1);
3942 last_cmd = "sdi\n";
3943 break;
3944 default:
3945 prdump(addr, 64);
3946 addr += 64;
3947 last_cmd = "sd\n";
3948 break;
3949 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003950
3951 spu_info[num].dump_addr = addr;
3952}
3953
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003954static int do_spu_cmd(void)
3955{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003956 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003957 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003958
3959 cmd = inchar();
3960 switch (cmd) {
3961 case 's':
3962 stop_spus();
3963 break;
3964 case 'r':
3965 restart_spus();
3966 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003967 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003968 subcmd = inchar();
3969 if (isxdigit(subcmd) || subcmd == '\n')
3970 termch = subcmd;
3971 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003972 scanhex(&num);
3973 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003974 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003975 return 0;
3976 }
3977
3978 switch (cmd) {
3979 case 'f':
3980 dump_spu_fields(spu_info[num].spu);
3981 break;
3982 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003983 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003984 break;
3985 }
3986
Michael Ellermana8984972006-10-24 18:31:28 +02003987 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003988 default:
3989 return -1;
3990 }
3991
3992 return 0;
3993}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003994#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003995static int do_spu_cmd(void)
3996{
3997 return -1;
3998}
3999#endif