blob: c2e9270728c75ef4ff9919090183653d18578dcc [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) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +0200518 printf("cpu 0x%x stopped at breakpoint 0x%tx (",
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) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +0200625 printf("Stopped at breakpoint %tx (", 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
Michal Suchanek7daf5932018-05-23 20:00:54 +0200781/* Force enable xmon if not already enabled */
782static inline void force_enable_xmon(void)
783{
784 /* Enable xmon hooks if needed */
785 if (!xmon_on) {
786 printf("xmon: Enabling debugger hooks\n");
787 xmon_on = 1;
788 }
789}
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791static struct bpt *at_breakpoint(unsigned long pc)
792{
793 int i;
794 struct bpt *bp;
795
796 bp = bpts;
797 for (i = 0; i < NBPTS; ++i, ++bp)
798 if (bp->enabled && pc == bp->address)
799 return bp;
800 return NULL;
801}
802
803static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
804{
805 unsigned long off;
806
807 off = nip - (unsigned long) bpts;
808 if (off >= sizeof(bpts))
809 return NULL;
810 off %= sizeof(struct bpt);
811 if (off != offsetof(struct bpt, instr[0])
812 && off != offsetof(struct bpt, instr[1]))
813 return NULL;
814 *offp = off - offsetof(struct bpt, instr[0]);
815 return (struct bpt *) (nip - off);
816}
817
818static struct bpt *new_breakpoint(unsigned long a)
819{
820 struct bpt *bp;
821
822 a &= ~3UL;
823 bp = at_breakpoint(a);
824 if (bp)
825 return bp;
826
827 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
828 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
829 bp->address = a;
830 bp->instr[1] = bpinstr;
831 store_inst(&bp->instr[1]);
832 return bp;
833 }
834 }
835
836 printf("Sorry, no free breakpoints. Please clear one first.\n");
837 return NULL;
838}
839
840static void insert_bpts(void)
841{
842 int i;
843 struct bpt *bp;
844
845 bp = bpts;
846 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100847 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 continue;
849 if (mread(bp->address, &bp->instr[0], 4) != 4) {
850 printf("Couldn't read instruction at %lx, "
851 "disabling breakpoint there\n", bp->address);
852 bp->enabled = 0;
853 continue;
854 }
855 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
856 printf("Breakpoint at %lx is on an mtmsrd or rfid "
857 "instruction, disabling it\n", bp->address);
858 bp->enabled = 0;
859 continue;
860 }
861 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100862 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 continue;
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000864 if (patch_instruction((unsigned int *)bp->address,
865 bpinstr) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 printf("Couldn't write instruction at %lx, "
867 "disabling breakpoint there\n", bp->address);
868 bp->enabled &= ~BP_TRAP;
869 continue;
870 }
871 store_inst((void *)bp->address);
872 }
873}
874
875static void insert_cpu_bpts(void)
876{
Michael Neuling9422de32012-12-20 14:06:44 +0000877 struct arch_hw_breakpoint brk;
878
879 if (dabr.enabled) {
880 brk.address = dabr.address;
881 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
882 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400883 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000884 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530885
886 if (iabr)
887 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888}
889
890static void remove_bpts(void)
891{
892 int i;
893 struct bpt *bp;
894 unsigned instr;
895
896 bp = bpts;
897 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100898 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 continue;
900 if (mread(bp->address, &instr, 4) == 4
901 && instr == bpinstr
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000902 && patch_instruction(
903 (unsigned int *)bp->address, bp->instr[0]) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 printf("Couldn't remove breakpoint at %lx\n",
905 bp->address);
906 else
907 store_inst((void *)bp->address);
908 }
909}
910
911static void remove_cpu_bpts(void)
912{
Michael Neuling9422de32012-12-20 14:06:44 +0000913 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530914 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915}
916
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300917/* Based on uptime_proc_show(). */
918static void
919show_uptime(void)
920{
921 struct timespec uptime;
922
923 if (setjmp(bus_error_jmp) == 0) {
924 catch_memory_errors = 1;
925 sync();
926
927 get_monotonic_boottime(&uptime);
928 printf("Uptime: %lu.%.2lu seconds\n", (unsigned long)uptime.tv_sec,
929 ((unsigned long)uptime.tv_nsec / (NSEC_PER_SEC/100)));
930
931 sync();
932 __delay(200); \
933 }
934 catch_memory_errors = 0;
935}
936
Sam bobroff958b7c82015-10-08 11:50:23 +1100937static void set_lpp_cmd(void)
938{
939 unsigned long lpp;
940
941 if (!scanhex(&lpp)) {
942 printf("Invalid number.\n");
943 lpp = 0;
944 }
945 xmon_set_pagination_lpp(lpp);
946}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947/* Command interpreting routine */
948static char *last_cmd;
949
950static int
951cmds(struct pt_regs *excp)
952{
953 int cmd = 0;
954
955 last_cmd = NULL;
956 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200957
Guilherme G. Piccolib5617832017-03-22 16:27:50 -0300958 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
Olaf Hering26c8af52006-09-08 16:29:21 +0200959
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 for(;;) {
961#ifdef CONFIG_SMP
962 printf("%x:", smp_processor_id());
963#endif /* CONFIG_SMP */
964 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 flush_input();
966 termch = 0;
967 cmd = skipbl();
968 if( cmd == '\n' ) {
969 if (last_cmd == NULL)
970 continue;
971 take_input(last_cmd);
972 last_cmd = NULL;
973 cmd = inchar();
974 }
975 switch (cmd) {
976 case 'm':
977 cmd = inchar();
978 switch (cmd) {
979 case 'm':
980 case 's':
981 case 'd':
982 memops(cmd);
983 break;
984 case 'l':
985 memlocate();
986 break;
987 case 'z':
988 memzcan();
989 break;
990 case 'i':
Michal Hocko9af744d2017-02-22 15:46:16 -0800991 show_mem(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 break;
993 default:
994 termch = cmd;
995 memex();
996 }
997 break;
998 case 'd':
999 dump();
1000 break;
1001 case 'l':
1002 symbol_lookup();
1003 break;
1004 case 'r':
1005 prregs(excp); /* print regs */
1006 break;
1007 case 'e':
1008 excprint(excp);
1009 break;
1010 case 'S':
1011 super_regs();
1012 break;
1013 case 't':
1014 backtrace(excp);
1015 break;
1016 case 'f':
1017 cacheflush();
1018 break;
1019 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +02001020 if (do_spu_cmd() == 0)
1021 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 if (do_step(excp))
1023 return cmd;
1024 break;
1025 case 'x':
1026 case 'X':
Breno Leitaoed49f7f2017-08-02 17:14:06 -03001027 if (tracing_enabled)
1028 tracing_on();
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001029 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001031 printf(" <no input ...>\n");
1032 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 return cmd;
1034 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +10001035 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 break;
Sam bobroff958b7c82015-10-08 11:50:23 +11001037 case '#':
1038 set_lpp_cmd();
1039 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 case 'b':
1041 bpt_cmds();
1042 break;
1043 case 'C':
1044 csum();
1045 break;
1046 case 'c':
1047 if (cpu_cmd())
1048 return 0;
1049 break;
1050 case 'z':
1051 bootcmds();
1052 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001053 case 'p':
1054 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -06001056 case 'P':
1057 show_tasks();
1058 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001059#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 case 'u':
1061 dump_segments();
1062 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +11001063#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11001064 case 'u':
1065 dump_tlb_44x();
1066 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +00001067#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10001068 case 'u':
1069 dump_tlb_book3e();
1070 break;
1071#endif
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -03001072 case 'U':
1073 show_uptime();
1074 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 default:
1076 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +00001077 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 if (' ' < cmd && cmd <= '~')
1079 putchar(cmd);
1080 else
1081 printf("\\x%x", cmd);
1082 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +00001083 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 printf(" (type ? for help)\n");
1085 break;
1086 }
1087 }
1088}
1089
Josh Boyercdd39042009-10-05 04:46:05 +00001090#ifdef CONFIG_BOOKE
1091static int do_step(struct pt_regs *regs)
1092{
1093 regs->msr |= MSR_DE;
1094 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1095 return 1;
1096}
1097#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098/*
1099 * Step a single instruction.
1100 * Some instructions we emulate, others we execute with MSR_SE set.
1101 */
1102static int do_step(struct pt_regs *regs)
1103{
1104 unsigned int instr;
1105 int stepped;
1106
Michal Suchanek7daf5932018-05-23 20:00:54 +02001107 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001109 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 if (mread(regs->nip, &instr, 4) == 4) {
1111 stepped = emulate_step(regs, instr);
1112 if (stepped < 0) {
1113 printf("Couldn't single-step %s instruction\n",
1114 (IS_RFID(instr)? "rfid": "mtmsrd"));
1115 return 0;
1116 }
1117 if (stepped > 0) {
1118 regs->trap = 0xd00 | (regs->trap & 1);
1119 printf("stepped to ");
1120 xmon_print_symbol(regs->nip, " ", "\n");
1121 ppc_inst_dump(regs->nip, 1, 0);
1122 return 0;
1123 }
1124 }
1125 }
1126 regs->msr |= MSR_SE;
1127 return 1;
1128}
Josh Boyercdd39042009-10-05 04:46:05 +00001129#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
1131static void bootcmds(void)
1132{
1133 int cmd;
1134
1135 cmd = inchar();
1136 if (cmd == 'r')
1137 ppc_md.restart(NULL);
1138 else if (cmd == 'h')
1139 ppc_md.halt();
1140 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001141 if (pm_power_off)
1142 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143}
1144
1145static int cpu_cmd(void)
1146{
1147#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001148 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
1151 if (!scanhex(&cpu)) {
1152 /* print cpus waiting or in xmon */
1153 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001154 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001155 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001156 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001157 if (cpu == last_cpu + 1) {
1158 last_cpu = cpu;
1159 } else {
1160 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001161 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001162 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001163 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 }
1166 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001167 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001168 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 printf("\n");
1170 return 0;
1171 }
1172 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001173 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001174 printf("cpu 0x%lx isn't in xmon\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 return 0;
1176 }
1177 xmon_taken = 0;
1178 mb();
1179 xmon_owner = cpu;
1180 timeout = 10000000;
1181 while (!xmon_taken) {
1182 if (--timeout == 0) {
1183 if (test_and_set_bit(0, &xmon_taken))
1184 break;
1185 /* take control back */
1186 mb();
1187 xmon_owner = smp_processor_id();
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001188 printf("cpu 0x%lx didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 return 0;
1190 }
1191 barrier();
1192 }
1193 return 1;
1194#else
1195 return 0;
1196#endif /* CONFIG_SMP */
1197}
1198
1199static unsigned short fcstab[256] = {
1200 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1201 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1202 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1203 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1204 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1205 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1206 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1207 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1208 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1209 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1210 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1211 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1212 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1213 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1214 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1215 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1216 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1217 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1218 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1219 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1220 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1221 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1222 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1223 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1224 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1225 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1226 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1227 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1228 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1229 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1230 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1231 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1232};
1233
1234#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1235
1236static void
1237csum(void)
1238{
1239 unsigned int i;
1240 unsigned short fcs;
1241 unsigned char v;
1242
1243 if (!scanhex(&adrs))
1244 return;
1245 if (!scanhex(&ncsum))
1246 return;
1247 fcs = 0xffff;
1248 for (i = 0; i < ncsum; ++i) {
1249 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001250 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 break;
1252 }
1253 fcs = FCS(fcs, v);
1254 }
1255 printf("%x\n", fcs);
1256}
1257
1258/*
1259 * Check if this is a suitable place to put a breakpoint.
1260 */
1261static long check_bp_loc(unsigned long addr)
1262{
1263 unsigned int instr;
1264
1265 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001266 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 printf("Breakpoints may only be placed at kernel addresses\n");
1268 return 0;
1269 }
1270 if (!mread(addr, &instr, sizeof(instr))) {
1271 printf("Can't read instruction at address %lx\n", addr);
1272 return 0;
1273 }
1274 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1275 printf("Breakpoints may not be placed on mtmsrd or rfid "
1276 "instructions\n");
1277 return 0;
1278 }
1279 return 1;
1280}
1281
Michael Ellermane3bc8042012-08-23 22:09:13 +00001282static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 "Breakpoint command usage:\n"
1284 "b show breakpoints\n"
1285 "b <addr> [cnt] set breakpoint at given instr addr\n"
1286 "bc clear all breakpoints\n"
1287 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301288 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 "bd <addr> [cnt] set hardware data breakpoint\n"
1290 "";
1291
1292static void
1293bpt_cmds(void)
1294{
1295 int cmd;
1296 unsigned long a;
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001297 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 struct bpt *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
1300 cmd = inchar();
1301 switch (cmd) {
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001302#ifndef CONFIG_PPC_8xx
1303 static const char badaddr[] = "Only kernel addresses are permitted for breakpoints\n";
1304 int mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 case 'd': /* bd - hardware data breakpoint */
Michael Neuling9bc2bd52018-03-27 15:37:19 +11001306 if (!ppc_breakpoint_available()) {
1307 printf("Hardware data breakpoint not supported on this cpu\n");
1308 break;
1309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 mode = 7;
1311 cmd = inchar();
1312 if (cmd == 'r')
1313 mode = 5;
1314 else if (cmd == 'w')
1315 mode = 6;
1316 else
1317 termch = cmd;
1318 dabr.address = 0;
1319 dabr.enabled = 0;
1320 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001321 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 printf(badaddr);
1323 break;
1324 }
Michael Neuling9422de32012-12-20 14:06:44 +00001325 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 dabr.enabled = mode | BP_DABR;
1327 }
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301328
1329 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 break;
1331
1332 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301333 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 printf("Hardware instruction breakpoint "
1335 "not supported on this cpu\n");
1336 break;
1337 }
1338 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001339 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 iabr = NULL;
1341 }
1342 if (!scanhex(&a))
1343 break;
1344 if (!check_bp_loc(a))
1345 break;
1346 bp = new_breakpoint(a);
1347 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001348 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 iabr = bp;
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301350 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 }
1352 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001353#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
1355 case 'c':
1356 if (!scanhex(&a)) {
1357 /* clear all breakpoints */
1358 for (i = 0; i < NBPTS; ++i)
1359 bpts[i].enabled = 0;
1360 iabr = NULL;
1361 dabr.enabled = 0;
1362 printf("All breakpoints cleared\n");
1363 break;
1364 }
1365
1366 if (a <= NBPTS && a >= 1) {
1367 /* assume a breakpoint number */
1368 bp = &bpts[a-1]; /* bp nums are 1 based */
1369 } else {
1370 /* assume a breakpoint address */
1371 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001372 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001373 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 break;
1375 }
1376 }
1377
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001378 printf("Cleared breakpoint %tx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 xmon_print_symbol(bp->address, " ", ")\n");
1380 bp->enabled = 0;
1381 break;
1382
1383 default:
1384 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001385 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 if (cmd == '?') {
1387 printf(breakpoint_help_string);
1388 break;
1389 }
1390 termch = cmd;
1391 if (!scanhex(&a)) {
1392 /* print all breakpoints */
1393 printf(" type address\n");
1394 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001395 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 if (dabr.enabled & 1)
1397 printf("r");
1398 if (dabr.enabled & 2)
1399 printf("w");
1400 printf("]\n");
1401 }
1402 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1403 if (!bp->enabled)
1404 continue;
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001405 printf("%tx %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001406 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 xmon_print_symbol(bp->address, " ", "\n");
1408 }
1409 break;
1410 }
1411
1412 if (!check_bp_loc(a))
1413 break;
1414 bp = new_breakpoint(a);
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301415 if (bp != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 bp->enabled |= BP_TRAP;
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301417 force_enable_xmon();
1418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 break;
1420 }
1421}
1422
1423/* Very cheap human name for vector lookup. */
1424static
1425const char *getvecname(unsigned long vec)
1426{
1427 char *ret;
1428
1429 switch (vec) {
1430 case 0x100: ret = "(System Reset)"; break;
1431 case 0x200: ret = "(Machine Check)"; break;
1432 case 0x300: ret = "(Data Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001433 case 0x380:
1434 if (radix_enabled())
1435 ret = "(Data Access Out of Range)";
1436 else
1437 ret = "(Data SLB Access)";
1438 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 case 0x400: ret = "(Instruction Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001440 case 0x480:
1441 if (radix_enabled())
1442 ret = "(Instruction Access Out of Range)";
1443 else
1444 ret = "(Instruction SLB Access)";
1445 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 case 0x500: ret = "(Hardware Interrupt)"; break;
1447 case 0x600: ret = "(Alignment)"; break;
1448 case 0x700: ret = "(Program Check)"; break;
1449 case 0x800: ret = "(FPU Unavailable)"; break;
1450 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001451 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1452 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 case 0xc00: ret = "(System Call)"; break;
1454 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001455 case 0xe40: ret = "(Emulation Assist)"; break;
1456 case 0xe60: ret = "(HMI)"; break;
1457 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 case 0xf00: ret = "(Performance Monitor)"; break;
1459 case 0xf20: ret = "(Altivec Unavailable)"; break;
1460 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001461 case 0x1500: ret = "(Denormalisation)"; break;
1462 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 default: ret = "";
1464 }
1465 return ret;
1466}
1467
1468static void get_function_bounds(unsigned long pc, unsigned long *startp,
1469 unsigned long *endp)
1470{
1471 unsigned long size, offset;
1472 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473
1474 *startp = *endp = 0;
1475 if (pc == 0)
1476 return;
1477 if (setjmp(bus_error_jmp) == 0) {
1478 catch_memory_errors = 1;
1479 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001480 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 if (name != NULL) {
1482 *startp = pc - offset;
1483 *endp = pc - offset + size;
1484 }
1485 sync();
1486 }
1487 catch_memory_errors = 0;
1488}
1489
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001490#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1491#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1492
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493static void xmon_show_stack(unsigned long sp, unsigned long lr,
1494 unsigned long pc)
1495{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001496 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 unsigned long ip;
1498 unsigned long newsp;
1499 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 struct pt_regs regs;
1501
Michael Ellerman0104cd62012-10-09 04:20:36 +00001502 while (max_to_print--) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301503 if (!is_kernel_addr(sp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 if (sp != 0)
1505 printf("SP (%lx) is in userspace\n", sp);
1506 break;
1507 }
1508
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001509 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 || !mread(sp, &newsp, sizeof(unsigned long))) {
1511 printf("Couldn't read stack frame at %lx\n", sp);
1512 break;
1513 }
1514
1515 /*
1516 * For the first stack frame, try to work out if
1517 * LR and/or the saved LR value in the bottommost
1518 * stack frame are valid.
1519 */
1520 if ((pc | lr) != 0) {
1521 unsigned long fnstart, fnend;
1522 unsigned long nextip;
1523 int printip = 1;
1524
1525 get_function_bounds(pc, &fnstart, &fnend);
1526 nextip = 0;
1527 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001528 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 sizeof(unsigned long));
1530 if (lr == ip) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301531 if (!is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 || (fnstart <= lr && lr < fnend))
1533 printip = 0;
1534 } else if (lr == nextip) {
1535 printip = 0;
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301536 } else if (is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 && !(fnstart <= lr && lr < fnend)) {
1538 printf("[link register ] ");
1539 xmon_print_symbol(lr, " ", "\n");
1540 }
1541 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001542 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 xmon_print_symbol(ip, " ", " (unreliable)\n");
1544 }
1545 pc = lr = 0;
1546
1547 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001548 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 xmon_print_symbol(ip, " ", "\n");
1550 }
1551
1552 /* Look for "regshere" marker to see if this is
1553 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001554 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001555 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001556 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 != sizeof(regs)) {
1558 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001559 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 break;
1561 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001562 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 getvecname(TRAP(&regs)));
1564 pc = regs.nip;
1565 lr = regs.link;
1566 xmon_print_symbol(pc, " ", "\n");
1567 }
1568
1569 if (newsp == 0)
1570 break;
1571
1572 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574}
1575
1576static void backtrace(struct pt_regs *excp)
1577{
1578 unsigned long sp;
1579
1580 if (scanhex(&sp))
1581 xmon_show_stack(sp, 0, 0);
1582 else
1583 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1584 scannl();
1585}
1586
1587static void print_bug_trap(struct pt_regs *regs)
1588{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001589#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001590 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 unsigned long addr;
1592
1593 if (regs->msr & MSR_PR)
1594 return; /* not in kernel */
1595 addr = regs->nip; /* address of trap instruction */
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301596 if (!is_kernel_addr(addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 return;
1598 bug = find_bug(regs->nip);
1599 if (bug == NULL)
1600 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001601 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 return;
1603
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001604#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001605 printf("kernel BUG at %s:%u!\n",
1606 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001607#else
Michael Ellermand8104182017-12-06 23:23:28 +11001608 printf("kernel BUG at %px!\n", (void *)bug->bug_addr);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001609#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001610#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611}
1612
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001613static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614{
1615 unsigned long trap;
1616
1617#ifdef CONFIG_SMP
1618 printf("cpu 0x%x: ", smp_processor_id());
1619#endif /* CONFIG_SMP */
1620
1621 trap = TRAP(fp);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001622 printf("Vector: %lx %s at [%px]\n", fp->trap, getvecname(trap), fp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 printf(" pc: ");
1624 xmon_print_symbol(fp->nip, ": ", "\n");
1625
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001626 printf(" lr: ");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 xmon_print_symbol(fp->link, ": ", "\n");
1628
1629 printf(" sp: %lx\n", fp->gpr[1]);
1630 printf(" msr: %lx\n", fp->msr);
1631
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001632 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 printf(" dar: %lx\n", fp->dar);
1634 if (trap != 0x380)
1635 printf(" dsisr: %lx\n", fp->dsisr);
1636 }
1637
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001638 printf(" current = 0x%px\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001639#ifdef CONFIG_PPC64
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001640 printf(" paca = 0x%px\t softe: %d\t irq_happened: 0x%02x\n",
Madhavan Srinivasan4e26bc42017-12-20 09:25:50 +05301641 local_paca, local_paca->irq_soft_mask, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001642#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 if (current) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001644 printf(" pid = %d, comm = %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 current->pid, current->comm);
1646 }
1647
1648 if (trap == 0x700)
1649 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001650
1651 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652}
1653
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001654static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001656 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 unsigned long base;
1658 struct pt_regs regs;
1659
1660 if (scanhex(&base)) {
1661 if (setjmp(bus_error_jmp) == 0) {
1662 catch_memory_errors = 1;
1663 sync();
1664 regs = *(struct pt_regs *)base;
1665 sync();
1666 __delay(200);
1667 } else {
1668 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001669 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 base);
1671 return;
1672 }
1673 catch_memory_errors = 0;
1674 fp = &regs;
1675 }
1676
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001677#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 if (FULL_REGS(fp)) {
1679 for (n = 0; n < 16; ++n)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001680 printf("R%.2d = "REG" R%.2d = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1682 } else {
1683 for (n = 0; n < 7; ++n)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001684 printf("R%.2d = "REG" R%.2d = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1686 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001687#else
1688 for (n = 0; n < 32; ++n) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001689 printf("R%.2d = %.8lx%s", n, fp->gpr[n],
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001690 (n & 3) == 3? "\n": " ");
1691 if (n == 12 && !FULL_REGS(fp)) {
1692 printf("\n");
1693 break;
1694 }
1695 }
1696#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 printf("pc = ");
1698 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001699 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1700 printf("cfar= ");
1701 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1702 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 printf("lr = ");
1704 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001705 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1706 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001708 trap = TRAP(fp);
1709 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1710 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711}
1712
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001713static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714{
1715 int cmd;
1716 unsigned long nflush;
1717
1718 cmd = inchar();
1719 if (cmd != 'i')
1720 termch = cmd;
1721 scanhex((void *)&adrs);
1722 if (termch != '\n')
1723 termch = 0;
1724 nflush = 1;
1725 scanhex(&nflush);
1726 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1727 if (setjmp(bus_error_jmp) == 0) {
1728 catch_memory_errors = 1;
1729 sync();
1730
1731 if (cmd != 'i') {
1732 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1733 cflush((void *) adrs);
1734 } else {
1735 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1736 cinval((void *) adrs);
1737 }
1738 sync();
1739 /* wait a little while to see if we get a machine check */
1740 __delay(200);
1741 }
1742 catch_memory_errors = 0;
1743}
1744
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001745extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1746extern void xmon_mtspr(int spr, unsigned long value);
1747
1748static int
1749read_spr(int n, unsigned long *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 unsigned long ret = -1UL;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001752 int ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
1754 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001755 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 sync();
1757
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001758 ret = xmon_mfspr(n, *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
1760 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001761 *vp = ret;
1762 ok = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001764 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001766 return ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767}
1768
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001769static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770write_spr(int n, unsigned long val)
1771{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001773 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 sync();
1775
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001776 xmon_mtspr(n, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
1778 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001779 } else {
1780 printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001782 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783}
1784
Michael Ellerman18461932016-07-07 22:54:29 +10001785static void dump_206_sprs(void)
1786{
1787#ifdef CONFIG_PPC64
1788 if (!cpu_has_feature(CPU_FTR_ARCH_206))
1789 return;
1790
1791 /* Actually some of these pre-date 2.06, but whatevs */
1792
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001793 printf("srr0 = %.16lx srr1 = %.16lx dsisr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001794 mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001795 printf("dscr = %.16lx ppr = %.16lx pir = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001796 mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001797 printf("amr = %.16lx uamor = %.16lx\n",
1798 mfspr(SPRN_AMR), mfspr(SPRN_UAMOR));
Michael Ellerman18461932016-07-07 22:54:29 +10001799
1800 if (!(mfmsr() & MSR_HV))
1801 return;
1802
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001803 printf("sdr1 = %.16lx hdar = %.16lx hdsisr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001804 mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001805 printf("hsrr0 = %.16lx hsrr1 = %.16lx hdec = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001806 mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001807 printf("lpcr = %.16lx pcr = %.16lx lpidr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001808 mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001809 printf("hsprg0 = %.16lx hsprg1 = %.16lx amor = %.16lx\n",
1810 mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1), mfspr(SPRN_AMOR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001811 printf("dabr = %.16lx dabrx = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001812 mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
1813#endif
1814}
1815
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001816static void dump_207_sprs(void)
1817{
1818#ifdef CONFIG_PPC64
1819 unsigned long msr;
1820
1821 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
1822 return;
1823
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001824 printf("dpdes = %.16lx tir = %.16lx cir = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001825 mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
1826
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001827 printf("fscr = %.16lx tar = %.16lx pspb = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001828 mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
1829
1830 msr = mfmsr();
1831 if (msr & MSR_TM) {
1832 /* Only if TM has been enabled in the kernel */
Balbir Singhc47a9402017-08-29 17:22:36 +10001833 printf("tfhar = %.16lx tfiar = %.16lx texasr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001834 mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
1835 mfspr(SPRN_TEXASR));
1836 }
1837
Balbir Singhc47a9402017-08-29 17:22:36 +10001838 printf("mmcr0 = %.16lx mmcr1 = %.16lx mmcr2 = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001839 mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001840 printf("pmc1 = %.8lx pmc2 = %.8lx pmc3 = %.8lx pmc4 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001841 mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
1842 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001843 printf("mmcra = %.16lx siar = %.16lx pmc5 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001844 mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001845 printf("sdar = %.16lx sier = %.16lx pmc6 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001846 mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
Balbir Singhc47a9402017-08-29 17:22:36 +10001847 printf("ebbhr = %.16lx ebbrr = %.16lx bescr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001848 mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001849 printf("iamr = %.16lx\n", mfspr(SPRN_IAMR));
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001850
1851 if (!(msr & MSR_HV))
1852 return;
1853
Balbir Singhc47a9402017-08-29 17:22:36 +10001854 printf("hfscr = %.16lx dhdes = %.16lx rpr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001855 mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001856 printf("dawr = %.16lx dawrx = %.16lx ciabr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001857 mfspr(SPRN_DAWR), mfspr(SPRN_DAWRX), mfspr(SPRN_CIABR));
1858#endif
1859}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
Balbir Singhd1e1b352017-08-30 21:45:09 +10001861static void dump_300_sprs(void)
1862{
1863#ifdef CONFIG_PPC64
1864 bool hv = mfmsr() & MSR_HV;
1865
1866 if (!cpu_has_feature(CPU_FTR_ARCH_300))
1867 return;
1868
1869 printf("pidr = %.16lx tidr = %.16lx\n",
1870 mfspr(SPRN_PID), mfspr(SPRN_TIDR));
1871 printf("asdr = %.16lx psscr = %.16lx\n",
1872 mfspr(SPRN_ASDR), hv ? mfspr(SPRN_PSSCR)
1873 : mfspr(SPRN_PSSCR_PR));
1874
1875 if (!hv)
1876 return;
1877
1878 printf("ptcr = %.16lx\n",
1879 mfspr(SPRN_PTCR));
1880#endif
1881}
1882
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001883static void dump_one_spr(int spr, bool show_unimplemented)
1884{
1885 unsigned long val;
1886
1887 val = 0xdeadbeef;
1888 if (!read_spr(spr, &val)) {
1889 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1890 return;
1891 }
1892
1893 if (val == 0xdeadbeef) {
1894 /* Looks like read was a nop, confirm */
1895 val = 0x0badcafe;
1896 if (!read_spr(spr, &val)) {
1897 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1898 return;
1899 }
1900
1901 if (val == 0x0badcafe) {
1902 if (show_unimplemented)
1903 printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
1904 return;
1905 }
1906 }
1907
1908 printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
1909}
1910
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001911static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912{
Michael Ellerman13629da2016-07-07 22:54:27 +10001913 static unsigned long regno;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 int cmd;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001915 int spr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916
1917 cmd = skipbl();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001918
1919 switch (cmd) {
1920 case '\n': {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001921 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 asm("mr %0,1" : "=r" (sp) :);
1923 asm("mr %0,2" : "=r" (toc) :);
1924
Michael Ellerman56346ad2016-07-07 22:54:28 +10001925 printf("msr = "REG" sprg0 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001926 mfmsr(), mfspr(SPRN_SPRG0));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001927 printf("pvr = "REG" sprg1 = "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001928 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001929 printf("dec = "REG" sprg2 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001930 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001931 printf("sp = "REG" sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
1932 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
1933
Michael Ellerman18461932016-07-07 22:54:29 +10001934 dump_206_sprs();
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001935 dump_207_sprs();
Balbir Singhd1e1b352017-08-30 21:45:09 +10001936 dump_300_sprs();
Michael Ellerman18461932016-07-07 22:54:29 +10001937
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 return;
1939 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001940 case 'w': {
1941 unsigned long val;
1942 scanhex(&regno);
1943 val = 0;
1944 read_spr(regno, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 scanhex(&val);
1946 write_spr(regno, val);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001947 dump_one_spr(regno, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001950 case 'r':
1951 scanhex(&regno);
1952 dump_one_spr(regno, true);
1953 break;
1954 case 'a':
1955 /* dump ALL SPRs */
1956 for (spr = 1; spr < 1024; ++spr)
1957 dump_one_spr(spr, false);
1958 break;
1959 }
1960
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 scannl();
1962}
1963
1964/*
1965 * Stuff for reading and writing memory safely
1966 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001967static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968mread(unsigned long adrs, void *buf, int size)
1969{
1970 volatile int n;
1971 char *p, *q;
1972
1973 n = 0;
1974 if (setjmp(bus_error_jmp) == 0) {
1975 catch_memory_errors = 1;
1976 sync();
1977 p = (char *)adrs;
1978 q = (char *)buf;
1979 switch (size) {
1980 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001981 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 break;
1983 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001984 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 break;
1986 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001987 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 break;
1989 default:
1990 for( ; n < size; ++n) {
1991 *q++ = *p++;
1992 sync();
1993 }
1994 }
1995 sync();
1996 /* wait a little while to see if we get a machine check */
1997 __delay(200);
1998 n = size;
1999 }
2000 catch_memory_errors = 0;
2001 return n;
2002}
2003
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002004static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005mwrite(unsigned long adrs, void *buf, int size)
2006{
2007 volatile int n;
2008 char *p, *q;
2009
2010 n = 0;
2011 if (setjmp(bus_error_jmp) == 0) {
2012 catch_memory_errors = 1;
2013 sync();
2014 p = (char *) adrs;
2015 q = (char *) buf;
2016 switch (size) {
2017 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002018 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 break;
2020 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002021 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 break;
2023 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002024 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 break;
2026 default:
2027 for ( ; n < size; ++n) {
2028 *p++ = *q++;
2029 sync();
2030 }
2031 }
2032 sync();
2033 /* wait a little while to see if we get a machine check */
2034 __delay(200);
2035 n = size;
2036 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10002037 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 }
2039 catch_memory_errors = 0;
2040 return n;
2041}
2042
2043static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002044static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045static char *fault_chars[] = { "--", "**", "##" };
2046
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002047static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002049 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 switch (TRAP(regs)) {
2051 case 0x200:
2052 fault_type = 0;
2053 break;
2054 case 0x300:
2055 case 0x380:
2056 fault_type = 1;
2057 break;
2058 default:
2059 fault_type = 2;
2060 }
2061
2062 longjmp(bus_error_jmp, 1);
2063
2064 return 0;
2065}
2066
2067#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
2068
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002069static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070byterev(unsigned char *val, int size)
2071{
2072 int t;
2073
2074 switch (size) {
2075 case 2:
2076 SWAP(val[0], val[1], t);
2077 break;
2078 case 4:
2079 SWAP(val[0], val[3], t);
2080 SWAP(val[1], val[2], t);
2081 break;
2082 case 8: /* is there really any use for this? */
2083 SWAP(val[0], val[7], t);
2084 SWAP(val[1], val[6], t);
2085 SWAP(val[2], val[5], t);
2086 SWAP(val[3], val[4], t);
2087 break;
2088 }
2089}
2090
2091static int brev;
2092static int mnoread;
2093
Michael Ellermane3bc8042012-08-23 22:09:13 +00002094static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 "Memory examine command usage:\n"
2096 "m [addr] [flags] examine/change memory\n"
2097 " addr is optional. will start where left off.\n"
2098 " flags may include chars from this set:\n"
2099 " b modify by bytes (default)\n"
2100 " w modify by words (2 byte)\n"
2101 " l modify by longs (4 byte)\n"
2102 " d modify by doubleword (8 byte)\n"
2103 " r toggle reverse byte order mode\n"
2104 " n do not read memory (for i/o spaces)\n"
2105 " . ok to read (default)\n"
2106 "NOTE: flags are saved as defaults\n"
2107 "";
2108
Michael Ellermane3bc8042012-08-23 22:09:13 +00002109static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 "Memory examine subcommands:\n"
2111 " hexval write this val to current location\n"
2112 " 'string' write chars from string to this location\n"
2113 " ' increment address\n"
2114 " ^ decrement address\n"
2115 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
2116 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
2117 " ` clear no-read flag\n"
2118 " ; stay at this addr\n"
2119 " v change to byte mode\n"
2120 " w change to word (2 byte) mode\n"
2121 " l change to long (4 byte) mode\n"
2122 " u change to doubleword (8 byte) mode\n"
2123 " m addr change current addr\n"
2124 " n toggle no-read flag\n"
2125 " r toggle byte reverse flag\n"
2126 " < count back up count bytes\n"
2127 " > count skip forward count bytes\n"
2128 " x exit this mode\n"
2129 "";
2130
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002131static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132memex(void)
2133{
2134 int cmd, inc, i, nslash;
2135 unsigned long n;
2136 unsigned char val[16];
2137
2138 scanhex((void *)&adrs);
2139 cmd = skipbl();
2140 if (cmd == '?') {
2141 printf(memex_help_string);
2142 return;
2143 } else {
2144 termch = cmd;
2145 }
2146 last_cmd = "m\n";
2147 while ((cmd = skipbl()) != '\n') {
2148 switch( cmd ){
2149 case 'b': size = 1; break;
2150 case 'w': size = 2; break;
2151 case 'l': size = 4; break;
2152 case 'd': size = 8; break;
2153 case 'r': brev = !brev; break;
2154 case 'n': mnoread = 1; break;
2155 case '.': mnoread = 0; break;
2156 }
2157 }
2158 if( size <= 0 )
2159 size = 1;
2160 else if( size > 8 )
2161 size = 8;
2162 for(;;){
2163 if (!mnoread)
2164 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002165 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 if (!mnoread) {
2167 if (brev)
2168 byterev(val, size);
2169 putchar(' ');
2170 for (i = 0; i < n; ++i)
2171 printf("%.2x", val[i]);
2172 for (; i < size; ++i)
2173 printf("%s", fault_chars[fault_type]);
2174 }
2175 putchar(' ');
2176 inc = size;
2177 nslash = 0;
2178 for(;;){
2179 if( scanhex(&n) ){
2180 for (i = 0; i < size; ++i)
2181 val[i] = n >> (i * 8);
2182 if (!brev)
2183 byterev(val, size);
2184 mwrite(adrs, val, size);
2185 inc = size;
2186 }
2187 cmd = skipbl();
2188 if (cmd == '\n')
2189 break;
2190 inc = 0;
2191 switch (cmd) {
2192 case '\'':
2193 for(;;){
2194 n = inchar();
2195 if( n == '\\' )
2196 n = bsesc();
2197 else if( n == '\'' )
2198 break;
2199 for (i = 0; i < size; ++i)
2200 val[i] = n >> (i * 8);
2201 if (!brev)
2202 byterev(val, size);
2203 mwrite(adrs, val, size);
2204 adrs += size;
2205 }
2206 adrs -= size;
2207 inc = size;
2208 break;
2209 case ',':
2210 adrs += size;
2211 break;
2212 case '.':
2213 mnoread = 0;
2214 break;
2215 case ';':
2216 break;
2217 case 'x':
2218 case EOF:
2219 scannl();
2220 return;
2221 case 'b':
2222 case 'v':
2223 size = 1;
2224 break;
2225 case 'w':
2226 size = 2;
2227 break;
2228 case 'l':
2229 size = 4;
2230 break;
2231 case 'u':
2232 size = 8;
2233 break;
2234 case '^':
2235 adrs -= size;
2236 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 case '/':
2238 if (nslash > 0)
2239 adrs -= 1 << nslash;
2240 else
2241 nslash = 0;
2242 nslash += 4;
2243 adrs += 1 << nslash;
2244 break;
2245 case '\\':
2246 if (nslash < 0)
2247 adrs += 1 << -nslash;
2248 else
2249 nslash = 0;
2250 nslash -= 4;
2251 adrs -= 1 << -nslash;
2252 break;
2253 case 'm':
2254 scanhex((void *)&adrs);
2255 break;
2256 case 'n':
2257 mnoread = 1;
2258 break;
2259 case 'r':
2260 brev = !brev;
2261 break;
2262 case '<':
2263 n = size;
2264 scanhex(&n);
2265 adrs -= n;
2266 break;
2267 case '>':
2268 n = size;
2269 scanhex(&n);
2270 adrs += n;
2271 break;
2272 case '?':
2273 printf(memex_subcmd_help_string);
2274 break;
2275 }
2276 }
2277 adrs += inc;
2278 }
2279}
2280
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002281static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282bsesc(void)
2283{
2284 int c;
2285
2286 c = inchar();
2287 switch( c ){
2288 case 'n': c = '\n'; break;
2289 case 'r': c = '\r'; break;
2290 case 'b': c = '\b'; break;
2291 case 't': c = '\t'; break;
2292 }
2293 return c;
2294}
2295
Olaf Hering7e5b5932006-03-08 20:40:28 +01002296static void xmon_rawdump (unsigned long adrs, long ndump)
2297{
2298 long n, m, r, nr;
2299 unsigned char temp[16];
2300
2301 for (n = ndump; n > 0;) {
2302 r = n < 16? n: 16;
2303 nr = mread(adrs, temp, r);
2304 adrs += nr;
2305 for (m = 0; m < r; ++m) {
2306 if (m < nr)
2307 printf("%.2x", temp[m]);
2308 else
2309 printf("%s", fault_chars[fault_type]);
2310 }
2311 n -= r;
2312 if (nr < r)
2313 break;
2314 }
2315 printf("\n");
2316}
2317
Breno Leitao4125d012017-08-02 17:14:05 -03002318static void dump_tracing(void)
2319{
2320 int c;
2321
2322 c = inchar();
2323 if (c == 'c')
2324 ftrace_dump(DUMP_ORIG);
2325 else
2326 ftrace_dump(DUMP_ALL);
Breno Leitao4125d012017-08-02 17:14:05 -03002327}
2328
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002329#ifdef CONFIG_PPC64
2330static void dump_one_paca(int cpu)
2331{
2332 struct paca_struct *p;
Michael Ellerman4e003742017-10-19 15:08:43 +11002333#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellermanad987fc2015-10-14 16:58:36 +11002334 int i = 0;
2335#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002336
2337 if (setjmp(bus_error_jmp) != 0) {
2338 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2339 return;
2340 }
2341
2342 catch_memory_errors = 1;
2343 sync();
2344
Nicholas Piggind2e60072018-02-14 01:08:12 +10002345 p = paca_ptrs[cpu];
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002346
Michael Ellermand8104182017-12-06 23:23:28 +11002347 printf("paca for cpu 0x%x @ %px:\n", cpu, p);
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002348
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002349 printf(" %-*s = %s\n", 25, "possible", cpu_possible(cpu) ? "yes" : "no");
2350 printf(" %-*s = %s\n", 25, "present", cpu_present(cpu) ? "yes" : "no");
2351 printf(" %-*s = %s\n", 25, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002352
Michael Ellerman66716832018-05-21 21:06:19 +10002353#define DUMP(paca, name, format) \
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002354 printf(" %-*s = "format"\t(0x%lx)\n", 25, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002355 offsetof(struct paca_struct, name));
2356
Michael Ellerman66716832018-05-21 21:06:19 +10002357 DUMP(p, lock_token, "%#-*x");
2358 DUMP(p, paca_index, "%#-*x");
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002359 DUMP(p, kernel_toc, "%#-*llx");
2360 DUMP(p, kernelbase, "%#-*llx");
2361 DUMP(p, kernel_msr, "%#-*llx");
Michael Ellerman66716832018-05-21 21:06:19 +10002362 DUMP(p, emergency_sp, "%-*px");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302363#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman66716832018-05-21 21:06:19 +10002364 DUMP(p, nmi_emergency_sp, "%-*px");
2365 DUMP(p, mc_emergency_sp, "%-*px");
2366 DUMP(p, in_nmi, "%#-*x");
2367 DUMP(p, in_mce, "%#-*x");
2368 DUMP(p, hmi_event_available, "%#-*x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302369#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002370 DUMP(p, data_offset, "%#-*llx");
Michael Ellerman66716832018-05-21 21:06:19 +10002371 DUMP(p, hw_cpu_id, "%#-*x");
2372 DUMP(p, cpu_start, "%#-*x");
2373 DUMP(p, kexec_state, "%#-*x");
Michael Ellerman4e003742017-10-19 15:08:43 +11002374#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellermanad987fc2015-10-14 16:58:36 +11002375 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2376 u64 esid, vsid;
2377
2378 if (!p->slb_shadow_ptr)
2379 continue;
2380
2381 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2382 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
2383
2384 if (esid || vsid) {
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002385 printf(" %-*s[%d] = 0x%016llx 0x%016llx\n",
2386 22, "slb_shadow", i, esid, vsid);
Michael Ellermanad987fc2015-10-14 16:58:36 +11002387 }
2388 }
Michael Ellerman66716832018-05-21 21:06:19 +10002389 DUMP(p, vmalloc_sllp, "%#-*x");
2390 DUMP(p, slb_cache_ptr, "%#-*x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002391 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002392 printf(" %-*s[%d] = 0x%016x\n",
2393 22, "slb_cache", i, p->slb_cache[i]);
Michael Ellerman274920a2018-01-10 23:49:12 +11002394
Michael Ellerman66716832018-05-21 21:06:19 +10002395 DUMP(p, rfi_flush_fallback_area, "%-*px");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002396#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002397 DUMP(p, dscr_default, "%#-*llx");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002398#ifdef CONFIG_PPC_BOOK3E
Michael Ellerman66716832018-05-21 21:06:19 +10002399 DUMP(p, pgd, "%-*px");
2400 DUMP(p, kernel_pgd, "%-*px");
2401 DUMP(p, tcd_ptr, "%-*px");
2402 DUMP(p, mc_kstack, "%-*px");
2403 DUMP(p, crit_kstack, "%-*px");
2404 DUMP(p, dbg_kstack, "%-*px");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002405#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002406 DUMP(p, __current, "%-*px");
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002407 DUMP(p, kstack, "%#-*llx");
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002408 printf(" %-*s = 0x%016llx\n", 25, "kstack_base", p->kstack & ~(THREAD_SIZE - 1));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002409 DUMP(p, stab_rr, "%#-*llx");
2410 DUMP(p, saved_r1, "%#-*llx");
Michael Ellerman66716832018-05-21 21:06:19 +10002411 DUMP(p, trap_save, "%#-*x");
2412 DUMP(p, irq_soft_mask, "%#-*x");
2413 DUMP(p, irq_happened, "%#-*x");
2414 DUMP(p, io_sync, "%#-*x");
2415 DUMP(p, irq_work_pending, "%#-*x");
2416 DUMP(p, nap_state_lost, "%#-*x");
2417 DUMP(p, sprg_vdso, "%#-*llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002418
Michael Ellermanad987fc2015-10-14 16:58:36 +11002419#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
Michael Ellerman66716832018-05-21 21:06:19 +10002420 DUMP(p, tm_scratch, "%#-*llx");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002421#endif
2422
2423#ifdef CONFIG_PPC_POWERNV
Michael Ellerman66716832018-05-21 21:06:19 +10002424 DUMP(p, core_idle_state_ptr, "%-*px");
2425 DUMP(p, thread_idle_state, "%#-*x");
2426 DUMP(p, thread_mask, "%#-*x");
2427 DUMP(p, subcore_sibling_mask, "%#-*x");
Michael Ellerman2e0986d2018-05-21 19:47:20 +10002428 DUMP(p, thread_sibling_pacas, "%-*px");
2429 DUMP(p, requested_psscr, "%#-*llx");
2430 DUMP(p, stop_sprs.pid, "%#-*llx");
2431 DUMP(p, stop_sprs.ldbar, "%#-*llx");
2432 DUMP(p, stop_sprs.fscr, "%#-*llx");
2433 DUMP(p, stop_sprs.hfscr, "%#-*llx");
2434 DUMP(p, stop_sprs.mmcr1, "%#-*llx");
2435 DUMP(p, stop_sprs.mmcr2, "%#-*llx");
2436 DUMP(p, stop_sprs.mmcra, "%#-*llx");
2437 DUMP(p, dont_stop.counter, "%#-*x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002438#endif
2439
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002440 DUMP(p, accounting.utime, "%#-*lx");
2441 DUMP(p, accounting.stime, "%#-*lx");
2442 DUMP(p, accounting.utime_scaled, "%#-*lx");
2443 DUMP(p, accounting.starttime, "%#-*lx");
2444 DUMP(p, accounting.starttime_user, "%#-*lx");
2445 DUMP(p, accounting.startspurr, "%#-*lx");
2446 DUMP(p, accounting.utime_sspurr, "%#-*lx");
2447 DUMP(p, accounting.steal_time, "%#-*lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002448#undef DUMP
2449
2450 catch_memory_errors = 0;
2451 sync();
2452}
2453
2454static void dump_all_pacas(void)
2455{
2456 int cpu;
2457
2458 if (num_possible_cpus() == 0) {
2459 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2460 return;
2461 }
2462
2463 for_each_possible_cpu(cpu)
2464 dump_one_paca(cpu);
2465}
2466
2467static void dump_pacas(void)
2468{
2469 unsigned long num;
2470 int c;
2471
2472 c = inchar();
2473 if (c == 'a') {
2474 dump_all_pacas();
2475 return;
2476 }
2477
2478 termch = c; /* Put c back, it wasn't 'a' */
2479
2480 if (scanhex(&num))
2481 dump_one_paca(num);
2482 else
2483 dump_one_paca(xmon_owner);
2484}
2485#endif
2486
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002487#ifdef CONFIG_PPC_POWERNV
2488static void dump_one_xive(int cpu)
2489{
2490 unsigned int hwid = get_hard_smp_processor_id(cpu);
2491
2492 opal_xive_dump(XIVE_DUMP_TM_HYP, hwid);
2493 opal_xive_dump(XIVE_DUMP_TM_POOL, hwid);
2494 opal_xive_dump(XIVE_DUMP_TM_OS, hwid);
2495 opal_xive_dump(XIVE_DUMP_TM_USER, hwid);
2496 opal_xive_dump(XIVE_DUMP_VP, hwid);
2497 opal_xive_dump(XIVE_DUMP_EMU_STATE, hwid);
2498
2499 if (setjmp(bus_error_jmp) != 0) {
2500 catch_memory_errors = 0;
2501 printf("*** Error dumping xive on cpu %d\n", cpu);
2502 return;
2503 }
2504
2505 catch_memory_errors = 1;
2506 sync();
2507 xmon_xive_do_dump(cpu);
2508 sync();
2509 __delay(200);
2510 catch_memory_errors = 0;
2511}
2512
2513static void dump_all_xives(void)
2514{
2515 int cpu;
2516
2517 if (num_possible_cpus() == 0) {
2518 printf("No possible cpus, use 'dx #' to dump individual cpus\n");
2519 return;
2520 }
2521
2522 for_each_possible_cpu(cpu)
2523 dump_one_xive(cpu);
2524}
2525
2526static void dump_one_xive_irq(u32 num)
2527{
2528 s64 rc;
2529 __be64 vp;
2530 u8 prio;
2531 __be32 lirq;
2532
2533 rc = opal_xive_get_irq_config(num, &vp, &prio, &lirq);
2534 xmon_printf("IRQ 0x%x config: vp=0x%llx prio=%d lirq=0x%x (rc=%lld)\n",
2535 num, be64_to_cpu(vp), prio, be32_to_cpu(lirq), rc);
2536}
2537
2538static void dump_xives(void)
2539{
2540 unsigned long num;
2541 int c;
2542
Breno Leitao402e1722017-10-17 16:20:18 -02002543 if (!xive_enabled()) {
2544 printf("Xive disabled on this system\n");
2545 return;
2546 }
2547
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002548 c = inchar();
2549 if (c == 'a') {
2550 dump_all_xives();
2551 return;
2552 } else if (c == 'i') {
2553 if (scanhex(&num))
2554 dump_one_xive_irq(num);
2555 return;
2556 }
2557
2558 termch = c; /* Put c back, it wasn't 'a' */
2559
2560 if (scanhex(&num))
2561 dump_one_xive(num);
2562 else
2563 dump_one_xive(xmon_owner);
2564}
2565#endif /* CONFIG_PPC_POWERNV */
2566
Douglas Miller5e48dc02017-02-07 07:40:44 -06002567static void dump_by_size(unsigned long addr, long count, int size)
2568{
2569 unsigned char temp[16];
2570 int i, j;
2571 u64 val;
2572
2573 count = ALIGN(count, 16);
2574
2575 for (i = 0; i < count; i += 16, addr += 16) {
2576 printf(REG, addr);
2577
2578 if (mread(addr, temp, 16) != 16) {
2579 printf("\nFaulted reading %d bytes from 0x"REG"\n", 16, addr);
2580 return;
2581 }
2582
2583 for (j = 0; j < 16; j += size) {
2584 putchar(' ');
2585 switch (size) {
2586 case 1: val = temp[j]; break;
2587 case 2: val = *(u16 *)&temp[j]; break;
2588 case 4: val = *(u32 *)&temp[j]; break;
2589 case 8: val = *(u64 *)&temp[j]; break;
2590 default: val = 0;
2591 }
2592
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002593 printf("%0*llx", size * 2, val);
Douglas Miller5e48dc02017-02-07 07:40:44 -06002594 }
2595 printf("\n");
2596 }
2597}
2598
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002599static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600dump(void)
2601{
Douglas Miller5e48dc02017-02-07 07:40:44 -06002602 static char last[] = { "d?\n" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 int c;
2604
2605 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002606
2607#ifdef CONFIG_PPC64
2608 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002609 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002610 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002611 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002612 return;
2613 }
2614#endif
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002615#ifdef CONFIG_PPC_POWERNV
2616 if (c == 'x') {
2617 xmon_start_pagination();
2618 dump_xives();
2619 xmon_end_pagination();
2620 return;
2621 }
2622#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002623
Breno Leitao4125d012017-08-02 17:14:05 -03002624 if (c == 't') {
2625 dump_tracing();
2626 return;
2627 }
2628
Douglas Miller5e48dc02017-02-07 07:40:44 -06002629 if (c == '\n')
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 termch = c;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002631
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 scanhex((void *)&adrs);
2633 if (termch != '\n')
2634 termch = 0;
2635 if (c == 'i') {
2636 scanhex(&nidump);
2637 if (nidump == 0)
2638 nidump = 16;
2639 else if (nidump > MAX_DUMP)
2640 nidump = MAX_DUMP;
2641 adrs += ppc_inst_dump(adrs, nidump, 1);
2642 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002643 } else if (c == 'l') {
2644 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002645 } else if (c == 'o') {
2646 dump_opal_msglog();
Balbir Singh80eff6c2017-10-30 22:01:12 +11002647 } else if (c == 'v') {
2648 /* dump virtual to physical translation */
2649 show_pte(adrs);
Olaf Hering7e5b5932006-03-08 20:40:28 +01002650 } else if (c == 'r') {
2651 scanhex(&ndump);
2652 if (ndump == 0)
2653 ndump = 64;
2654 xmon_rawdump(adrs, ndump);
2655 adrs += ndump;
2656 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 } else {
2658 scanhex(&ndump);
2659 if (ndump == 0)
2660 ndump = 64;
2661 else if (ndump > MAX_DUMP)
2662 ndump = MAX_DUMP;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002663
2664 switch (c) {
2665 case '8':
2666 case '4':
2667 case '2':
2668 case '1':
2669 ndump = ALIGN(ndump, 16);
2670 dump_by_size(adrs, ndump, c - '0');
2671 last[1] = c;
2672 last_cmd = last;
2673 break;
2674 default:
2675 prdump(adrs, ndump);
2676 last_cmd = "d\n";
2677 }
2678
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 adrs += ndump;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 }
2681}
2682
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002683static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684prdump(unsigned long adrs, long ndump)
2685{
2686 long n, m, c, r, nr;
2687 unsigned char temp[16];
2688
2689 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002690 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 putchar(' ');
2692 r = n < 16? n: 16;
2693 nr = mread(adrs, temp, r);
2694 adrs += nr;
2695 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002696 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002697 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 if (m < nr)
2699 printf("%.2x", temp[m]);
2700 else
2701 printf("%s", fault_chars[fault_type]);
2702 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002703 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002704 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002705 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 printf(" |");
2709 for (m = 0; m < r; ++m) {
2710 if (m < nr) {
2711 c = temp[m];
2712 putchar(' ' <= c && c <= '~'? c: '.');
2713 } else
2714 putchar(' ');
2715 }
2716 n -= r;
2717 for (; m < 16; ++m)
2718 putchar(' ');
2719 printf("|\n");
2720 if (nr < r)
2721 break;
2722 }
2723}
2724
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002725typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2726
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002727static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002728generic_inst_dump(unsigned long adr, long count, int praddr,
2729 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730{
2731 int nr, dotted;
2732 unsigned long first_adr;
2733 unsigned long inst, last_inst = 0;
2734 unsigned char val[4];
2735
2736 dotted = 0;
2737 for (first_adr = adr; count > 0; --count, adr += 4) {
2738 nr = mread(adr, val, 4);
2739 if (nr == 0) {
2740 if (praddr) {
2741 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002742 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 }
2744 break;
2745 }
2746 inst = GETWORD(val);
2747 if (adr > first_adr && inst == last_inst) {
2748 if (!dotted) {
2749 printf(" ...\n");
2750 dotted = 1;
2751 }
2752 continue;
2753 }
2754 dotted = 0;
2755 last_inst = inst;
2756 if (praddr)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002757 printf(REG" %.8lx", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002759 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 printf("\n");
2761 }
2762 return adr - first_adr;
2763}
2764
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002765static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002766ppc_inst_dump(unsigned long adr, long count, int praddr)
2767{
2768 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2769}
2770
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771void
2772print_address(unsigned long addr)
2773{
2774 xmon_print_symbol(addr, "\t# ", "");
2775}
2776
Vinay Sridharf312deb2009-05-14 23:13:07 +00002777void
2778dump_log_buf(void)
2779{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002780 struct kmsg_dumper dumper = { .active = 1 };
2781 unsigned char buf[128];
2782 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002783
Michael Ellermane3bc8042012-08-23 22:09:13 +00002784 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002785 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002786 return;
2787 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002788
Michael Ellermane3bc8042012-08-23 22:09:13 +00002789 catch_memory_errors = 1;
2790 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002791
Michael Ellermanca5dd392012-08-23 22:09:12 +00002792 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002793 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002794 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2795 buf[len] = '\0';
2796 printf("%s", buf);
2797 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002798 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002799
Michael Ellermane3bc8042012-08-23 22:09:13 +00002800 sync();
2801 /* wait a little while to see if we get a machine check */
2802 __delay(200);
2803 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002804}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002806#ifdef CONFIG_PPC_POWERNV
2807static void dump_opal_msglog(void)
2808{
2809 unsigned char buf[128];
2810 ssize_t res;
2811 loff_t pos = 0;
2812
2813 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2814 printf("Machine is not running OPAL firmware.\n");
2815 return;
2816 }
2817
2818 if (setjmp(bus_error_jmp) != 0) {
2819 printf("Error dumping OPAL msglog!\n");
2820 return;
2821 }
2822
2823 catch_memory_errors = 1;
2824 sync();
2825
2826 xmon_start_pagination();
2827 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2828 if (res < 0) {
2829 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2830 break;
2831 }
2832 buf[res] = '\0';
2833 printf("%s", buf);
2834 pos += res;
2835 }
2836 xmon_end_pagination();
2837
2838 sync();
2839 /* wait a little while to see if we get a machine check */
2840 __delay(200);
2841 catch_memory_errors = 0;
2842}
2843#endif
2844
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845/*
2846 * Memory operations - move, set, print differences
2847 */
2848static unsigned long mdest; /* destination address */
2849static unsigned long msrc; /* source address */
2850static unsigned long mval; /* byte value to set memory to */
2851static unsigned long mcount; /* # bytes to affect */
2852static unsigned long mdiffs; /* max # differences to print */
2853
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002854static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855memops(int cmd)
2856{
2857 scanhex((void *)&mdest);
2858 if( termch != '\n' )
2859 termch = 0;
2860 scanhex((void *)(cmd == 's'? &mval: &msrc));
2861 if( termch != '\n' )
2862 termch = 0;
2863 scanhex((void *)&mcount);
2864 switch( cmd ){
2865 case 'm':
2866 memmove((void *)mdest, (void *)msrc, mcount);
2867 break;
2868 case 's':
2869 memset((void *)mdest, mval, mcount);
2870 break;
2871 case 'd':
2872 if( termch != '\n' )
2873 termch = 0;
2874 scanhex((void *)&mdiffs);
2875 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2876 break;
2877 }
2878}
2879
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002880static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2882{
2883 unsigned n, prt;
2884
2885 prt = 0;
2886 for( n = nb; n > 0; --n )
2887 if( *p1++ != *p2++ )
2888 if( ++prt <= maxpr )
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002889 printf("%px %.2x # %px %.2x\n", p1 - 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 p1[-1], p2 - 1, p2[-1]);
2891 if( prt > maxpr )
2892 printf("Total of %d differences\n", prt);
2893}
2894
2895static unsigned mend;
2896static unsigned mask;
2897
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002898static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899memlocate(void)
2900{
2901 unsigned a, n;
2902 unsigned char val[4];
2903
2904 last_cmd = "ml";
2905 scanhex((void *)&mdest);
2906 if (termch != '\n') {
2907 termch = 0;
2908 scanhex((void *)&mend);
2909 if (termch != '\n') {
2910 termch = 0;
2911 scanhex((void *)&mval);
2912 mask = ~0;
2913 if (termch != '\n') termch = 0;
2914 scanhex((void *)&mask);
2915 }
2916 }
2917 n = 0;
2918 for (a = mdest; a < mend; a += 4) {
2919 if (mread(a, val, 4) == 4
2920 && ((GETWORD(val) ^ mval) & mask) == 0) {
2921 printf("%.16x: %.16x\n", a, GETWORD(val));
2922 if (++n >= 10)
2923 break;
2924 }
2925 }
2926}
2927
2928static unsigned long mskip = 0x1000;
2929static unsigned long mlim = 0xffffffff;
2930
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002931static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932memzcan(void)
2933{
2934 unsigned char v;
2935 unsigned a;
2936 int ok, ook;
2937
2938 scanhex(&mdest);
2939 if (termch != '\n') termch = 0;
2940 scanhex(&mskip);
2941 if (termch != '\n') termch = 0;
2942 scanhex(&mlim);
2943 ook = 0;
2944 for (a = mdest; a < mlim; a += mskip) {
2945 ok = mread(a, &v, 1);
2946 if (ok && !ook) {
2947 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 } else if (!ok && ook)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002949 printf("%.8lx\n", a - mskip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 ook = ok;
2951 if (a + mskip < a)
2952 break;
2953 }
2954 if (ook)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002955 printf("%.8lx\n", a - mskip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956}
2957
Douglas Miller6dfb5402015-11-23 09:01:15 -06002958static void show_task(struct task_struct *tsk)
2959{
2960 char state;
2961
2962 /*
2963 * Cloned from kdb_task_state_char(), which is not entirely
2964 * appropriate for calling from xmon. This could be moved
2965 * to a common, generic, routine used by both.
2966 */
2967 state = (tsk->state == 0) ? 'R' :
2968 (tsk->state < 0) ? 'U' :
2969 (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
2970 (tsk->state & TASK_STOPPED) ? 'T' :
2971 (tsk->state & TASK_TRACED) ? 'C' :
2972 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
2973 (tsk->exit_state & EXIT_DEAD) ? 'E' :
2974 (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
2975
Michael Ellermand8104182017-12-06 23:23:28 +11002976 printf("%px %016lx %6d %6d %c %2d %s\n", tsk,
Douglas Miller6dfb5402015-11-23 09:01:15 -06002977 tsk->thread.ksp,
2978 tsk->pid, tsk->parent->pid,
2979 state, task_thread_info(tsk)->cpu,
2980 tsk->comm);
2981}
2982
Balbir Singh80eff6c2017-10-30 22:01:12 +11002983#ifdef CONFIG_PPC_BOOK3S_64
2984void format_pte(void *ptep, unsigned long pte)
2985{
2986 printf("ptep @ 0x%016lx = 0x%016lx\n", (unsigned long)ptep, pte);
2987 printf("Maps physical address = 0x%016lx\n", pte & PTE_RPN_MASK);
2988
2989 printf("Flags = %s%s%s%s%s\n",
2990 (pte & _PAGE_ACCESSED) ? "Accessed " : "",
2991 (pte & _PAGE_DIRTY) ? "Dirty " : "",
2992 (pte & _PAGE_READ) ? "Read " : "",
2993 (pte & _PAGE_WRITE) ? "Write " : "",
2994 (pte & _PAGE_EXEC) ? "Exec " : "");
2995}
2996
2997static void show_pte(unsigned long addr)
2998{
2999 unsigned long tskv = 0;
3000 struct task_struct *tsk = NULL;
3001 struct mm_struct *mm;
3002 pgd_t *pgdp, *pgdir;
3003 pud_t *pudp;
3004 pmd_t *pmdp;
3005 pte_t *ptep;
3006
3007 if (!scanhex(&tskv))
3008 mm = &init_mm;
3009 else
3010 tsk = (struct task_struct *)tskv;
3011
3012 if (tsk == NULL)
3013 mm = &init_mm;
3014 else
3015 mm = tsk->active_mm;
3016
3017 if (setjmp(bus_error_jmp) != 0) {
3018 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11003019 printf("*** Error dumping pte for task %px\n", tsk);
Balbir Singh80eff6c2017-10-30 22:01:12 +11003020 return;
3021 }
3022
3023 catch_memory_errors = 1;
3024 sync();
3025
3026 if (mm == &init_mm) {
3027 pgdp = pgd_offset_k(addr);
3028 pgdir = pgd_offset_k(0);
3029 } else {
3030 pgdp = pgd_offset(mm, addr);
3031 pgdir = pgd_offset(mm, 0);
3032 }
3033
3034 if (pgd_none(*pgdp)) {
3035 printf("no linux page table for address\n");
3036 return;
3037 }
3038
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003039 printf("pgd @ 0x%px\n", pgdir);
Balbir Singh80eff6c2017-10-30 22:01:12 +11003040
3041 if (pgd_huge(*pgdp)) {
3042 format_pte(pgdp, pgd_val(*pgdp));
3043 return;
3044 }
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003045 printf("pgdp @ 0x%px = 0x%016lx\n", pgdp, pgd_val(*pgdp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003046
3047 pudp = pud_offset(pgdp, addr);
3048
3049 if (pud_none(*pudp)) {
3050 printf("No valid PUD\n");
3051 return;
3052 }
3053
3054 if (pud_huge(*pudp)) {
3055 format_pte(pudp, pud_val(*pudp));
3056 return;
3057 }
3058
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003059 printf("pudp @ 0x%px = 0x%016lx\n", pudp, pud_val(*pudp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003060
3061 pmdp = pmd_offset(pudp, addr);
3062
3063 if (pmd_none(*pmdp)) {
3064 printf("No valid PMD\n");
3065 return;
3066 }
3067
3068 if (pmd_huge(*pmdp)) {
3069 format_pte(pmdp, pmd_val(*pmdp));
3070 return;
3071 }
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003072 printf("pmdp @ 0x%px = 0x%016lx\n", pmdp, pmd_val(*pmdp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003073
3074 ptep = pte_offset_map(pmdp, addr);
3075 if (pte_none(*ptep)) {
3076 printf("no valid PTE\n");
3077 return;
3078 }
3079
3080 format_pte(ptep, pte_val(*ptep));
3081
3082 sync();
3083 __delay(200);
3084 catch_memory_errors = 0;
3085}
3086#else
3087static void show_pte(unsigned long addr)
3088{
3089 printf("show_pte not yet implemented\n");
3090}
3091#endif /* CONFIG_PPC_BOOK3S_64 */
3092
Douglas Miller6dfb5402015-11-23 09:01:15 -06003093static void show_tasks(void)
3094{
3095 unsigned long tskv;
3096 struct task_struct *tsk = NULL;
3097
3098 printf(" task_struct ->thread.ksp PID PPID S P CMD\n");
3099
3100 if (scanhex(&tskv))
3101 tsk = (struct task_struct *)tskv;
3102
3103 if (setjmp(bus_error_jmp) != 0) {
3104 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11003105 printf("*** Error dumping task %px\n", tsk);
Douglas Miller6dfb5402015-11-23 09:01:15 -06003106 return;
3107 }
3108
3109 catch_memory_errors = 1;
3110 sync();
3111
3112 if (tsk)
3113 show_task(tsk);
3114 else
3115 for_each_process(tsk)
3116 show_task(tsk);
3117
3118 sync();
3119 __delay(200);
3120 catch_memory_errors = 0;
3121}
3122
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003123static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003124{
3125 unsigned long args[8];
3126 unsigned long ret;
3127 int i;
3128 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
3129 unsigned long, unsigned long, unsigned long,
3130 unsigned long, unsigned long, unsigned long);
3131 callfunc_t func;
3132
3133 if (!scanhex(&adrs))
3134 return;
3135 if (termch != '\n')
3136 termch = 0;
3137 for (i = 0; i < 8; ++i)
3138 args[i] = 0;
3139 for (i = 0; i < 8; ++i) {
3140 if (!scanhex(&args[i]) || termch == '\n')
3141 break;
3142 termch = 0;
3143 }
3144 func = (callfunc_t) adrs;
3145 ret = 0;
3146 if (setjmp(bus_error_jmp) == 0) {
3147 catch_memory_errors = 1;
3148 sync();
3149 ret = func(args[0], args[1], args[2], args[3],
3150 args[4], args[5], args[6], args[7]);
3151 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10003152 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003153 } else {
3154 printf("*** %x exception occurred\n", fault_except);
3155 }
3156 catch_memory_errors = 0;
3157}
3158
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159/* Input scanning routines */
3160int
3161skipbl(void)
3162{
3163 int c;
3164
3165 if( termch != 0 ){
3166 c = termch;
3167 termch = 0;
3168 } else
3169 c = inchar();
3170 while( c == ' ' || c == '\t' )
3171 c = inchar();
3172 return c;
3173}
3174
3175#define N_PTREGS 44
3176static char *regnames[N_PTREGS] = {
3177 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
3178 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
3179 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
3180 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003181 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
3182#ifdef CONFIG_PPC64
3183 "softe",
3184#else
3185 "mq",
3186#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 "trap", "dar", "dsisr", "res"
3188};
3189
3190int
3191scanhex(unsigned long *vp)
3192{
3193 int c, d;
3194 unsigned long v;
3195
3196 c = skipbl();
3197 if (c == '%') {
3198 /* parse register name */
3199 char regname[8];
3200 int i;
3201
3202 for (i = 0; i < sizeof(regname) - 1; ++i) {
3203 c = inchar();
3204 if (!isalnum(c)) {
3205 termch = c;
3206 break;
3207 }
3208 regname[i] = c;
3209 }
3210 regname[i] = 0;
3211 for (i = 0; i < N_PTREGS; ++i) {
3212 if (strcmp(regnames[i], regname) == 0) {
3213 if (xmon_regs == NULL) {
3214 printf("regs not available\n");
3215 return 0;
3216 }
3217 *vp = ((unsigned long *)xmon_regs)[i];
3218 return 1;
3219 }
3220 }
3221 printf("invalid register name '%%%s'\n", regname);
3222 return 0;
3223 }
3224
3225 /* skip leading "0x" if any */
3226
3227 if (c == '0') {
3228 c = inchar();
3229 if (c == 'x') {
3230 c = inchar();
3231 } else {
3232 d = hexdigit(c);
3233 if (d == EOF) {
3234 termch = c;
3235 *vp = 0;
3236 return 1;
3237 }
3238 }
3239 } else if (c == '$') {
3240 int i;
3241 for (i=0; i<63; i++) {
3242 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02003243 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 termch = c;
3245 break;
3246 }
3247 tmpstr[i] = c;
3248 }
3249 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07003250 *vp = 0;
3251 if (setjmp(bus_error_jmp) == 0) {
3252 catch_memory_errors = 1;
3253 sync();
3254 *vp = kallsyms_lookup_name(tmpstr);
3255 sync();
3256 }
3257 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 if (!(*vp)) {
3259 printf("unknown symbol '%s'\n", tmpstr);
3260 return 0;
3261 }
3262 return 1;
3263 }
3264
3265 d = hexdigit(c);
3266 if (d == EOF) {
3267 termch = c;
3268 return 0;
3269 }
3270 v = 0;
3271 do {
3272 v = (v << 4) + d;
3273 c = inchar();
3274 d = hexdigit(c);
3275 } while (d != EOF);
3276 termch = c;
3277 *vp = v;
3278 return 1;
3279}
3280
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003281static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282scannl(void)
3283{
3284 int c;
3285
3286 c = termch;
3287 termch = 0;
3288 while( c != '\n' )
3289 c = inchar();
3290}
3291
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003292static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293{
3294 if( '0' <= c && c <= '9' )
3295 return c - '0';
3296 if( 'A' <= c && c <= 'F' )
3297 return c - ('A' - 10);
3298 if( 'a' <= c && c <= 'f' )
3299 return c - ('a' - 10);
3300 return EOF;
3301}
3302
3303void
3304getstring(char *s, int size)
3305{
3306 int c;
3307
3308 c = skipbl();
3309 do {
3310 if( size > 1 ){
3311 *s++ = c;
3312 --size;
3313 }
3314 c = inchar();
3315 } while( c != ' ' && c != '\t' && c != '\n' );
3316 termch = c;
3317 *s = 0;
3318}
3319
3320static char line[256];
3321static char *lineptr;
3322
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003323static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324flush_input(void)
3325{
3326 lineptr = NULL;
3327}
3328
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003329static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330inchar(void)
3331{
3332 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003333 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 lineptr = NULL;
3335 return EOF;
3336 }
3337 lineptr = line;
3338 }
3339 return *lineptr++;
3340}
3341
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003342static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343take_input(char *str)
3344{
3345 lineptr = str;
3346}
3347
3348
3349static void
3350symbol_lookup(void)
3351{
3352 int type = inchar();
3353 unsigned long addr;
3354 static char tmp[64];
3355
3356 switch (type) {
3357 case 'a':
3358 if (scanhex(&addr))
3359 xmon_print_symbol(addr, ": ", "\n");
3360 termch = 0;
3361 break;
3362 case 's':
3363 getstring(tmp, 64);
3364 if (setjmp(bus_error_jmp) == 0) {
3365 catch_memory_errors = 1;
3366 sync();
3367 addr = kallsyms_lookup_name(tmp);
3368 if (addr)
3369 printf("%s: %lx\n", tmp, addr);
3370 else
3371 printf("Symbol '%s' not found.\n", tmp);
3372 sync();
3373 }
3374 catch_memory_errors = 0;
3375 termch = 0;
3376 break;
3377 }
3378}
3379
3380
3381/* Print an address in numeric and symbolic form (if possible) */
3382static void xmon_print_symbol(unsigned long address, const char *mid,
3383 const char *after)
3384{
3385 char *modname;
3386 const char *name = NULL;
3387 unsigned long offset, size;
3388
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003389 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 if (setjmp(bus_error_jmp) == 0) {
3391 catch_memory_errors = 1;
3392 sync();
3393 name = kallsyms_lookup(address, &size, &offset, &modname,
3394 tmpstr);
3395 sync();
3396 /* wait a little while to see if we get a machine check */
3397 __delay(200);
3398 }
3399
3400 catch_memory_errors = 0;
3401
3402 if (name) {
3403 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
3404 if (modname)
3405 printf(" [%s]", modname);
3406 }
3407 printf("%s", after);
3408}
3409
Michael Ellerman4e003742017-10-19 15:08:43 +11003410#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10003411void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412{
3413 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05303414 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11003415 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416
Michael Ellerman736256e2014-05-26 21:02:14 +10003417 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418
Michael Neuling584f8b72007-12-06 17:24:48 +11003419 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11003420 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
3421 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Michael Ellerman85673642017-04-24 10:35:14 +10003422
3423 if (!esid && !vsid)
3424 continue;
3425
3426 printf("%02d %016lx %016lx", i, esid, vsid);
3427
3428 if (!(esid & SLB_ESID_V)) {
3429 printf("\n");
3430 continue;
3431 }
3432
3433 llp = vsid & SLB_VSID_LLP;
3434 if (vsid & SLB_VSID_B_1T) {
3435 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
3436 GET_ESID_1T(esid),
3437 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
3438 llp);
3439 } else {
3440 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
3441 GET_ESID(esid),
3442 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
3443 llp);
will schmidtb3b95952007-12-07 08:22:23 +11003444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 }
3446}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003447#endif
3448
3449#ifdef CONFIG_PPC_STD_MMU_32
3450void dump_segments(void)
3451{
3452 int i;
3453
3454 printf("sr0-15 =");
3455 for (i = 0; i < 16; ++i)
3456 printf(" %x", mfsrin(i));
3457 printf("\n");
3458}
3459#endif
3460
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003461#ifdef CONFIG_44x
3462static void dump_tlb_44x(void)
3463{
3464 int i;
3465
3466 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
3467 unsigned long w0,w1,w2;
3468 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
3469 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
3470 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003471 printf("[%02x] %08lx %08lx %08lx ", i, w0, w1, w2);
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003472 if (w0 & PPC44x_TLB_VALID) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003473 printf("V %08lx -> %01lx%08lx %c%c%c%c%c",
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003474 w0 & PPC44x_TLB_EPN_MASK,
3475 w1 & PPC44x_TLB_ERPN_MASK,
3476 w1 & PPC44x_TLB_RPN_MASK,
3477 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
3478 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
3479 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
3480 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
3481 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
3482 }
3483 printf("\n");
3484 }
3485}
3486#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003487
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10003488#ifdef CONFIG_PPC_BOOK3E
3489static void dump_tlb_book3e(void)
3490{
3491 u32 mmucfg, pidmask, lpidmask;
3492 u64 ramask;
3493 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3494 int mmu_version;
3495 static const char *pgsz_names[] = {
3496 " 1K",
3497 " 2K",
3498 " 4K",
3499 " 8K",
3500 " 16K",
3501 " 32K",
3502 " 64K",
3503 "128K",
3504 "256K",
3505 "512K",
3506 " 1M",
3507 " 2M",
3508 " 4M",
3509 " 8M",
3510 " 16M",
3511 " 32M",
3512 " 64M",
3513 "128M",
3514 "256M",
3515 "512M",
3516 " 1G",
3517 " 2G",
3518 " 4G",
3519 " 8G",
3520 " 16G",
3521 " 32G",
3522 " 64G",
3523 "128G",
3524 "256G",
3525 "512G",
3526 " 1T",
3527 " 2T",
3528 };
3529
3530 /* Gather some infos about the MMU */
3531 mmucfg = mfspr(SPRN_MMUCFG);
3532 mmu_version = (mmucfg & 3) + 1;
3533 ntlbs = ((mmucfg >> 2) & 3) + 1;
3534 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3535 lpidsz = (mmucfg >> 24) & 0xf;
3536 rasz = (mmucfg >> 16) & 0x7f;
3537 if ((mmu_version > 1) && (mmucfg & 0x10000))
3538 lrat = 1;
3539 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3540 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3541 pidmask = (1ul << pidsz) - 1;
3542 lpidmask = (1ul << lpidsz) - 1;
3543 ramask = (1ull << rasz) - 1;
3544
3545 for (tlb = 0; tlb < ntlbs; tlb++) {
3546 u32 tlbcfg;
3547 int nent, assoc, new_cc = 1;
3548 printf("TLB %d:\n------\n", tlb);
3549 switch(tlb) {
3550 case 0:
3551 tlbcfg = mfspr(SPRN_TLB0CFG);
3552 break;
3553 case 1:
3554 tlbcfg = mfspr(SPRN_TLB1CFG);
3555 break;
3556 case 2:
3557 tlbcfg = mfspr(SPRN_TLB2CFG);
3558 break;
3559 case 3:
3560 tlbcfg = mfspr(SPRN_TLB3CFG);
3561 break;
3562 default:
3563 printf("Unsupported TLB number !\n");
3564 continue;
3565 }
3566 nent = tlbcfg & 0xfff;
3567 assoc = (tlbcfg >> 24) & 0xff;
3568 for (i = 0; i < nent; i++) {
3569 u32 mas0 = MAS0_TLBSEL(tlb);
3570 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3571 u64 mas2 = 0;
3572 u64 mas7_mas3;
3573 int esel = i, cc = i;
3574
3575 if (assoc != 0) {
3576 cc = i / assoc;
3577 esel = i % assoc;
3578 mas2 = cc * 0x1000;
3579 }
3580
3581 mas0 |= MAS0_ESEL(esel);
3582 mtspr(SPRN_MAS0, mas0);
3583 mtspr(SPRN_MAS1, mas1);
3584 mtspr(SPRN_MAS2, mas2);
3585 asm volatile("tlbre 0,0,0" : : : "memory");
3586 mas1 = mfspr(SPRN_MAS1);
3587 mas2 = mfspr(SPRN_MAS2);
3588 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3589 if (assoc && (i % assoc) == 0)
3590 new_cc = 1;
3591 if (!(mas1 & MAS1_VALID))
3592 continue;
3593 if (assoc == 0)
3594 printf("%04x- ", i);
3595 else if (new_cc)
3596 printf("%04x-%c", cc, 'A' + esel);
3597 else
3598 printf(" |%c", 'A' + esel);
3599 new_cc = 0;
3600 printf(" %016llx %04x %s %c%c AS%c",
3601 mas2 & ~0x3ffull,
3602 (mas1 >> 16) & 0x3fff,
3603 pgsz_names[(mas1 >> 7) & 0x1f],
3604 mas1 & MAS1_IND ? 'I' : ' ',
3605 mas1 & MAS1_IPROT ? 'P' : ' ',
3606 mas1 & MAS1_TS ? '1' : '0');
3607 printf(" %c%c%c%c%c%c%c",
3608 mas2 & MAS2_X0 ? 'a' : ' ',
3609 mas2 & MAS2_X1 ? 'v' : ' ',
3610 mas2 & MAS2_W ? 'w' : ' ',
3611 mas2 & MAS2_I ? 'i' : ' ',
3612 mas2 & MAS2_M ? 'm' : ' ',
3613 mas2 & MAS2_G ? 'g' : ' ',
3614 mas2 & MAS2_E ? 'e' : ' ');
3615 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3616 if (mas1 & MAS1_IND)
3617 printf(" %s\n",
3618 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3619 else
3620 printf(" U%c%c%c S%c%c%c\n",
3621 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3622 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3623 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3624 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3625 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3626 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3627 }
3628 }
3629}
3630#endif /* CONFIG_PPC_BOOK3E */
3631
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003632static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003634 if (enable) {
3635 __debugger = xmon;
3636 __debugger_ipi = xmon_ipi;
3637 __debugger_bpt = xmon_bpt;
3638 __debugger_sstep = xmon_sstep;
3639 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003640 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003641 __debugger_fault_handler = xmon_fault_handler;
3642 } else {
3643 __debugger = NULL;
3644 __debugger_ipi = NULL;
3645 __debugger_bpt = NULL;
3646 __debugger_sstep = NULL;
3647 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003648 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003649 __debugger_fault_handler = NULL;
3650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003652
3653#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003654static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003655{
3656 /* ensure xmon is enabled */
3657 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003658 debugger(get_irq_regs());
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003659 if (!xmon_on)
3660 xmon_init(0);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003661}
3662
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003663static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003664 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003665 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003666 .action_msg = "Entering xmon",
3667};
3668
3669static int __init setup_xmon_sysrq(void)
3670{
3671 register_sysrq_key('x', &sysrq_xmon_op);
3672 return 0;
3673}
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003674device_initcall(setup_xmon_sysrq);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003675#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003676
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003677#ifdef CONFIG_DEBUG_FS
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05303678static void clear_all_bpt(void)
3679{
3680 int i;
3681
3682 /* clear/unpatch all breakpoints */
3683 remove_bpts();
3684 remove_cpu_bpts();
3685
3686 /* Disable all breakpoints */
3687 for (i = 0; i < NBPTS; ++i)
3688 bpts[i].enabled = 0;
3689
3690 /* Clear any data or iabr breakpoints */
3691 if (iabr || dabr.enabled) {
3692 iabr = NULL;
3693 dabr.enabled = 0;
3694 }
3695
3696 printf("xmon: All breakpoints cleared\n");
3697}
3698
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003699static int xmon_dbgfs_set(void *data, u64 val)
3700{
3701 xmon_on = !!val;
3702 xmon_init(xmon_on);
3703
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05303704 /* make sure all breakpoints removed when disabling */
3705 if (!xmon_on)
3706 clear_all_bpt();
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003707 return 0;
3708}
3709
3710static int xmon_dbgfs_get(void *data, u64 *val)
3711{
3712 *val = xmon_on;
3713 return 0;
3714}
3715
3716DEFINE_SIMPLE_ATTRIBUTE(xmon_dbgfs_ops, xmon_dbgfs_get,
3717 xmon_dbgfs_set, "%llu\n");
3718
3719static int __init setup_xmon_dbgfs(void)
3720{
3721 debugfs_create_file("xmon", 0600, powerpc_debugfs_root, NULL,
3722 &xmon_dbgfs_ops);
3723 return 0;
3724}
3725device_initcall(setup_xmon_dbgfs);
3726#endif /* CONFIG_DEBUG_FS */
3727
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003728static int xmon_early __initdata;
Michael Ellerman476792832006-10-03 14:12:08 +10003729
3730static int __init early_parse_xmon(char *p)
3731{
3732 if (!p || strncmp(p, "early", 5) == 0) {
3733 /* just "xmon" is equivalent to "xmon=early" */
3734 xmon_init(1);
3735 xmon_early = 1;
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003736 xmon_on = 1;
3737 } else if (strncmp(p, "on", 2) == 0) {
Michael Ellerman476792832006-10-03 14:12:08 +10003738 xmon_init(1);
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003739 xmon_on = 1;
3740 } else if (strncmp(p, "off", 3) == 0)
3741 xmon_on = 0;
Michael Ellerman476792832006-10-03 14:12:08 +10003742 else
3743 return 1;
3744
3745 return 0;
3746}
3747early_param("xmon", early_parse_xmon);
3748
3749void __init xmon_setup(void)
3750{
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003751 if (xmon_on)
Michael Ellerman476792832006-10-03 14:12:08 +10003752 xmon_init(1);
Michael Ellerman476792832006-10-03 14:12:08 +10003753 if (xmon_early)
3754 debugger(NULL);
3755}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003756
Arnd Bergmanne0555952006-11-27 19:18:55 +01003757#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003758
3759struct spu_info {
3760 struct spu *spu;
3761 u64 saved_mfc_sr1_RW;
3762 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003763 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003764 u8 stopped_ok;
3765};
3766
3767#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3768
3769static struct spu_info spu_info[XMON_NUM_SPUS];
3770
3771void xmon_register_spus(struct list_head *list)
3772{
3773 struct spu *spu;
3774
3775 list_for_each_entry(spu, list, full_list) {
3776 if (spu->number >= XMON_NUM_SPUS) {
3777 WARN_ON(1);
3778 continue;
3779 }
3780
3781 spu_info[spu->number].spu = spu;
3782 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003783 spu_info[spu->number].dump_addr = (unsigned long)
3784 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003785 }
3786}
3787
3788static void stop_spus(void)
3789{
3790 struct spu *spu;
3791 int i;
3792 u64 tmp;
3793
3794 for (i = 0; i < XMON_NUM_SPUS; i++) {
3795 if (!spu_info[i].spu)
3796 continue;
3797
3798 if (setjmp(bus_error_jmp) == 0) {
3799 catch_memory_errors = 1;
3800 sync();
3801
3802 spu = spu_info[i].spu;
3803
3804 spu_info[i].saved_spu_runcntl_RW =
3805 in_be32(&spu->problem->spu_runcntl_RW);
3806
3807 tmp = spu_mfc_sr1_get(spu);
3808 spu_info[i].saved_mfc_sr1_RW = tmp;
3809
3810 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3811 spu_mfc_sr1_set(spu, tmp);
3812
3813 sync();
3814 __delay(200);
3815
3816 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003817
3818 printf("Stopped spu %.2d (was %s)\n", i,
3819 spu_info[i].saved_spu_runcntl_RW ?
3820 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003821 } else {
3822 catch_memory_errors = 0;
3823 printf("*** Error stopping spu %.2d\n", i);
3824 }
3825 catch_memory_errors = 0;
3826 }
3827}
3828
3829static void restart_spus(void)
3830{
3831 struct spu *spu;
3832 int i;
3833
3834 for (i = 0; i < XMON_NUM_SPUS; i++) {
3835 if (!spu_info[i].spu)
3836 continue;
3837
3838 if (!spu_info[i].stopped_ok) {
3839 printf("*** Error, spu %d was not successfully stopped"
3840 ", not restarting\n", i);
3841 continue;
3842 }
3843
3844 if (setjmp(bus_error_jmp) == 0) {
3845 catch_memory_errors = 1;
3846 sync();
3847
3848 spu = spu_info[i].spu;
3849 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3850 out_be32(&spu->problem->spu_runcntl_RW,
3851 spu_info[i].saved_spu_runcntl_RW);
3852
3853 sync();
3854 __delay(200);
3855
3856 printf("Restarted spu %.2d\n", i);
3857 } else {
3858 catch_memory_errors = 0;
3859 printf("*** Error restarting spu %.2d\n", i);
3860 }
3861 catch_memory_errors = 0;
3862 }
3863}
3864
Michael Ellermana8984972006-10-24 18:31:28 +02003865#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003866#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003867do { \
3868 if (setjmp(bus_error_jmp) == 0) { \
3869 catch_memory_errors = 1; \
3870 sync(); \
3871 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003872 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003873 sync(); \
3874 __delay(200); \
3875 } else { \
3876 catch_memory_errors = 0; \
3877 printf(" %-*s = *** Error reading field.\n", \
3878 DUMP_WIDTH, #field); \
3879 } \
3880 catch_memory_errors = 0; \
3881} while (0)
3882
Michael Ellerman437a0702006-11-23 00:46:39 +01003883#define DUMP_FIELD(obj, format, field) \
3884 DUMP_VALUE(format, field, obj->field)
3885
Michael Ellermana8984972006-10-24 18:31:28 +02003886static void dump_spu_fields(struct spu *spu)
3887{
3888 printf("Dumping spu fields at address %p:\n", spu);
3889
3890 DUMP_FIELD(spu, "0x%x", number);
3891 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003892 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3893 DUMP_FIELD(spu, "0x%p", local_store);
3894 DUMP_FIELD(spu, "0x%lx", ls_size);
3895 DUMP_FIELD(spu, "0x%x", node);
3896 DUMP_FIELD(spu, "0x%lx", flags);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003897 DUMP_FIELD(spu, "%llu", class_0_pending);
3898 DUMP_FIELD(spu, "0x%llx", class_0_dar);
3899 DUMP_FIELD(spu, "0x%llx", class_1_dar);
3900 DUMP_FIELD(spu, "0x%llx", class_1_dsisr);
3901 DUMP_FIELD(spu, "0x%x", irqs[0]);
3902 DUMP_FIELD(spu, "0x%x", irqs[1]);
3903 DUMP_FIELD(spu, "0x%x", irqs[2]);
Michael Ellermana8984972006-10-24 18:31:28 +02003904 DUMP_FIELD(spu, "0x%x", slb_replace);
3905 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003906 DUMP_FIELD(spu, "0x%p", mm);
3907 DUMP_FIELD(spu, "0x%p", ctx);
3908 DUMP_FIELD(spu, "0x%p", rq);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003909 DUMP_FIELD(spu, "0x%llx", timestamp);
Michael Ellermana8984972006-10-24 18:31:28 +02003910 DUMP_FIELD(spu, "0x%lx", problem_phys);
3911 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003912 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3913 in_be32(&spu->problem->spu_runcntl_RW));
3914 DUMP_VALUE("0x%x", problem->spu_status_R,
3915 in_be32(&spu->problem->spu_status_R));
3916 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3917 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003918 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003919 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003920}
3921
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003922int
3923spu_inst_dump(unsigned long adr, long count, int praddr)
3924{
3925 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3926}
3927
3928static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003929{
3930 unsigned long offset, addr, ls_addr;
3931
3932 if (setjmp(bus_error_jmp) == 0) {
3933 catch_memory_errors = 1;
3934 sync();
3935 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3936 sync();
3937 __delay(200);
3938 } else {
3939 catch_memory_errors = 0;
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003940 printf("*** Error: accessing spu info for spu %ld\n", num);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003941 return;
3942 }
3943 catch_memory_errors = 0;
3944
3945 if (scanhex(&offset))
3946 addr = ls_addr + offset;
3947 else
3948 addr = spu_info[num].dump_addr;
3949
3950 if (addr >= ls_addr + LS_SIZE) {
3951 printf("*** Error: address outside of local store\n");
3952 return;
3953 }
3954
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003955 switch (subcmd) {
3956 case 'i':
3957 addr += spu_inst_dump(addr, 16, 1);
3958 last_cmd = "sdi\n";
3959 break;
3960 default:
3961 prdump(addr, 64);
3962 addr += 64;
3963 last_cmd = "sd\n";
3964 break;
3965 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003966
3967 spu_info[num].dump_addr = addr;
3968}
3969
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003970static int do_spu_cmd(void)
3971{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003972 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003973 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003974
3975 cmd = inchar();
3976 switch (cmd) {
3977 case 's':
3978 stop_spus();
3979 break;
3980 case 'r':
3981 restart_spus();
3982 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003983 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003984 subcmd = inchar();
3985 if (isxdigit(subcmd) || subcmd == '\n')
3986 termch = subcmd;
3987 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003988 scanhex(&num);
3989 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003990 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003991 return 0;
3992 }
3993
3994 switch (cmd) {
3995 case 'f':
3996 dump_spu_fields(spu_info[num].spu);
3997 break;
3998 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003999 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01004000 break;
4001 }
4002
Michael Ellermana8984972006-10-24 18:31:28 +02004003 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004004 default:
4005 return -1;
4006 }
4007
4008 return 0;
4009}
Arnd Bergmanne0555952006-11-27 19:18:55 +01004010#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004011static int do_spu_cmd(void)
4012{
4013 return -1;
4014}
4015#endif