blob: a0f44f9923608929d352596e43af8311698c3467 [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>
Boqun Feng302c7b02016-11-22 17:20:09 +080059#include <asm/sections.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110060
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100061#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100063#include <asm/paca.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010067#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100070static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071static unsigned long xmon_taken = 1;
72static int xmon_owner;
73static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000074#else
75#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#endif /* CONFIG_SMP */
77
Breno Leitao8d4a8622018-11-08 15:12:42 -020078#ifdef CONFIG_PPC_PSERIES
79static int set_indicator_token = RTAS_UNKNOWN_SERVICE;
80#endif
Anton Blanchard5be34922010-01-12 00:50:14 +000081static unsigned long in_xmon __read_mostly = 0;
Pan Xinhui3b5bf422017-03-22 16:27:49 -030082static int xmon_on = IS_ENABLED(CONFIG_XMON_DEFAULT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84static unsigned long adrs;
85static int size = 1;
86#define MAX_DUMP (128 * 1024)
87static unsigned long ndump = 64;
88static unsigned long nidump = 16;
89static unsigned long ncsum = 4096;
90static int termch;
91static char tmpstr[128];
Breno Leitaoed49f7f2017-08-02 17:14:06 -030092static int tracing_enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static long bus_error_jmp[JMP_BUF_LEN];
95static int catch_memory_errors;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +100096static int catch_spr_faults;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99/* Breakpoint stuff */
100struct bpt {
101 unsigned long address;
102 unsigned int instr[2];
103 atomic_t ref_count;
104 int enabled;
105 unsigned long pad;
106};
107
108/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100109#define BP_CIABR 1
110#define BP_TRAP 2
111#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
113#define NBPTS 256
114static struct bpt bpts[NBPTS];
115static struct bpt dabr;
116static struct bpt *iabr;
117static unsigned bpinstr = 0x7fe00008; /* trap */
118
119#define BP_NUM(bp) ((bp) - bpts + 1)
120
121/* Prototypes */
122static int cmds(struct pt_regs *);
123static int mread(unsigned long, void *, int);
124static int mwrite(unsigned long, void *, int);
125static int handle_fault(struct pt_regs *);
126static void byterev(unsigned char *, int);
127static void memex(void);
128static int bsesc(void);
129static void dump(void);
Balbir Singh80eff6c2017-10-30 22:01:12 +1100130static void show_pte(unsigned long);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131static void prdump(unsigned long, long);
132static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000133static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100134
135#ifdef CONFIG_PPC_POWERNV
136static void dump_opal_msglog(void);
137#else
138static inline void dump_opal_msglog(void)
139{
140 printf("Machine is not running OPAL firmware.\n");
141}
142#endif
143
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144static void backtrace(struct pt_regs *);
145static void excprint(struct pt_regs *);
146static void prregs(struct pt_regs *);
147static void memops(int);
148static void memlocate(void);
149static void memzcan(void);
150static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
151int skipbl(void);
152int scanhex(unsigned long *valp);
153static void scannl(void);
154static int hexdigit(int);
155void getstring(char *, int);
156static void flush_input(void);
157static int inchar(void);
158static void take_input(char *);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000159static int read_spr(int, unsigned long *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160static void write_spr(int, unsigned long);
161static void super_regs(void);
162static void remove_bpts(void);
163static void insert_bpts(void);
164static void remove_cpu_bpts(void);
165static void insert_cpu_bpts(void);
166static struct bpt *at_breakpoint(unsigned long pc);
167static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
168static int do_step(struct pt_regs *);
169static void bpt_cmds(void);
170static void cacheflush(void);
171static int cpu_cmd(void);
172static void csum(void);
173static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000174static void proccall(void);
Douglas Miller6dfb5402015-11-23 09:01:15 -0600175static void show_tasks(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176void dump_segments(void);
177static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200178static void xmon_show_stack(unsigned long sp, unsigned long lr,
179 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180static void xmon_print_symbol(unsigned long address, const char *mid,
181 const char *after);
182static const char *getvecname(unsigned long vec);
183
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200184static int do_spu_cmd(void);
185
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100186#ifdef CONFIG_44x
187static void dump_tlb_44x(void);
188#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000189#ifdef CONFIG_PPC_BOOK3E
190static void dump_tlb_book3e(void);
191#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100192
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000193#ifdef CONFIG_PPC64
194#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000195#else
196#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000197#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100199#ifdef __LITTLE_ENDIAN__
200#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
201#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100203#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205static char *help_string = "\
206Commands:\n\
207 b show breakpoints\n\
208 bd set data breakpoint\n\
209 bi set instruction breakpoint\n\
210 bc clear breakpoint\n"
211#ifdef CONFIG_SMP
212 "\
213 c print cpus stopped in xmon\n\
214 c# try to switch to cpu number h (in hex)\n"
215#endif
216 "\
217 C checksum\n\
218 d dump bytes\n\
Douglas Miller5e48dc02017-02-07 07:40:44 -0600219 d1 dump 1 byte values\n\
220 d2 dump 2 byte values\n\
221 d4 dump 4 byte values\n\
222 d8 dump 8 byte values\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 di dump instructions\n\
224 df dump float values\n\
225 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000226 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100227#ifdef CONFIG_PPC_POWERNV
228 "\
229 do dump the OPAL message log\n"
230#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000231#ifdef CONFIG_PPC64
232 "\
233 dp[#] dump paca for current cpu, or cpu #\n\
234 dpa dump paca for all possible cpus\n"
235#endif
236 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100237 dr dump stream of raw bytes\n\
Balbir Singh80eff6c2017-10-30 22:01:12 +1100238 dv dump virtual address translation \n\
Michael Ellerman56144ec2015-11-06 13:21:17 +1100239 dt dump the tracing buffers (uses printk)\n\
Breno Leitao4125d012017-08-02 17:14:05 -0300240 dtc dump the tracing buffers for current CPU (uses printk)\n\
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +1000241"
242#ifdef CONFIG_PPC_POWERNV
243" dx# dump xive on CPU #\n\
244 dxi# dump xive irq state #\n\
245 dxa dump xive on all CPUs\n"
246#endif
247" e print exception information\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 f flush cache\n\
249 la lookup symbol+offset of specified address\n\
250 ls lookup address of specified symbol\n\
Boqun Feng302c7b02016-11-22 17:20:09 +0800251 lp s [#] lookup address of percpu symbol s for current cpu, or cpu #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 m examine/change memory\n\
253 mm move a block of memory\n\
254 ms set a block of memory\n\
255 md compare two blocks of memory\n\
256 ml locate a block of memory\n\
257 mz zero a block of memory\n\
258 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000259 p call a procedure\n\
Douglas Miller6dfb5402015-11-23 09:01:15 -0600260 P list processes/tasks\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200262 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100263#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200264" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200265 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100266 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900267 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100268 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200269#endif
270" S print special registers\n\
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000271 Sa print all SPRs\n\
272 Sr # read SPR #\n\
273 Sw #v write v to SPR #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100276 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000277#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000278" u dump segment table or SLB\n"
Christophe Leroy68289ae2018-11-17 10:25:02 +0000279#elif defined(CONFIG_PPC_BOOK3S_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000280" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000281#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100282" u dump TLB\n"
283#endif
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300284" U show uptime information\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000285" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100286" # n limit output to n lines per page (for dp, dpa, dl)\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000287" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 zh halt\n"
289;
290
291static struct pt_regs *xmon_regs;
292
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000293static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294{
295 asm volatile("sync; isync");
296}
297
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000298static inline void store_inst(void *p)
299{
300 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
301}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000303static inline void cflush(void *p)
304{
305 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
306}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000308static inline void cinval(void *p)
309{
310 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
311}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530313/**
314 * write_ciabr() - write the CIABR SPR
315 * @ciabr: The value to write.
316 *
317 * This function writes a value to the CIARB register either directly
318 * through mtspr instruction if the kernel is in HV privilege mode or
319 * call a hypervisor function to achieve the same in case the kernel
320 * is in supervisor privilege mode.
321 */
322static void write_ciabr(unsigned long ciabr)
323{
324 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
325 return;
326
327 if (cpu_has_feature(CPU_FTR_HVMODE)) {
328 mtspr(SPRN_CIABR, ciabr);
329 return;
330 }
Michael Ellerman7c09c182018-03-08 13:54:41 +1100331 plpar_set_ciabr(ciabr);
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530332}
333
334/**
335 * set_ciabr() - set the CIABR
336 * @addr: The value to set.
337 *
338 * This function sets the correct privilege value into the the HW
339 * breakpoint address before writing it up in the CIABR register.
340 */
341static void set_ciabr(unsigned long addr)
342{
343 addr &= ~CIABR_PRIV;
344
345 if (cpu_has_feature(CPU_FTR_HVMODE))
346 addr |= CIABR_PRIV_HYPER;
347 else
348 addr |= CIABR_PRIV_SUPER;
349 write_ciabr(addr);
350}
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352/*
353 * Disable surveillance (the service processor watchdog function)
354 * while we are in xmon.
355 * XXX we should re-enable it when we leave. :)
356 */
357#define SURVEILLANCE_TOKEN 9000
358
359static inline void disable_surveillance(void)
360{
361#ifdef CONFIG_PPC_PSERIES
362 /* Since this can't be a module, args should end up below 4GB. */
363 static struct rtas_args args;
364
365 /*
366 * At this point we have got all the cpus we can into
367 * xmon, so there is hopefully no other cpu calling RTAS
368 * at the moment, even though we don't take rtas.lock.
369 * If we did try to take rtas.lock there would be a
370 * real possibility of deadlock.
371 */
Breno Leitao8d4a8622018-11-08 15:12:42 -0200372 if (set_indicator_token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100374
Breno Leitao8d4a8622018-11-08 15:12:42 -0200375 rtas_call_unlocked(&args, set_indicator_token, 3, 1, NULL,
376 SURVEILLANCE_TOKEN, 0, 0);
Michael Ellerman08eb1052015-11-24 22:26:09 +1100377
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378#endif /* CONFIG_PPC_PSERIES */
379}
380
381#ifdef CONFIG_SMP
382static int xmon_speaker;
383
384static void get_output_lock(void)
385{
386 int me = smp_processor_id() + 0x100;
387 int last_speaker = 0, prev;
388 long timeout;
389
390 if (xmon_speaker == me)
391 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100392
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100394 last_speaker = cmpxchg(&xmon_speaker, 0, me);
395 if (last_speaker == 0)
396 return;
397
Michael Ellerman15075892013-12-23 23:46:05 +1100398 /*
399 * Wait a full second for the lock, we might be on a slow
400 * console, but check every 100us.
401 */
402 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100404 if (--timeout > 0) {
405 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100407 }
408
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 /* hostile takeover */
410 prev = cmpxchg(&xmon_speaker, last_speaker, me);
411 if (prev == last_speaker)
412 return;
413 break;
414 }
415 }
416}
417
418static void release_output_lock(void)
419{
420 xmon_speaker = 0;
421}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000422
423int cpus_are_in_xmon(void)
424{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000425 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000426}
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000427
428static bool wait_for_other_cpus(int ncpus)
429{
430 unsigned long timeout;
431
432 /* We wait for 2s, which is a metric "little while" */
433 for (timeout = 20000; timeout != 0; --timeout) {
434 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
435 return true;
436 udelay(100);
437 barrier();
438 }
439
440 return false;
441}
442#endif /* CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
Josh Boyerdaf8f402009-09-23 03:51:04 +0000444static inline int unrecoverable_excp(struct pt_regs *regs)
445{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000446#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000447 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000448 return 0;
449#else
450 return ((regs->msr & MSR_RI) == 0);
451#endif
452}
453
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000454static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455{
456 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 struct bpt *bp;
458 long recurse_jmp[JMP_BUF_LEN];
459 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100460 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461#ifdef CONFIG_SMP
462 int cpu;
463 int secondary;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464#endif
465
Anton Blanchardf13659e2007-03-21 01:48:34 +1100466 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000467 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Breno Leitaoed49f7f2017-08-02 17:14:06 -0300469 tracing_enabled = tracing_is_on();
470 tracing_off();
471
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 bp = in_breakpoint_table(regs->nip, &offset);
473 if (bp != NULL) {
474 regs->nip = bp->address + offset;
475 atomic_dec(&bp->ref_count);
476 }
477
478 remove_cpu_bpts();
479
480#ifdef CONFIG_SMP
481 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000482 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000483 /*
484 * We catch SPR read/write faults here because the 0x700, 0xf60
485 * etc. handlers don't call debugger_fault_handler().
486 */
487 if (catch_spr_faults)
488 longjmp(bus_error_jmp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 get_output_lock();
490 excprint(regs);
491 printf("cpu 0x%x: Exception %lx %s in xmon, "
492 "returning to main loop\n",
493 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000494 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 longjmp(xmon_fault_jmp[cpu], 1);
496 }
497
498 if (setjmp(recurse_jmp) != 0) {
499 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000500 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 printf("xmon: WARNING: bad recursive fault "
502 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000503 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 goto waiting;
505 }
506 secondary = !(xmon_taken && cpu == xmon_owner);
507 goto cmdloop;
508 }
509
510 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
512 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000513 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000515 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 fromipi = 0;
517
518 if (!fromipi) {
519 get_output_lock();
520 excprint(regs);
521 if (bp) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +0200522 printf("cpu 0x%x stopped at breakpoint 0x%tx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 cpu, BP_NUM(bp));
524 xmon_print_symbol(regs->nip, " ", ")\n");
525 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000526 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 printf("WARNING: exception is not recoverable, "
528 "can't continue\n");
529 release_output_lock();
530 }
531
Michael Ellermand2b496e2013-12-23 23:46:06 +1100532 cpumask_set_cpu(cpu, &cpus_in_xmon);
533
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 waiting:
535 secondary = 1;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000536 spin_begin();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 while (secondary && !xmon_gate) {
538 if (in_xmon == 0) {
Nicholas Piggin064996d2017-09-29 13:29:40 +1000539 if (fromipi) {
540 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 goto leave;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 secondary = test_and_set_bit(0, &in_xmon);
544 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000545 spin_cpu_relax();
546 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000548 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
550 if (!secondary && !xmon_gate) {
551 /* we are the first cpu to come in */
552 /* interrupt other cpu(s) */
553 int ncpus = num_online_cpus();
554
555 xmon_owner = cpu;
556 mb();
557 if (ncpus > 1) {
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000558 /*
559 * A system reset (trap == 0x100) can be triggered on
560 * all CPUs, so when we come in via 0x100 try waiting
561 * for the other CPUs to come in before we send the
562 * debugger break (IPI). This is similar to
563 * crash_kexec_secondary().
564 */
565 if (TRAP(regs) != 0x100 || !wait_for_other_cpus(ncpus))
566 smp_send_debugger_break();
567
568 wait_for_other_cpus(ncpus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 }
570 remove_bpts();
571 disable_surveillance();
572 /* for breakpoint or single step, print the current instr. */
573 if (bp || TRAP(regs) == 0xd00)
574 ppc_inst_dump(regs->nip, 1, 0);
575 printf("enter ? for help\n");
576 mb();
577 xmon_gate = 1;
578 barrier();
Nicholas Piggin064996d2017-09-29 13:29:40 +1000579 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 }
581
582 cmdloop:
583 while (in_xmon) {
584 if (secondary) {
Nicholas Piggin064996d2017-09-29 13:29:40 +1000585 spin_begin();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 if (cpu == xmon_owner) {
587 if (!test_and_set_bit(0, &xmon_taken)) {
588 secondary = 0;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000589 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 continue;
591 }
592 /* missed it */
593 while (cpu == xmon_owner)
Nicholas Piggin064996d2017-09-29 13:29:40 +1000594 spin_cpu_relax();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000596 spin_cpu_relax();
597 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 } else {
599 cmd = cmds(regs);
600 if (cmd != 0) {
601 /* exiting xmon */
602 insert_bpts();
603 xmon_gate = 0;
604 wmb();
605 in_xmon = 0;
606 break;
607 }
608 /* have switched to some other cpu */
609 secondary = 1;
610 }
611 }
612 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000613 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615#else
616 /* UP is simple... */
617 if (in_xmon) {
618 printf("Exception %lx %s in xmon, returning to main loop\n",
619 regs->trap, getvecname(TRAP(regs)));
620 longjmp(xmon_fault_jmp[0], 1);
621 }
622 if (setjmp(recurse_jmp) == 0) {
623 xmon_fault_jmp[0] = recurse_jmp;
624 in_xmon = 1;
625
626 excprint(regs);
627 bp = at_breakpoint(regs->nip);
628 if (bp) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +0200629 printf("Stopped at breakpoint %tx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 xmon_print_symbol(regs->nip, " ", ")\n");
631 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000632 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 printf("WARNING: exception is not recoverable, "
634 "can't continue\n");
635 remove_bpts();
636 disable_surveillance();
637 /* for breakpoint or single step, print the current instr. */
638 if (bp || TRAP(regs) == 0xd00)
639 ppc_inst_dump(regs->nip, 1, 0);
640 printf("enter ? for help\n");
641 }
642
643 cmd = cmds(regs);
644
645 insert_bpts();
646 in_xmon = 0;
647#endif
648
Josh Boyercdd39042009-10-05 04:46:05 +0000649#ifdef CONFIG_BOOKE
650 if (regs->msr & MSR_DE) {
651 bp = at_breakpoint(regs->nip);
652 if (bp != NULL) {
653 regs->nip = (unsigned long) &bp->instr[0];
654 atomic_inc(&bp->ref_count);
655 }
656 }
657#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000658 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 bp = at_breakpoint(regs->nip);
660 if (bp != NULL) {
661 int stepped = emulate_step(regs, bp->instr[0]);
662 if (stepped == 0) {
663 regs->nip = (unsigned long) &bp->instr[0];
664 atomic_inc(&bp->ref_count);
665 } else if (stepped < 0) {
666 printf("Couldn't single-step %s instruction\n",
667 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
668 }
669 }
670 }
Josh Boyercdd39042009-10-05 04:46:05 +0000671#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 insert_cpu_bpts();
673
Anton Blancharda71d64b2014-08-05 14:55:00 +1000674 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100675 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000677 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678}
679
680int xmon(struct pt_regs *excp)
681{
682 struct pt_regs regs;
683
684 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000685 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 excp = &regs;
687 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200688
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 return xmon_core(excp, 0);
690}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000691EXPORT_SYMBOL(xmon);
692
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000693irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000694{
695 unsigned long flags;
696 local_irq_save(flags);
697 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000698 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000699 local_irq_restore(flags);
700 return IRQ_HANDLED;
701}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000703static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704{
705 struct bpt *bp;
706 unsigned long offset;
707
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000708 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 return 0;
710
711 /* Are we at the trap at bp->instr[1] for some bp? */
712 bp = in_breakpoint_table(regs->nip, &offset);
713 if (bp != NULL && offset == 4) {
714 regs->nip = bp->address + 4;
715 atomic_dec(&bp->ref_count);
716 return 1;
717 }
718
719 /* Are we at a breakpoint? */
720 bp = at_breakpoint(regs->nip);
721 if (!bp)
722 return 0;
723
724 xmon_core(regs, 0);
725
726 return 1;
727}
728
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000729static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730{
731 if (user_mode(regs))
732 return 0;
733 xmon_core(regs, 0);
734 return 1;
735}
736
Michael Neuling9422de32012-12-20 14:06:44 +0000737static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000739 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000741 if (dabr.enabled == 0)
742 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 xmon_core(regs, 0);
744 return 1;
745}
746
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000747static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000749 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000751 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return 0;
753 xmon_core(regs, 0);
754 return 1;
755}
756
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000757static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758{
759#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000760 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 xmon_core(regs, 1);
762#endif
763 return 0;
764}
765
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000766static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767{
768 struct bpt *bp;
769 unsigned long offset;
770
771 if (in_xmon && catch_memory_errors)
772 handle_fault(regs); /* doesn't return */
773
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000774 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 bp = in_breakpoint_table(regs->nip, &offset);
776 if (bp != NULL) {
777 regs->nip = bp->address + offset;
778 atomic_dec(&bp->ref_count);
779 }
780 }
781
782 return 0;
783}
784
Michal Suchanek7daf5932018-05-23 20:00:54 +0200785/* Force enable xmon if not already enabled */
786static inline void force_enable_xmon(void)
787{
788 /* Enable xmon hooks if needed */
789 if (!xmon_on) {
790 printf("xmon: Enabling debugger hooks\n");
791 xmon_on = 1;
792 }
793}
794
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795static struct bpt *at_breakpoint(unsigned long pc)
796{
797 int i;
798 struct bpt *bp;
799
800 bp = bpts;
801 for (i = 0; i < NBPTS; ++i, ++bp)
802 if (bp->enabled && pc == bp->address)
803 return bp;
804 return NULL;
805}
806
807static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
808{
809 unsigned long off;
810
811 off = nip - (unsigned long) bpts;
812 if (off >= sizeof(bpts))
813 return NULL;
814 off %= sizeof(struct bpt);
815 if (off != offsetof(struct bpt, instr[0])
816 && off != offsetof(struct bpt, instr[1]))
817 return NULL;
818 *offp = off - offsetof(struct bpt, instr[0]);
819 return (struct bpt *) (nip - off);
820}
821
822static struct bpt *new_breakpoint(unsigned long a)
823{
824 struct bpt *bp;
825
826 a &= ~3UL;
827 bp = at_breakpoint(a);
828 if (bp)
829 return bp;
830
831 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
832 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
833 bp->address = a;
834 bp->instr[1] = bpinstr;
835 store_inst(&bp->instr[1]);
836 return bp;
837 }
838 }
839
840 printf("Sorry, no free breakpoints. Please clear one first.\n");
841 return NULL;
842}
843
844static void insert_bpts(void)
845{
846 int i;
847 struct bpt *bp;
848
849 bp = bpts;
850 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100851 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 continue;
853 if (mread(bp->address, &bp->instr[0], 4) != 4) {
854 printf("Couldn't read instruction at %lx, "
855 "disabling breakpoint there\n", bp->address);
856 bp->enabled = 0;
857 continue;
858 }
859 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
860 printf("Breakpoint at %lx is on an mtmsrd or rfid "
861 "instruction, disabling it\n", bp->address);
862 bp->enabled = 0;
863 continue;
864 }
865 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100866 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 continue;
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000868 if (patch_instruction((unsigned int *)bp->address,
869 bpinstr) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 printf("Couldn't write instruction at %lx, "
871 "disabling breakpoint there\n", bp->address);
872 bp->enabled &= ~BP_TRAP;
873 continue;
874 }
875 store_inst((void *)bp->address);
876 }
877}
878
879static void insert_cpu_bpts(void)
880{
Michael Neuling9422de32012-12-20 14:06:44 +0000881 struct arch_hw_breakpoint brk;
882
883 if (dabr.enabled) {
884 brk.address = dabr.address;
885 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
886 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400887 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000888 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530889
890 if (iabr)
891 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892}
893
894static void remove_bpts(void)
895{
896 int i;
897 struct bpt *bp;
898 unsigned instr;
899
900 bp = bpts;
901 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100902 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 continue;
904 if (mread(bp->address, &instr, 4) == 4
905 && instr == bpinstr
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000906 && patch_instruction(
907 (unsigned int *)bp->address, bp->instr[0]) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 printf("Couldn't remove breakpoint at %lx\n",
909 bp->address);
910 else
911 store_inst((void *)bp->address);
912 }
913}
914
915static void remove_cpu_bpts(void)
916{
Michael Neuling9422de32012-12-20 14:06:44 +0000917 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530918 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919}
920
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300921/* Based on uptime_proc_show(). */
922static void
923show_uptime(void)
924{
Arnd Bergmannf6bd74f2018-06-18 11:56:24 +0200925 struct timespec64 uptime;
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300926
927 if (setjmp(bus_error_jmp) == 0) {
928 catch_memory_errors = 1;
929 sync();
930
Arnd Bergmannf6bd74f2018-06-18 11:56:24 +0200931 ktime_get_coarse_boottime_ts64(&uptime);
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300932 printf("Uptime: %lu.%.2lu seconds\n", (unsigned long)uptime.tv_sec,
933 ((unsigned long)uptime.tv_nsec / (NSEC_PER_SEC/100)));
934
935 sync();
936 __delay(200); \
937 }
938 catch_memory_errors = 0;
939}
940
Sam bobroff958b7c82015-10-08 11:50:23 +1100941static void set_lpp_cmd(void)
942{
943 unsigned long lpp;
944
945 if (!scanhex(&lpp)) {
946 printf("Invalid number.\n");
947 lpp = 0;
948 }
949 xmon_set_pagination_lpp(lpp);
950}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951/* Command interpreting routine */
952static char *last_cmd;
953
954static int
955cmds(struct pt_regs *excp)
956{
957 int cmd = 0;
958
959 last_cmd = NULL;
960 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200961
Guilherme G. Piccolib5617832017-03-22 16:27:50 -0300962 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
Olaf Hering26c8af52006-09-08 16:29:21 +0200963
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 for(;;) {
965#ifdef CONFIG_SMP
966 printf("%x:", smp_processor_id());
967#endif /* CONFIG_SMP */
968 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 flush_input();
970 termch = 0;
971 cmd = skipbl();
972 if( cmd == '\n' ) {
973 if (last_cmd == NULL)
974 continue;
975 take_input(last_cmd);
976 last_cmd = NULL;
977 cmd = inchar();
978 }
979 switch (cmd) {
980 case 'm':
981 cmd = inchar();
982 switch (cmd) {
983 case 'm':
984 case 's':
985 case 'd':
986 memops(cmd);
987 break;
988 case 'l':
989 memlocate();
990 break;
991 case 'z':
992 memzcan();
993 break;
994 case 'i':
Michal Hocko9af744d2017-02-22 15:46:16 -0800995 show_mem(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 break;
997 default:
998 termch = cmd;
999 memex();
1000 }
1001 break;
1002 case 'd':
1003 dump();
1004 break;
1005 case 'l':
1006 symbol_lookup();
1007 break;
1008 case 'r':
1009 prregs(excp); /* print regs */
1010 break;
1011 case 'e':
1012 excprint(excp);
1013 break;
1014 case 'S':
1015 super_regs();
1016 break;
1017 case 't':
1018 backtrace(excp);
1019 break;
1020 case 'f':
1021 cacheflush();
1022 break;
1023 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +02001024 if (do_spu_cmd() == 0)
1025 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 if (do_step(excp))
1027 return cmd;
1028 break;
1029 case 'x':
1030 case 'X':
Breno Leitaoed49f7f2017-08-02 17:14:06 -03001031 if (tracing_enabled)
1032 tracing_on();
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001033 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001035 printf(" <no input ...>\n");
1036 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 return cmd;
1038 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +10001039 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 break;
Sam bobroff958b7c82015-10-08 11:50:23 +11001041 case '#':
1042 set_lpp_cmd();
1043 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 case 'b':
1045 bpt_cmds();
1046 break;
1047 case 'C':
1048 csum();
1049 break;
1050 case 'c':
1051 if (cpu_cmd())
1052 return 0;
1053 break;
1054 case 'z':
1055 bootcmds();
1056 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001057 case 'p':
1058 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -06001060 case 'P':
1061 show_tasks();
1062 break;
Christophe Leroy5b3e84f2018-11-17 10:25:04 +00001063#ifdef CONFIG_PPC_BOOK3S
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 case 'u':
1065 dump_segments();
1066 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +11001067#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11001068 case 'u':
1069 dump_tlb_44x();
1070 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +00001071#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10001072 case 'u':
1073 dump_tlb_book3e();
1074 break;
1075#endif
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -03001076 case 'U':
1077 show_uptime();
1078 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 default:
1080 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +00001081 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 if (' ' < cmd && cmd <= '~')
1083 putchar(cmd);
1084 else
1085 printf("\\x%x", cmd);
1086 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +00001087 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 printf(" (type ? for help)\n");
1089 break;
1090 }
1091 }
1092}
1093
Josh Boyercdd39042009-10-05 04:46:05 +00001094#ifdef CONFIG_BOOKE
1095static int do_step(struct pt_regs *regs)
1096{
1097 regs->msr |= MSR_DE;
1098 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1099 return 1;
1100}
1101#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102/*
1103 * Step a single instruction.
1104 * Some instructions we emulate, others we execute with MSR_SE set.
1105 */
1106static int do_step(struct pt_regs *regs)
1107{
1108 unsigned int instr;
1109 int stepped;
1110
Michal Suchanek7daf5932018-05-23 20:00:54 +02001111 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001113 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 if (mread(regs->nip, &instr, 4) == 4) {
1115 stepped = emulate_step(regs, instr);
1116 if (stepped < 0) {
1117 printf("Couldn't single-step %s instruction\n",
1118 (IS_RFID(instr)? "rfid": "mtmsrd"));
1119 return 0;
1120 }
1121 if (stepped > 0) {
1122 regs->trap = 0xd00 | (regs->trap & 1);
1123 printf("stepped to ");
1124 xmon_print_symbol(regs->nip, " ", "\n");
1125 ppc_inst_dump(regs->nip, 1, 0);
1126 return 0;
1127 }
1128 }
1129 }
1130 regs->msr |= MSR_SE;
1131 return 1;
1132}
Josh Boyercdd39042009-10-05 04:46:05 +00001133#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
1135static void bootcmds(void)
1136{
1137 int cmd;
1138
1139 cmd = inchar();
1140 if (cmd == 'r')
1141 ppc_md.restart(NULL);
1142 else if (cmd == 'h')
1143 ppc_md.halt();
1144 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001145 if (pm_power_off)
1146 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147}
1148
1149static int cpu_cmd(void)
1150{
1151#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001152 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154
1155 if (!scanhex(&cpu)) {
1156 /* print cpus waiting or in xmon */
1157 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001158 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001159 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001160 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001161 if (cpu == last_cpu + 1) {
1162 last_cpu = cpu;
1163 } else {
1164 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001165 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001166 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001167 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 }
1170 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001171 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001172 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 printf("\n");
1174 return 0;
1175 }
1176 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001177 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001178 printf("cpu 0x%lx isn't in xmon\n", cpu);
Michael Ellerman7b087292018-05-02 23:07:26 +10001179#ifdef CONFIG_PPC64
1180 printf("backtrace of paca[0x%lx].saved_r1 (possibly stale):\n", cpu);
1181 xmon_show_stack(paca_ptrs[cpu]->saved_r1, 0, 0);
1182#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 return 0;
1184 }
1185 xmon_taken = 0;
1186 mb();
1187 xmon_owner = cpu;
1188 timeout = 10000000;
1189 while (!xmon_taken) {
1190 if (--timeout == 0) {
1191 if (test_and_set_bit(0, &xmon_taken))
1192 break;
1193 /* take control back */
1194 mb();
1195 xmon_owner = smp_processor_id();
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001196 printf("cpu 0x%lx didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 return 0;
1198 }
1199 barrier();
1200 }
1201 return 1;
1202#else
1203 return 0;
1204#endif /* CONFIG_SMP */
1205}
1206
1207static unsigned short fcstab[256] = {
1208 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1209 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1210 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1211 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1212 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1213 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1214 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1215 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1216 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1217 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1218 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1219 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1220 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1221 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1222 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1223 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1224 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1225 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1226 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1227 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1228 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1229 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1230 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1231 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1232 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1233 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1234 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1235 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1236 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1237 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1238 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1239 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1240};
1241
1242#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1243
1244static void
1245csum(void)
1246{
1247 unsigned int i;
1248 unsigned short fcs;
1249 unsigned char v;
1250
1251 if (!scanhex(&adrs))
1252 return;
1253 if (!scanhex(&ncsum))
1254 return;
1255 fcs = 0xffff;
1256 for (i = 0; i < ncsum; ++i) {
1257 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001258 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 break;
1260 }
1261 fcs = FCS(fcs, v);
1262 }
1263 printf("%x\n", fcs);
1264}
1265
1266/*
1267 * Check if this is a suitable place to put a breakpoint.
1268 */
1269static long check_bp_loc(unsigned long addr)
1270{
1271 unsigned int instr;
1272
1273 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001274 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 printf("Breakpoints may only be placed at kernel addresses\n");
1276 return 0;
1277 }
1278 if (!mread(addr, &instr, sizeof(instr))) {
1279 printf("Can't read instruction at address %lx\n", addr);
1280 return 0;
1281 }
1282 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1283 printf("Breakpoints may not be placed on mtmsrd or rfid "
1284 "instructions\n");
1285 return 0;
1286 }
1287 return 1;
1288}
1289
Michael Ellermane3bc8042012-08-23 22:09:13 +00001290static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 "Breakpoint command usage:\n"
1292 "b show breakpoints\n"
1293 "b <addr> [cnt] set breakpoint at given instr addr\n"
1294 "bc clear all breakpoints\n"
1295 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301296 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 "bd <addr> [cnt] set hardware data breakpoint\n"
1298 "";
1299
1300static void
1301bpt_cmds(void)
1302{
1303 int cmd;
1304 unsigned long a;
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001305 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 struct bpt *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
1308 cmd = inchar();
1309 switch (cmd) {
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001310#ifndef CONFIG_PPC_8xx
1311 static const char badaddr[] = "Only kernel addresses are permitted for breakpoints\n";
1312 int mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 case 'd': /* bd - hardware data breakpoint */
Michael Neuling9bc2bd52018-03-27 15:37:19 +11001314 if (!ppc_breakpoint_available()) {
1315 printf("Hardware data breakpoint not supported on this cpu\n");
1316 break;
1317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 mode = 7;
1319 cmd = inchar();
1320 if (cmd == 'r')
1321 mode = 5;
1322 else if (cmd == 'w')
1323 mode = 6;
1324 else
1325 termch = cmd;
1326 dabr.address = 0;
1327 dabr.enabled = 0;
1328 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001329 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 printf(badaddr);
1331 break;
1332 }
Michael Neuling9422de32012-12-20 14:06:44 +00001333 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 dabr.enabled = mode | BP_DABR;
1335 }
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301336
1337 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 break;
1339
1340 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301341 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 printf("Hardware instruction breakpoint "
1343 "not supported on this cpu\n");
1344 break;
1345 }
1346 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001347 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 iabr = NULL;
1349 }
1350 if (!scanhex(&a))
1351 break;
1352 if (!check_bp_loc(a))
1353 break;
1354 bp = new_breakpoint(a);
1355 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001356 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 iabr = bp;
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301358 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 }
1360 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001361#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
1363 case 'c':
1364 if (!scanhex(&a)) {
1365 /* clear all breakpoints */
1366 for (i = 0; i < NBPTS; ++i)
1367 bpts[i].enabled = 0;
1368 iabr = NULL;
1369 dabr.enabled = 0;
1370 printf("All breakpoints cleared\n");
1371 break;
1372 }
1373
1374 if (a <= NBPTS && a >= 1) {
1375 /* assume a breakpoint number */
1376 bp = &bpts[a-1]; /* bp nums are 1 based */
1377 } else {
1378 /* assume a breakpoint address */
1379 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001380 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001381 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 break;
1383 }
1384 }
1385
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001386 printf("Cleared breakpoint %tx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 xmon_print_symbol(bp->address, " ", ")\n");
1388 bp->enabled = 0;
1389 break;
1390
1391 default:
1392 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001393 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 if (cmd == '?') {
1395 printf(breakpoint_help_string);
1396 break;
1397 }
1398 termch = cmd;
1399 if (!scanhex(&a)) {
1400 /* print all breakpoints */
1401 printf(" type address\n");
1402 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001403 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 if (dabr.enabled & 1)
1405 printf("r");
1406 if (dabr.enabled & 2)
1407 printf("w");
1408 printf("]\n");
1409 }
1410 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1411 if (!bp->enabled)
1412 continue;
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001413 printf("%tx %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001414 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 xmon_print_symbol(bp->address, " ", "\n");
1416 }
1417 break;
1418 }
1419
1420 if (!check_bp_loc(a))
1421 break;
1422 bp = new_breakpoint(a);
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301423 if (bp != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 bp->enabled |= BP_TRAP;
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301425 force_enable_xmon();
1426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 break;
1428 }
1429}
1430
1431/* Very cheap human name for vector lookup. */
1432static
1433const char *getvecname(unsigned long vec)
1434{
1435 char *ret;
1436
1437 switch (vec) {
1438 case 0x100: ret = "(System Reset)"; break;
1439 case 0x200: ret = "(Machine Check)"; break;
1440 case 0x300: ret = "(Data Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001441 case 0x380:
1442 if (radix_enabled())
1443 ret = "(Data Access Out of Range)";
1444 else
1445 ret = "(Data SLB Access)";
1446 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 case 0x400: ret = "(Instruction Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001448 case 0x480:
1449 if (radix_enabled())
1450 ret = "(Instruction Access Out of Range)";
1451 else
1452 ret = "(Instruction SLB Access)";
1453 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 case 0x500: ret = "(Hardware Interrupt)"; break;
1455 case 0x600: ret = "(Alignment)"; break;
1456 case 0x700: ret = "(Program Check)"; break;
1457 case 0x800: ret = "(FPU Unavailable)"; break;
1458 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001459 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1460 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 case 0xc00: ret = "(System Call)"; break;
1462 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001463 case 0xe40: ret = "(Emulation Assist)"; break;
1464 case 0xe60: ret = "(HMI)"; break;
1465 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 case 0xf00: ret = "(Performance Monitor)"; break;
1467 case 0xf20: ret = "(Altivec Unavailable)"; break;
1468 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001469 case 0x1500: ret = "(Denormalisation)"; break;
1470 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 default: ret = "";
1472 }
1473 return ret;
1474}
1475
1476static void get_function_bounds(unsigned long pc, unsigned long *startp,
1477 unsigned long *endp)
1478{
1479 unsigned long size, offset;
1480 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481
1482 *startp = *endp = 0;
1483 if (pc == 0)
1484 return;
1485 if (setjmp(bus_error_jmp) == 0) {
1486 catch_memory_errors = 1;
1487 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001488 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 if (name != NULL) {
1490 *startp = pc - offset;
1491 *endp = pc - offset + size;
1492 }
1493 sync();
1494 }
1495 catch_memory_errors = 0;
1496}
1497
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001498#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1499#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501static void xmon_show_stack(unsigned long sp, unsigned long lr,
1502 unsigned long pc)
1503{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001504 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 unsigned long ip;
1506 unsigned long newsp;
1507 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 struct pt_regs regs;
1509
Michael Ellerman0104cd62012-10-09 04:20:36 +00001510 while (max_to_print--) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301511 if (!is_kernel_addr(sp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 if (sp != 0)
1513 printf("SP (%lx) is in userspace\n", sp);
1514 break;
1515 }
1516
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001517 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 || !mread(sp, &newsp, sizeof(unsigned long))) {
1519 printf("Couldn't read stack frame at %lx\n", sp);
1520 break;
1521 }
1522
1523 /*
1524 * For the first stack frame, try to work out if
1525 * LR and/or the saved LR value in the bottommost
1526 * stack frame are valid.
1527 */
1528 if ((pc | lr) != 0) {
1529 unsigned long fnstart, fnend;
1530 unsigned long nextip;
1531 int printip = 1;
1532
1533 get_function_bounds(pc, &fnstart, &fnend);
1534 nextip = 0;
1535 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001536 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 sizeof(unsigned long));
1538 if (lr == ip) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301539 if (!is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 || (fnstart <= lr && lr < fnend))
1541 printip = 0;
1542 } else if (lr == nextip) {
1543 printip = 0;
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301544 } else if (is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 && !(fnstart <= lr && lr < fnend)) {
1546 printf("[link register ] ");
1547 xmon_print_symbol(lr, " ", "\n");
1548 }
1549 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001550 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 xmon_print_symbol(ip, " ", " (unreliable)\n");
1552 }
1553 pc = lr = 0;
1554
1555 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001556 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 xmon_print_symbol(ip, " ", "\n");
1558 }
1559
1560 /* Look for "regshere" marker to see if this is
1561 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001562 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001563 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001564 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 != sizeof(regs)) {
1566 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001567 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 break;
1569 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001570 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 getvecname(TRAP(&regs)));
1572 pc = regs.nip;
1573 lr = regs.link;
1574 xmon_print_symbol(pc, " ", "\n");
1575 }
1576
1577 if (newsp == 0)
1578 break;
1579
1580 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582}
1583
1584static void backtrace(struct pt_regs *excp)
1585{
1586 unsigned long sp;
1587
1588 if (scanhex(&sp))
1589 xmon_show_stack(sp, 0, 0);
1590 else
1591 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1592 scannl();
1593}
1594
1595static void print_bug_trap(struct pt_regs *regs)
1596{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001597#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001598 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 unsigned long addr;
1600
1601 if (regs->msr & MSR_PR)
1602 return; /* not in kernel */
1603 addr = regs->nip; /* address of trap instruction */
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301604 if (!is_kernel_addr(addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 return;
1606 bug = find_bug(regs->nip);
1607 if (bug == NULL)
1608 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001609 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 return;
1611
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001612#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001613 printf("kernel BUG at %s:%u!\n",
1614 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001615#else
Michael Ellermand8104182017-12-06 23:23:28 +11001616 printf("kernel BUG at %px!\n", (void *)bug->bug_addr);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001617#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001618#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619}
1620
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001621static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622{
1623 unsigned long trap;
1624
1625#ifdef CONFIG_SMP
1626 printf("cpu 0x%x: ", smp_processor_id());
1627#endif /* CONFIG_SMP */
1628
1629 trap = TRAP(fp);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001630 printf("Vector: %lx %s at [%px]\n", fp->trap, getvecname(trap), fp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 printf(" pc: ");
1632 xmon_print_symbol(fp->nip, ": ", "\n");
1633
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001634 printf(" lr: ");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 xmon_print_symbol(fp->link, ": ", "\n");
1636
1637 printf(" sp: %lx\n", fp->gpr[1]);
1638 printf(" msr: %lx\n", fp->msr);
1639
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001640 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 printf(" dar: %lx\n", fp->dar);
1642 if (trap != 0x380)
1643 printf(" dsisr: %lx\n", fp->dsisr);
1644 }
1645
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001646 printf(" current = 0x%px\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001647#ifdef CONFIG_PPC64
Nicholas Piggin3130a7b2018-05-10 11:04:24 +10001648 printf(" paca = 0x%px\t irqmask: 0x%02x\t irq_happened: 0x%02x\n",
Madhavan Srinivasan4e26bc42017-12-20 09:25:50 +05301649 local_paca, local_paca->irq_soft_mask, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001650#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 if (current) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001652 printf(" pid = %d, comm = %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 current->pid, current->comm);
1654 }
1655
1656 if (trap == 0x700)
1657 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001658
1659 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660}
1661
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001662static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001664 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 unsigned long base;
1666 struct pt_regs regs;
1667
1668 if (scanhex(&base)) {
1669 if (setjmp(bus_error_jmp) == 0) {
1670 catch_memory_errors = 1;
1671 sync();
1672 regs = *(struct pt_regs *)base;
1673 sync();
1674 __delay(200);
1675 } else {
1676 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001677 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 base);
1679 return;
1680 }
1681 catch_memory_errors = 0;
1682 fp = &regs;
1683 }
1684
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001685#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 if (FULL_REGS(fp)) {
1687 for (n = 0; n < 16; ++n)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001688 printf("R%.2d = "REG" R%.2d = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1690 } else {
1691 for (n = 0; n < 7; ++n)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001692 printf("R%.2d = "REG" R%.2d = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1694 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001695#else
1696 for (n = 0; n < 32; ++n) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001697 printf("R%.2d = %.8lx%s", n, fp->gpr[n],
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001698 (n & 3) == 3? "\n": " ");
1699 if (n == 12 && !FULL_REGS(fp)) {
1700 printf("\n");
1701 break;
1702 }
1703 }
1704#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 printf("pc = ");
1706 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001707 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1708 printf("cfar= ");
1709 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 printf("lr = ");
1712 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001713 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1714 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001716 trap = TRAP(fp);
1717 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1718 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719}
1720
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001721static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722{
1723 int cmd;
1724 unsigned long nflush;
1725
1726 cmd = inchar();
1727 if (cmd != 'i')
1728 termch = cmd;
1729 scanhex((void *)&adrs);
1730 if (termch != '\n')
1731 termch = 0;
1732 nflush = 1;
1733 scanhex(&nflush);
1734 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1735 if (setjmp(bus_error_jmp) == 0) {
1736 catch_memory_errors = 1;
1737 sync();
1738
1739 if (cmd != 'i') {
1740 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1741 cflush((void *) adrs);
1742 } else {
1743 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1744 cinval((void *) adrs);
1745 }
1746 sync();
1747 /* wait a little while to see if we get a machine check */
1748 __delay(200);
1749 }
1750 catch_memory_errors = 0;
1751}
1752
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001753extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1754extern void xmon_mtspr(int spr, unsigned long value);
1755
1756static int
1757read_spr(int n, unsigned long *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 unsigned long ret = -1UL;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001760 int ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761
1762 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001763 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 sync();
1765
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001766 ret = xmon_mfspr(n, *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
1768 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001769 *vp = ret;
1770 ok = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001772 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001774 return ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775}
1776
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001777static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778write_spr(int n, unsigned long val)
1779{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001781 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 sync();
1783
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001784 xmon_mtspr(n, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
1786 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001787 } else {
1788 printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001790 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791}
1792
Michael Ellerman18461932016-07-07 22:54:29 +10001793static void dump_206_sprs(void)
1794{
1795#ifdef CONFIG_PPC64
1796 if (!cpu_has_feature(CPU_FTR_ARCH_206))
1797 return;
1798
1799 /* Actually some of these pre-date 2.06, but whatevs */
1800
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001801 printf("srr0 = %.16lx srr1 = %.16lx dsisr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001802 mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001803 printf("dscr = %.16lx ppr = %.16lx pir = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001804 mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001805 printf("amr = %.16lx uamor = %.16lx\n",
1806 mfspr(SPRN_AMR), mfspr(SPRN_UAMOR));
Michael Ellerman18461932016-07-07 22:54:29 +10001807
1808 if (!(mfmsr() & MSR_HV))
1809 return;
1810
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001811 printf("sdr1 = %.16lx hdar = %.16lx hdsisr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001812 mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001813 printf("hsrr0 = %.16lx hsrr1 = %.16lx hdec = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001814 mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001815 printf("lpcr = %.16lx pcr = %.16lx lpidr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001816 mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001817 printf("hsprg0 = %.16lx hsprg1 = %.16lx amor = %.16lx\n",
1818 mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1), mfspr(SPRN_AMOR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001819 printf("dabr = %.16lx dabrx = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001820 mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
1821#endif
1822}
1823
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001824static void dump_207_sprs(void)
1825{
1826#ifdef CONFIG_PPC64
1827 unsigned long msr;
1828
1829 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
1830 return;
1831
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001832 printf("dpdes = %.16lx tir = %.16lx cir = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001833 mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
1834
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001835 printf("fscr = %.16lx tar = %.16lx pspb = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001836 mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
1837
1838 msr = mfmsr();
1839 if (msr & MSR_TM) {
1840 /* Only if TM has been enabled in the kernel */
Balbir Singhc47a9402017-08-29 17:22:36 +10001841 printf("tfhar = %.16lx tfiar = %.16lx texasr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001842 mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
1843 mfspr(SPRN_TEXASR));
1844 }
1845
Balbir Singhc47a9402017-08-29 17:22:36 +10001846 printf("mmcr0 = %.16lx mmcr1 = %.16lx mmcr2 = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001847 mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001848 printf("pmc1 = %.8lx pmc2 = %.8lx pmc3 = %.8lx pmc4 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001849 mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
1850 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001851 printf("mmcra = %.16lx siar = %.16lx pmc5 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001852 mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001853 printf("sdar = %.16lx sier = %.16lx pmc6 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001854 mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
Balbir Singhc47a9402017-08-29 17:22:36 +10001855 printf("ebbhr = %.16lx ebbrr = %.16lx bescr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001856 mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001857 printf("iamr = %.16lx\n", mfspr(SPRN_IAMR));
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001858
1859 if (!(msr & MSR_HV))
1860 return;
1861
Balbir Singhc47a9402017-08-29 17:22:36 +10001862 printf("hfscr = %.16lx dhdes = %.16lx rpr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001863 mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001864 printf("dawr = %.16lx dawrx = %.16lx ciabr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001865 mfspr(SPRN_DAWR), mfspr(SPRN_DAWRX), mfspr(SPRN_CIABR));
1866#endif
1867}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868
Balbir Singhd1e1b352017-08-30 21:45:09 +10001869static void dump_300_sprs(void)
1870{
1871#ifdef CONFIG_PPC64
1872 bool hv = mfmsr() & MSR_HV;
1873
1874 if (!cpu_has_feature(CPU_FTR_ARCH_300))
1875 return;
1876
1877 printf("pidr = %.16lx tidr = %.16lx\n",
1878 mfspr(SPRN_PID), mfspr(SPRN_TIDR));
1879 printf("asdr = %.16lx psscr = %.16lx\n",
1880 mfspr(SPRN_ASDR), hv ? mfspr(SPRN_PSSCR)
1881 : mfspr(SPRN_PSSCR_PR));
1882
1883 if (!hv)
1884 return;
1885
1886 printf("ptcr = %.16lx\n",
1887 mfspr(SPRN_PTCR));
1888#endif
1889}
1890
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001891static void dump_one_spr(int spr, bool show_unimplemented)
1892{
1893 unsigned long val;
1894
1895 val = 0xdeadbeef;
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 == 0xdeadbeef) {
1902 /* Looks like read was a nop, confirm */
1903 val = 0x0badcafe;
1904 if (!read_spr(spr, &val)) {
1905 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1906 return;
1907 }
1908
1909 if (val == 0x0badcafe) {
1910 if (show_unimplemented)
1911 printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
1912 return;
1913 }
1914 }
1915
1916 printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
1917}
1918
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001919static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920{
Michael Ellerman13629da2016-07-07 22:54:27 +10001921 static unsigned long regno;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 int cmd;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001923 int spr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
1925 cmd = skipbl();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001926
1927 switch (cmd) {
1928 case '\n': {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001929 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 asm("mr %0,1" : "=r" (sp) :);
1931 asm("mr %0,2" : "=r" (toc) :);
1932
Michael Ellerman56346ad2016-07-07 22:54:28 +10001933 printf("msr = "REG" sprg0 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001934 mfmsr(), mfspr(SPRN_SPRG0));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001935 printf("pvr = "REG" sprg1 = "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001936 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001937 printf("dec = "REG" sprg2 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001938 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001939 printf("sp = "REG" sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
1940 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
1941
Michael Ellerman18461932016-07-07 22:54:29 +10001942 dump_206_sprs();
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001943 dump_207_sprs();
Balbir Singhd1e1b352017-08-30 21:45:09 +10001944 dump_300_sprs();
Michael Ellerman18461932016-07-07 22:54:29 +10001945
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 return;
1947 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001948 case 'w': {
1949 unsigned long val;
1950 scanhex(&regno);
1951 val = 0;
1952 read_spr(regno, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 scanhex(&val);
1954 write_spr(regno, val);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001955 dump_one_spr(regno, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001958 case 'r':
1959 scanhex(&regno);
1960 dump_one_spr(regno, true);
1961 break;
1962 case 'a':
1963 /* dump ALL SPRs */
1964 for (spr = 1; spr < 1024; ++spr)
1965 dump_one_spr(spr, false);
1966 break;
1967 }
1968
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 scannl();
1970}
1971
1972/*
1973 * Stuff for reading and writing memory safely
1974 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001975static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976mread(unsigned long adrs, void *buf, int size)
1977{
1978 volatile int n;
1979 char *p, *q;
1980
1981 n = 0;
1982 if (setjmp(bus_error_jmp) == 0) {
1983 catch_memory_errors = 1;
1984 sync();
1985 p = (char *)adrs;
1986 q = (char *)buf;
1987 switch (size) {
1988 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001989 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 break;
1991 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001992 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 break;
1994 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001995 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 break;
1997 default:
1998 for( ; n < size; ++n) {
1999 *q++ = *p++;
2000 sync();
2001 }
2002 }
2003 sync();
2004 /* wait a little while to see if we get a machine check */
2005 __delay(200);
2006 n = size;
2007 }
2008 catch_memory_errors = 0;
2009 return n;
2010}
2011
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002012static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013mwrite(unsigned long adrs, void *buf, int size)
2014{
2015 volatile int n;
2016 char *p, *q;
2017
2018 n = 0;
2019 if (setjmp(bus_error_jmp) == 0) {
2020 catch_memory_errors = 1;
2021 sync();
2022 p = (char *) adrs;
2023 q = (char *) buf;
2024 switch (size) {
2025 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002026 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 break;
2028 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002029 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 break;
2031 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002032 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 break;
2034 default:
2035 for ( ; n < size; ++n) {
2036 *p++ = *q++;
2037 sync();
2038 }
2039 }
2040 sync();
2041 /* wait a little while to see if we get a machine check */
2042 __delay(200);
2043 n = size;
2044 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10002045 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 }
2047 catch_memory_errors = 0;
2048 return n;
2049}
2050
2051static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002052static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053static char *fault_chars[] = { "--", "**", "##" };
2054
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002055static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002057 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 switch (TRAP(regs)) {
2059 case 0x200:
2060 fault_type = 0;
2061 break;
2062 case 0x300:
2063 case 0x380:
2064 fault_type = 1;
2065 break;
2066 default:
2067 fault_type = 2;
2068 }
2069
2070 longjmp(bus_error_jmp, 1);
2071
2072 return 0;
2073}
2074
2075#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
2076
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002077static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078byterev(unsigned char *val, int size)
2079{
2080 int t;
2081
2082 switch (size) {
2083 case 2:
2084 SWAP(val[0], val[1], t);
2085 break;
2086 case 4:
2087 SWAP(val[0], val[3], t);
2088 SWAP(val[1], val[2], t);
2089 break;
2090 case 8: /* is there really any use for this? */
2091 SWAP(val[0], val[7], t);
2092 SWAP(val[1], val[6], t);
2093 SWAP(val[2], val[5], t);
2094 SWAP(val[3], val[4], t);
2095 break;
2096 }
2097}
2098
2099static int brev;
2100static int mnoread;
2101
Michael Ellermane3bc8042012-08-23 22:09:13 +00002102static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 "Memory examine command usage:\n"
2104 "m [addr] [flags] examine/change memory\n"
2105 " addr is optional. will start where left off.\n"
2106 " flags may include chars from this set:\n"
2107 " b modify by bytes (default)\n"
2108 " w modify by words (2 byte)\n"
2109 " l modify by longs (4 byte)\n"
2110 " d modify by doubleword (8 byte)\n"
2111 " r toggle reverse byte order mode\n"
2112 " n do not read memory (for i/o spaces)\n"
2113 " . ok to read (default)\n"
2114 "NOTE: flags are saved as defaults\n"
2115 "";
2116
Michael Ellermane3bc8042012-08-23 22:09:13 +00002117static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 "Memory examine subcommands:\n"
2119 " hexval write this val to current location\n"
2120 " 'string' write chars from string to this location\n"
2121 " ' increment address\n"
2122 " ^ decrement address\n"
2123 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
2124 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
2125 " ` clear no-read flag\n"
2126 " ; stay at this addr\n"
2127 " v change to byte mode\n"
2128 " w change to word (2 byte) mode\n"
2129 " l change to long (4 byte) mode\n"
2130 " u change to doubleword (8 byte) mode\n"
2131 " m addr change current addr\n"
2132 " n toggle no-read flag\n"
2133 " r toggle byte reverse flag\n"
2134 " < count back up count bytes\n"
2135 " > count skip forward count bytes\n"
2136 " x exit this mode\n"
2137 "";
2138
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002139static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140memex(void)
2141{
2142 int cmd, inc, i, nslash;
2143 unsigned long n;
2144 unsigned char val[16];
2145
2146 scanhex((void *)&adrs);
2147 cmd = skipbl();
2148 if (cmd == '?') {
2149 printf(memex_help_string);
2150 return;
2151 } else {
2152 termch = cmd;
2153 }
2154 last_cmd = "m\n";
2155 while ((cmd = skipbl()) != '\n') {
2156 switch( cmd ){
2157 case 'b': size = 1; break;
2158 case 'w': size = 2; break;
2159 case 'l': size = 4; break;
2160 case 'd': size = 8; break;
2161 case 'r': brev = !brev; break;
2162 case 'n': mnoread = 1; break;
2163 case '.': mnoread = 0; break;
2164 }
2165 }
2166 if( size <= 0 )
2167 size = 1;
2168 else if( size > 8 )
2169 size = 8;
2170 for(;;){
2171 if (!mnoread)
2172 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002173 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 if (!mnoread) {
2175 if (brev)
2176 byterev(val, size);
2177 putchar(' ');
2178 for (i = 0; i < n; ++i)
2179 printf("%.2x", val[i]);
2180 for (; i < size; ++i)
2181 printf("%s", fault_chars[fault_type]);
2182 }
2183 putchar(' ');
2184 inc = size;
2185 nslash = 0;
2186 for(;;){
2187 if( scanhex(&n) ){
2188 for (i = 0; i < size; ++i)
2189 val[i] = n >> (i * 8);
2190 if (!brev)
2191 byterev(val, size);
2192 mwrite(adrs, val, size);
2193 inc = size;
2194 }
2195 cmd = skipbl();
2196 if (cmd == '\n')
2197 break;
2198 inc = 0;
2199 switch (cmd) {
2200 case '\'':
2201 for(;;){
2202 n = inchar();
2203 if( n == '\\' )
2204 n = bsesc();
2205 else if( n == '\'' )
2206 break;
2207 for (i = 0; i < size; ++i)
2208 val[i] = n >> (i * 8);
2209 if (!brev)
2210 byterev(val, size);
2211 mwrite(adrs, val, size);
2212 adrs += size;
2213 }
2214 adrs -= size;
2215 inc = size;
2216 break;
2217 case ',':
2218 adrs += size;
2219 break;
2220 case '.':
2221 mnoread = 0;
2222 break;
2223 case ';':
2224 break;
2225 case 'x':
2226 case EOF:
2227 scannl();
2228 return;
2229 case 'b':
2230 case 'v':
2231 size = 1;
2232 break;
2233 case 'w':
2234 size = 2;
2235 break;
2236 case 'l':
2237 size = 4;
2238 break;
2239 case 'u':
2240 size = 8;
2241 break;
2242 case '^':
2243 adrs -= size;
2244 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 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 '\\':
2254 if (nslash < 0)
2255 adrs += 1 << -nslash;
2256 else
2257 nslash = 0;
2258 nslash -= 4;
2259 adrs -= 1 << -nslash;
2260 break;
2261 case 'm':
2262 scanhex((void *)&adrs);
2263 break;
2264 case 'n':
2265 mnoread = 1;
2266 break;
2267 case 'r':
2268 brev = !brev;
2269 break;
2270 case '<':
2271 n = size;
2272 scanhex(&n);
2273 adrs -= n;
2274 break;
2275 case '>':
2276 n = size;
2277 scanhex(&n);
2278 adrs += n;
2279 break;
2280 case '?':
2281 printf(memex_subcmd_help_string);
2282 break;
2283 }
2284 }
2285 adrs += inc;
2286 }
2287}
2288
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002289static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290bsesc(void)
2291{
2292 int c;
2293
2294 c = inchar();
2295 switch( c ){
2296 case 'n': c = '\n'; break;
2297 case 'r': c = '\r'; break;
2298 case 'b': c = '\b'; break;
2299 case 't': c = '\t'; break;
2300 }
2301 return c;
2302}
2303
Olaf Hering7e5b5932006-03-08 20:40:28 +01002304static void xmon_rawdump (unsigned long adrs, long ndump)
2305{
2306 long n, m, r, nr;
2307 unsigned char temp[16];
2308
2309 for (n = ndump; n > 0;) {
2310 r = n < 16? n: 16;
2311 nr = mread(adrs, temp, r);
2312 adrs += nr;
2313 for (m = 0; m < r; ++m) {
2314 if (m < nr)
2315 printf("%.2x", temp[m]);
2316 else
2317 printf("%s", fault_chars[fault_type]);
2318 }
2319 n -= r;
2320 if (nr < r)
2321 break;
2322 }
2323 printf("\n");
2324}
2325
Breno Leitao4125d012017-08-02 17:14:05 -03002326static void dump_tracing(void)
2327{
2328 int c;
2329
2330 c = inchar();
2331 if (c == 'c')
2332 ftrace_dump(DUMP_ORIG);
2333 else
2334 ftrace_dump(DUMP_ALL);
Breno Leitao4125d012017-08-02 17:14:05 -03002335}
2336
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002337#ifdef CONFIG_PPC64
2338static void dump_one_paca(int cpu)
2339{
2340 struct paca_struct *p;
Michael Ellerman4e003742017-10-19 15:08:43 +11002341#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellermanad987fc2015-10-14 16:58:36 +11002342 int i = 0;
2343#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002344
2345 if (setjmp(bus_error_jmp) != 0) {
2346 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2347 return;
2348 }
2349
2350 catch_memory_errors = 1;
2351 sync();
2352
Nicholas Piggind2e60072018-02-14 01:08:12 +10002353 p = paca_ptrs[cpu];
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002354
Michael Ellermand8104182017-12-06 23:23:28 +11002355 printf("paca for cpu 0x%x @ %px:\n", cpu, p);
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002356
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002357 printf(" %-*s = %s\n", 25, "possible", cpu_possible(cpu) ? "yes" : "no");
2358 printf(" %-*s = %s\n", 25, "present", cpu_present(cpu) ? "yes" : "no");
2359 printf(" %-*s = %s\n", 25, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002360
Michael Ellerman66716832018-05-21 21:06:19 +10002361#define DUMP(paca, name, format) \
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002362 printf(" %-*s = "format"\t(0x%lx)\n", 25, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002363 offsetof(struct paca_struct, name));
2364
Michael Ellerman66716832018-05-21 21:06:19 +10002365 DUMP(p, lock_token, "%#-*x");
2366 DUMP(p, paca_index, "%#-*x");
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002367 DUMP(p, kernel_toc, "%#-*llx");
2368 DUMP(p, kernelbase, "%#-*llx");
2369 DUMP(p, kernel_msr, "%#-*llx");
Michael Ellerman66716832018-05-21 21:06:19 +10002370 DUMP(p, emergency_sp, "%-*px");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302371#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman66716832018-05-21 21:06:19 +10002372 DUMP(p, nmi_emergency_sp, "%-*px");
2373 DUMP(p, mc_emergency_sp, "%-*px");
2374 DUMP(p, in_nmi, "%#-*x");
2375 DUMP(p, in_mce, "%#-*x");
2376 DUMP(p, hmi_event_available, "%#-*x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302377#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002378 DUMP(p, data_offset, "%#-*llx");
Michael Ellerman66716832018-05-21 21:06:19 +10002379 DUMP(p, hw_cpu_id, "%#-*x");
2380 DUMP(p, cpu_start, "%#-*x");
2381 DUMP(p, kexec_state, "%#-*x");
Michael Ellerman4e003742017-10-19 15:08:43 +11002382#ifdef CONFIG_PPC_BOOK3S_64
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002383 if (!early_radix_enabled()) {
2384 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2385 u64 esid, vsid;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002386
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002387 if (!p->slb_shadow_ptr)
2388 continue;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002389
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002390 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2391 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
Michael Ellermanad987fc2015-10-14 16:58:36 +11002392
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002393 if (esid || vsid) {
2394 printf(" %-*s[%d] = 0x%016llx 0x%016llx\n",
2395 22, "slb_shadow", i, esid, vsid);
2396 }
Michael Ellermanad987fc2015-10-14 16:58:36 +11002397 }
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002398 DUMP(p, vmalloc_sllp, "%#-*x");
Nicholas Piggin126b11b2018-09-15 01:30:53 +10002399 DUMP(p, stab_rr, "%#-*x");
2400 DUMP(p, slb_used_bitmap, "%#-*x");
2401 DUMP(p, slb_kern_bitmap, "%#-*x");
Nicholas Piggin82d8f4c2018-09-15 01:30:50 +10002402
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002403 if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) {
2404 DUMP(p, slb_cache_ptr, "%#-*x");
2405 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2406 printf(" %-*s[%d] = 0x%016x\n",
2407 22, "slb_cache", i, p->slb_cache[i]);
2408 }
Nicholas Piggin82d8f4c2018-09-15 01:30:50 +10002409 }
Michael Ellerman274920a2018-01-10 23:49:12 +11002410
Michael Ellerman66716832018-05-21 21:06:19 +10002411 DUMP(p, rfi_flush_fallback_area, "%-*px");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002412#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002413 DUMP(p, dscr_default, "%#-*llx");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002414#ifdef CONFIG_PPC_BOOK3E
Michael Ellerman66716832018-05-21 21:06:19 +10002415 DUMP(p, pgd, "%-*px");
2416 DUMP(p, kernel_pgd, "%-*px");
2417 DUMP(p, tcd_ptr, "%-*px");
2418 DUMP(p, mc_kstack, "%-*px");
2419 DUMP(p, crit_kstack, "%-*px");
2420 DUMP(p, dbg_kstack, "%-*px");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002421#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002422 DUMP(p, __current, "%-*px");
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002423 DUMP(p, kstack, "%#-*llx");
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002424 printf(" %-*s = 0x%016llx\n", 25, "kstack_base", p->kstack & ~(THREAD_SIZE - 1));
Michael Ellerman50530f52018-10-12 13:58:52 +11002425#ifdef CONFIG_STACKPROTECTOR
2426 DUMP(p, canary, "%#-*lx");
2427#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002428 DUMP(p, saved_r1, "%#-*llx");
Michael Ellerman66716832018-05-21 21:06:19 +10002429 DUMP(p, trap_save, "%#-*x");
2430 DUMP(p, irq_soft_mask, "%#-*x");
2431 DUMP(p, irq_happened, "%#-*x");
2432 DUMP(p, io_sync, "%#-*x");
2433 DUMP(p, irq_work_pending, "%#-*x");
2434 DUMP(p, nap_state_lost, "%#-*x");
2435 DUMP(p, sprg_vdso, "%#-*llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002436
Michael Ellermanad987fc2015-10-14 16:58:36 +11002437#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
Michael Ellerman66716832018-05-21 21:06:19 +10002438 DUMP(p, tm_scratch, "%#-*llx");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002439#endif
2440
2441#ifdef CONFIG_PPC_POWERNV
Michael Ellerman66716832018-05-21 21:06:19 +10002442 DUMP(p, core_idle_state_ptr, "%-*px");
2443 DUMP(p, thread_idle_state, "%#-*x");
2444 DUMP(p, thread_mask, "%#-*x");
2445 DUMP(p, subcore_sibling_mask, "%#-*x");
Michael Ellerman2e0986d2018-05-21 19:47:20 +10002446 DUMP(p, requested_psscr, "%#-*llx");
2447 DUMP(p, stop_sprs.pid, "%#-*llx");
2448 DUMP(p, stop_sprs.ldbar, "%#-*llx");
2449 DUMP(p, stop_sprs.fscr, "%#-*llx");
2450 DUMP(p, stop_sprs.hfscr, "%#-*llx");
2451 DUMP(p, stop_sprs.mmcr1, "%#-*llx");
2452 DUMP(p, stop_sprs.mmcr2, "%#-*llx");
2453 DUMP(p, stop_sprs.mmcra, "%#-*llx");
2454 DUMP(p, dont_stop.counter, "%#-*x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002455#endif
2456
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002457 DUMP(p, accounting.utime, "%#-*lx");
2458 DUMP(p, accounting.stime, "%#-*lx");
Christophe Leroyabcff862018-08-02 07:53:59 +00002459#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002460 DUMP(p, accounting.utime_scaled, "%#-*lx");
Christophe Leroyabcff862018-08-02 07:53:59 +00002461#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002462 DUMP(p, accounting.starttime, "%#-*lx");
2463 DUMP(p, accounting.starttime_user, "%#-*lx");
Christophe Leroyabcff862018-08-02 07:53:59 +00002464#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002465 DUMP(p, accounting.startspurr, "%#-*lx");
2466 DUMP(p, accounting.utime_sspurr, "%#-*lx");
Christophe Leroyabcff862018-08-02 07:53:59 +00002467#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002468 DUMP(p, accounting.steal_time, "%#-*lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002469#undef DUMP
2470
2471 catch_memory_errors = 0;
2472 sync();
2473}
2474
2475static void dump_all_pacas(void)
2476{
2477 int cpu;
2478
2479 if (num_possible_cpus() == 0) {
2480 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2481 return;
2482 }
2483
2484 for_each_possible_cpu(cpu)
2485 dump_one_paca(cpu);
2486}
2487
2488static void dump_pacas(void)
2489{
2490 unsigned long num;
2491 int c;
2492
2493 c = inchar();
2494 if (c == 'a') {
2495 dump_all_pacas();
2496 return;
2497 }
2498
2499 termch = c; /* Put c back, it wasn't 'a' */
2500
2501 if (scanhex(&num))
2502 dump_one_paca(num);
2503 else
2504 dump_one_paca(xmon_owner);
2505}
2506#endif
2507
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002508#ifdef CONFIG_PPC_POWERNV
2509static void dump_one_xive(int cpu)
2510{
2511 unsigned int hwid = get_hard_smp_processor_id(cpu);
2512
2513 opal_xive_dump(XIVE_DUMP_TM_HYP, hwid);
2514 opal_xive_dump(XIVE_DUMP_TM_POOL, hwid);
2515 opal_xive_dump(XIVE_DUMP_TM_OS, hwid);
2516 opal_xive_dump(XIVE_DUMP_TM_USER, hwid);
2517 opal_xive_dump(XIVE_DUMP_VP, hwid);
2518 opal_xive_dump(XIVE_DUMP_EMU_STATE, hwid);
2519
2520 if (setjmp(bus_error_jmp) != 0) {
2521 catch_memory_errors = 0;
2522 printf("*** Error dumping xive on cpu %d\n", cpu);
2523 return;
2524 }
2525
2526 catch_memory_errors = 1;
2527 sync();
2528 xmon_xive_do_dump(cpu);
2529 sync();
2530 __delay(200);
2531 catch_memory_errors = 0;
2532}
2533
2534static void dump_all_xives(void)
2535{
2536 int cpu;
2537
2538 if (num_possible_cpus() == 0) {
2539 printf("No possible cpus, use 'dx #' to dump individual cpus\n");
2540 return;
2541 }
2542
2543 for_each_possible_cpu(cpu)
2544 dump_one_xive(cpu);
2545}
2546
2547static void dump_one_xive_irq(u32 num)
2548{
2549 s64 rc;
2550 __be64 vp;
2551 u8 prio;
2552 __be32 lirq;
2553
2554 rc = opal_xive_get_irq_config(num, &vp, &prio, &lirq);
2555 xmon_printf("IRQ 0x%x config: vp=0x%llx prio=%d lirq=0x%x (rc=%lld)\n",
2556 num, be64_to_cpu(vp), prio, be32_to_cpu(lirq), rc);
2557}
2558
2559static void dump_xives(void)
2560{
2561 unsigned long num;
2562 int c;
2563
Breno Leitao402e1722017-10-17 16:20:18 -02002564 if (!xive_enabled()) {
2565 printf("Xive disabled on this system\n");
2566 return;
2567 }
2568
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002569 c = inchar();
2570 if (c == 'a') {
2571 dump_all_xives();
2572 return;
2573 } else if (c == 'i') {
2574 if (scanhex(&num))
2575 dump_one_xive_irq(num);
2576 return;
2577 }
2578
2579 termch = c; /* Put c back, it wasn't 'a' */
2580
2581 if (scanhex(&num))
2582 dump_one_xive(num);
2583 else
2584 dump_one_xive(xmon_owner);
2585}
2586#endif /* CONFIG_PPC_POWERNV */
2587
Douglas Miller5e48dc02017-02-07 07:40:44 -06002588static void dump_by_size(unsigned long addr, long count, int size)
2589{
2590 unsigned char temp[16];
2591 int i, j;
2592 u64 val;
2593
2594 count = ALIGN(count, 16);
2595
2596 for (i = 0; i < count; i += 16, addr += 16) {
2597 printf(REG, addr);
2598
2599 if (mread(addr, temp, 16) != 16) {
2600 printf("\nFaulted reading %d bytes from 0x"REG"\n", 16, addr);
2601 return;
2602 }
2603
2604 for (j = 0; j < 16; j += size) {
2605 putchar(' ');
2606 switch (size) {
2607 case 1: val = temp[j]; break;
2608 case 2: val = *(u16 *)&temp[j]; break;
2609 case 4: val = *(u32 *)&temp[j]; break;
2610 case 8: val = *(u64 *)&temp[j]; break;
2611 default: val = 0;
2612 }
2613
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002614 printf("%0*llx", size * 2, val);
Douglas Miller5e48dc02017-02-07 07:40:44 -06002615 }
2616 printf("\n");
2617 }
2618}
2619
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002620static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621dump(void)
2622{
Douglas Miller5e48dc02017-02-07 07:40:44 -06002623 static char last[] = { "d?\n" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 int c;
2625
2626 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002627
2628#ifdef CONFIG_PPC64
2629 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002630 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002631 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002632 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002633 return;
2634 }
2635#endif
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002636#ifdef CONFIG_PPC_POWERNV
2637 if (c == 'x') {
2638 xmon_start_pagination();
2639 dump_xives();
2640 xmon_end_pagination();
2641 return;
2642 }
2643#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002644
Breno Leitao4125d012017-08-02 17:14:05 -03002645 if (c == 't') {
2646 dump_tracing();
2647 return;
2648 }
2649
Douglas Miller5e48dc02017-02-07 07:40:44 -06002650 if (c == '\n')
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 termch = c;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002652
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 scanhex((void *)&adrs);
2654 if (termch != '\n')
2655 termch = 0;
2656 if (c == 'i') {
2657 scanhex(&nidump);
2658 if (nidump == 0)
2659 nidump = 16;
2660 else if (nidump > MAX_DUMP)
2661 nidump = MAX_DUMP;
2662 adrs += ppc_inst_dump(adrs, nidump, 1);
2663 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002664 } else if (c == 'l') {
2665 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002666 } else if (c == 'o') {
2667 dump_opal_msglog();
Balbir Singh80eff6c2017-10-30 22:01:12 +11002668 } else if (c == 'v') {
2669 /* dump virtual to physical translation */
2670 show_pte(adrs);
Olaf Hering7e5b5932006-03-08 20:40:28 +01002671 } else if (c == 'r') {
2672 scanhex(&ndump);
2673 if (ndump == 0)
2674 ndump = 64;
2675 xmon_rawdump(adrs, ndump);
2676 adrs += ndump;
2677 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 } else {
2679 scanhex(&ndump);
2680 if (ndump == 0)
2681 ndump = 64;
2682 else if (ndump > MAX_DUMP)
2683 ndump = MAX_DUMP;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002684
2685 switch (c) {
2686 case '8':
2687 case '4':
2688 case '2':
2689 case '1':
2690 ndump = ALIGN(ndump, 16);
2691 dump_by_size(adrs, ndump, c - '0');
2692 last[1] = c;
2693 last_cmd = last;
2694 break;
2695 default:
2696 prdump(adrs, ndump);
2697 last_cmd = "d\n";
2698 }
2699
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 adrs += ndump;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 }
2702}
2703
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002704static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705prdump(unsigned long adrs, long ndump)
2706{
2707 long n, m, c, r, nr;
2708 unsigned char temp[16];
2709
2710 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002711 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 putchar(' ');
2713 r = n < 16? n: 16;
2714 nr = mread(adrs, temp, r);
2715 adrs += nr;
2716 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002717 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002718 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 if (m < nr)
2720 printf("%.2x", temp[m]);
2721 else
2722 printf("%s", fault_chars[fault_type]);
2723 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002724 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002725 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002726 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 printf(" |");
2730 for (m = 0; m < r; ++m) {
2731 if (m < nr) {
2732 c = temp[m];
2733 putchar(' ' <= c && c <= '~'? c: '.');
2734 } else
2735 putchar(' ');
2736 }
2737 n -= r;
2738 for (; m < 16; ++m)
2739 putchar(' ');
2740 printf("|\n");
2741 if (nr < r)
2742 break;
2743 }
2744}
2745
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002746typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2747
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002748static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002749generic_inst_dump(unsigned long adr, long count, int praddr,
2750 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751{
2752 int nr, dotted;
2753 unsigned long first_adr;
Michael Ellerman941d8102018-07-16 23:52:14 +10002754 unsigned int inst, last_inst = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 unsigned char val[4];
2756
2757 dotted = 0;
2758 for (first_adr = adr; count > 0; --count, adr += 4) {
2759 nr = mread(adr, val, 4);
2760 if (nr == 0) {
2761 if (praddr) {
2762 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002763 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 }
2765 break;
2766 }
2767 inst = GETWORD(val);
2768 if (adr > first_adr && inst == last_inst) {
2769 if (!dotted) {
2770 printf(" ...\n");
2771 dotted = 1;
2772 }
2773 continue;
2774 }
2775 dotted = 0;
2776 last_inst = inst;
2777 if (praddr)
Michael Ellerman941d8102018-07-16 23:52:14 +10002778 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002780 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 printf("\n");
2782 }
2783 return adr - first_adr;
2784}
2785
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002786static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002787ppc_inst_dump(unsigned long adr, long count, int praddr)
2788{
2789 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2790}
2791
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792void
2793print_address(unsigned long addr)
2794{
2795 xmon_print_symbol(addr, "\t# ", "");
2796}
2797
Breno Leitaoe3a83792018-10-22 11:54:16 -03002798static void
Vinay Sridharf312deb2009-05-14 23:13:07 +00002799dump_log_buf(void)
2800{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002801 struct kmsg_dumper dumper = { .active = 1 };
2802 unsigned char buf[128];
2803 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002804
Michael Ellermane3bc8042012-08-23 22:09:13 +00002805 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002806 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002807 return;
2808 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002809
Michael Ellermane3bc8042012-08-23 22:09:13 +00002810 catch_memory_errors = 1;
2811 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002812
Michael Ellermanca5dd392012-08-23 22:09:12 +00002813 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002814 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002815 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2816 buf[len] = '\0';
2817 printf("%s", buf);
2818 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002819 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002820
Michael Ellermane3bc8042012-08-23 22:09:13 +00002821 sync();
2822 /* wait a little while to see if we get a machine check */
2823 __delay(200);
2824 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002825}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002827#ifdef CONFIG_PPC_POWERNV
2828static void dump_opal_msglog(void)
2829{
2830 unsigned char buf[128];
2831 ssize_t res;
2832 loff_t pos = 0;
2833
2834 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2835 printf("Machine is not running OPAL firmware.\n");
2836 return;
2837 }
2838
2839 if (setjmp(bus_error_jmp) != 0) {
2840 printf("Error dumping OPAL msglog!\n");
2841 return;
2842 }
2843
2844 catch_memory_errors = 1;
2845 sync();
2846
2847 xmon_start_pagination();
2848 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2849 if (res < 0) {
2850 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2851 break;
2852 }
2853 buf[res] = '\0';
2854 printf("%s", buf);
2855 pos += res;
2856 }
2857 xmon_end_pagination();
2858
2859 sync();
2860 /* wait a little while to see if we get a machine check */
2861 __delay(200);
2862 catch_memory_errors = 0;
2863}
2864#endif
2865
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866/*
2867 * Memory operations - move, set, print differences
2868 */
2869static unsigned long mdest; /* destination address */
2870static unsigned long msrc; /* source address */
2871static unsigned long mval; /* byte value to set memory to */
2872static unsigned long mcount; /* # bytes to affect */
2873static unsigned long mdiffs; /* max # differences to print */
2874
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002875static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876memops(int cmd)
2877{
2878 scanhex((void *)&mdest);
2879 if( termch != '\n' )
2880 termch = 0;
2881 scanhex((void *)(cmd == 's'? &mval: &msrc));
2882 if( termch != '\n' )
2883 termch = 0;
2884 scanhex((void *)&mcount);
2885 switch( cmd ){
2886 case 'm':
2887 memmove((void *)mdest, (void *)msrc, mcount);
2888 break;
2889 case 's':
2890 memset((void *)mdest, mval, mcount);
2891 break;
2892 case 'd':
2893 if( termch != '\n' )
2894 termch = 0;
2895 scanhex((void *)&mdiffs);
2896 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2897 break;
2898 }
2899}
2900
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002901static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2903{
2904 unsigned n, prt;
2905
2906 prt = 0;
2907 for( n = nb; n > 0; --n )
2908 if( *p1++ != *p2++ )
2909 if( ++prt <= maxpr )
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002910 printf("%px %.2x # %px %.2x\n", p1 - 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 p1[-1], p2 - 1, p2[-1]);
2912 if( prt > maxpr )
2913 printf("Total of %d differences\n", prt);
2914}
2915
2916static unsigned mend;
2917static unsigned mask;
2918
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002919static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920memlocate(void)
2921{
2922 unsigned a, n;
2923 unsigned char val[4];
2924
2925 last_cmd = "ml";
2926 scanhex((void *)&mdest);
2927 if (termch != '\n') {
2928 termch = 0;
2929 scanhex((void *)&mend);
2930 if (termch != '\n') {
2931 termch = 0;
2932 scanhex((void *)&mval);
2933 mask = ~0;
2934 if (termch != '\n') termch = 0;
2935 scanhex((void *)&mask);
2936 }
2937 }
2938 n = 0;
2939 for (a = mdest; a < mend; a += 4) {
2940 if (mread(a, val, 4) == 4
2941 && ((GETWORD(val) ^ mval) & mask) == 0) {
2942 printf("%.16x: %.16x\n", a, GETWORD(val));
2943 if (++n >= 10)
2944 break;
2945 }
2946 }
2947}
2948
2949static unsigned long mskip = 0x1000;
2950static unsigned long mlim = 0xffffffff;
2951
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002952static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953memzcan(void)
2954{
2955 unsigned char v;
2956 unsigned a;
2957 int ok, ook;
2958
2959 scanhex(&mdest);
2960 if (termch != '\n') termch = 0;
2961 scanhex(&mskip);
2962 if (termch != '\n') termch = 0;
2963 scanhex(&mlim);
2964 ook = 0;
2965 for (a = mdest; a < mlim; a += mskip) {
2966 ok = mread(a, &v, 1);
2967 if (ok && !ook) {
2968 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 } else if (!ok && ook)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002970 printf("%.8lx\n", a - mskip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 ook = ok;
2972 if (a + mskip < a)
2973 break;
2974 }
2975 if (ook)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002976 printf("%.8lx\n", a - mskip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977}
2978
Douglas Miller6dfb5402015-11-23 09:01:15 -06002979static void show_task(struct task_struct *tsk)
2980{
2981 char state;
2982
2983 /*
2984 * Cloned from kdb_task_state_char(), which is not entirely
2985 * appropriate for calling from xmon. This could be moved
2986 * to a common, generic, routine used by both.
2987 */
2988 state = (tsk->state == 0) ? 'R' :
2989 (tsk->state < 0) ? 'U' :
2990 (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
2991 (tsk->state & TASK_STOPPED) ? 'T' :
2992 (tsk->state & TASK_TRACED) ? 'C' :
2993 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
2994 (tsk->exit_state & EXIT_DEAD) ? 'E' :
2995 (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
2996
Michael Ellermand8104182017-12-06 23:23:28 +11002997 printf("%px %016lx %6d %6d %c %2d %s\n", tsk,
Douglas Miller6dfb5402015-11-23 09:01:15 -06002998 tsk->thread.ksp,
Breno Leitaoe3a83792018-10-22 11:54:16 -03002999 tsk->pid, rcu_dereference(tsk->parent)->pid,
Christophe Leroy05486082019-01-31 10:08:50 +00003000 state, task_cpu(tsk),
Douglas Miller6dfb5402015-11-23 09:01:15 -06003001 tsk->comm);
3002}
3003
Balbir Singh80eff6c2017-10-30 22:01:12 +11003004#ifdef CONFIG_PPC_BOOK3S_64
Breno Leitaoe3a83792018-10-22 11:54:16 -03003005static void format_pte(void *ptep, unsigned long pte)
Balbir Singh80eff6c2017-10-30 22:01:12 +11003006{
Christophe Leroy26973fa2018-10-09 13:51:56 +00003007 pte_t entry = __pte(pte);
3008
Balbir Singh80eff6c2017-10-30 22:01:12 +11003009 printf("ptep @ 0x%016lx = 0x%016lx\n", (unsigned long)ptep, pte);
3010 printf("Maps physical address = 0x%016lx\n", pte & PTE_RPN_MASK);
3011
3012 printf("Flags = %s%s%s%s%s\n",
Christophe Leroy26973fa2018-10-09 13:51:56 +00003013 pte_young(entry) ? "Accessed " : "",
3014 pte_dirty(entry) ? "Dirty " : "",
3015 pte_read(entry) ? "Read " : "",
3016 pte_write(entry) ? "Write " : "",
3017 pte_exec(entry) ? "Exec " : "");
Balbir Singh80eff6c2017-10-30 22:01:12 +11003018}
3019
3020static void show_pte(unsigned long addr)
3021{
3022 unsigned long tskv = 0;
3023 struct task_struct *tsk = NULL;
3024 struct mm_struct *mm;
3025 pgd_t *pgdp, *pgdir;
3026 pud_t *pudp;
3027 pmd_t *pmdp;
3028 pte_t *ptep;
3029
3030 if (!scanhex(&tskv))
3031 mm = &init_mm;
3032 else
3033 tsk = (struct task_struct *)tskv;
3034
3035 if (tsk == NULL)
3036 mm = &init_mm;
3037 else
3038 mm = tsk->active_mm;
3039
3040 if (setjmp(bus_error_jmp) != 0) {
3041 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11003042 printf("*** Error dumping pte for task %px\n", tsk);
Balbir Singh80eff6c2017-10-30 22:01:12 +11003043 return;
3044 }
3045
3046 catch_memory_errors = 1;
3047 sync();
3048
3049 if (mm == &init_mm) {
3050 pgdp = pgd_offset_k(addr);
3051 pgdir = pgd_offset_k(0);
3052 } else {
3053 pgdp = pgd_offset(mm, addr);
3054 pgdir = pgd_offset(mm, 0);
3055 }
3056
3057 if (pgd_none(*pgdp)) {
3058 printf("no linux page table for address\n");
3059 return;
3060 }
3061
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003062 printf("pgd @ 0x%px\n", pgdir);
Balbir Singh80eff6c2017-10-30 22:01:12 +11003063
3064 if (pgd_huge(*pgdp)) {
3065 format_pte(pgdp, pgd_val(*pgdp));
3066 return;
3067 }
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003068 printf("pgdp @ 0x%px = 0x%016lx\n", pgdp, pgd_val(*pgdp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003069
3070 pudp = pud_offset(pgdp, addr);
3071
3072 if (pud_none(*pudp)) {
3073 printf("No valid PUD\n");
3074 return;
3075 }
3076
3077 if (pud_huge(*pudp)) {
3078 format_pte(pudp, pud_val(*pudp));
3079 return;
3080 }
3081
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003082 printf("pudp @ 0x%px = 0x%016lx\n", pudp, pud_val(*pudp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003083
3084 pmdp = pmd_offset(pudp, addr);
3085
3086 if (pmd_none(*pmdp)) {
3087 printf("No valid PMD\n");
3088 return;
3089 }
3090
3091 if (pmd_huge(*pmdp)) {
3092 format_pte(pmdp, pmd_val(*pmdp));
3093 return;
3094 }
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003095 printf("pmdp @ 0x%px = 0x%016lx\n", pmdp, pmd_val(*pmdp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003096
3097 ptep = pte_offset_map(pmdp, addr);
3098 if (pte_none(*ptep)) {
3099 printf("no valid PTE\n");
3100 return;
3101 }
3102
3103 format_pte(ptep, pte_val(*ptep));
3104
3105 sync();
3106 __delay(200);
3107 catch_memory_errors = 0;
3108}
3109#else
3110static void show_pte(unsigned long addr)
3111{
3112 printf("show_pte not yet implemented\n");
3113}
3114#endif /* CONFIG_PPC_BOOK3S_64 */
3115
Douglas Miller6dfb5402015-11-23 09:01:15 -06003116static void show_tasks(void)
3117{
3118 unsigned long tskv;
3119 struct task_struct *tsk = NULL;
3120
3121 printf(" task_struct ->thread.ksp PID PPID S P CMD\n");
3122
3123 if (scanhex(&tskv))
3124 tsk = (struct task_struct *)tskv;
3125
3126 if (setjmp(bus_error_jmp) != 0) {
3127 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11003128 printf("*** Error dumping task %px\n", tsk);
Douglas Miller6dfb5402015-11-23 09:01:15 -06003129 return;
3130 }
3131
3132 catch_memory_errors = 1;
3133 sync();
3134
3135 if (tsk)
3136 show_task(tsk);
3137 else
3138 for_each_process(tsk)
3139 show_task(tsk);
3140
3141 sync();
3142 __delay(200);
3143 catch_memory_errors = 0;
3144}
3145
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003146static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003147{
3148 unsigned long args[8];
3149 unsigned long ret;
3150 int i;
3151 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
3152 unsigned long, unsigned long, unsigned long,
3153 unsigned long, unsigned long, unsigned long);
3154 callfunc_t func;
3155
3156 if (!scanhex(&adrs))
3157 return;
3158 if (termch != '\n')
3159 termch = 0;
3160 for (i = 0; i < 8; ++i)
3161 args[i] = 0;
3162 for (i = 0; i < 8; ++i) {
3163 if (!scanhex(&args[i]) || termch == '\n')
3164 break;
3165 termch = 0;
3166 }
3167 func = (callfunc_t) adrs;
3168 ret = 0;
3169 if (setjmp(bus_error_jmp) == 0) {
3170 catch_memory_errors = 1;
3171 sync();
3172 ret = func(args[0], args[1], args[2], args[3],
3173 args[4], args[5], args[6], args[7]);
3174 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10003175 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003176 } else {
3177 printf("*** %x exception occurred\n", fault_except);
3178 }
3179 catch_memory_errors = 0;
3180}
3181
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182/* Input scanning routines */
3183int
3184skipbl(void)
3185{
3186 int c;
3187
3188 if( termch != 0 ){
3189 c = termch;
3190 termch = 0;
3191 } else
3192 c = inchar();
3193 while( c == ' ' || c == '\t' )
3194 c = inchar();
3195 return c;
3196}
3197
3198#define N_PTREGS 44
Yisheng Xie0abbf2b2018-05-31 19:11:25 +08003199static const char *regnames[N_PTREGS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
3201 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
3202 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
3203 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003204 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
3205#ifdef CONFIG_PPC64
3206 "softe",
3207#else
3208 "mq",
3209#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 "trap", "dar", "dsisr", "res"
3211};
3212
3213int
3214scanhex(unsigned long *vp)
3215{
3216 int c, d;
3217 unsigned long v;
3218
3219 c = skipbl();
3220 if (c == '%') {
3221 /* parse register name */
3222 char regname[8];
3223 int i;
3224
3225 for (i = 0; i < sizeof(regname) - 1; ++i) {
3226 c = inchar();
3227 if (!isalnum(c)) {
3228 termch = c;
3229 break;
3230 }
3231 regname[i] = c;
3232 }
3233 regname[i] = 0;
Yisheng Xie0abbf2b2018-05-31 19:11:25 +08003234 i = match_string(regnames, N_PTREGS, regname);
3235 if (i < 0) {
3236 printf("invalid register name '%%%s'\n", regname);
3237 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 }
Yisheng Xie0abbf2b2018-05-31 19:11:25 +08003239 if (xmon_regs == NULL) {
3240 printf("regs not available\n");
3241 return 0;
3242 }
3243 *vp = ((unsigned long *)xmon_regs)[i];
3244 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 }
3246
3247 /* skip leading "0x" if any */
3248
3249 if (c == '0') {
3250 c = inchar();
3251 if (c == 'x') {
3252 c = inchar();
3253 } else {
3254 d = hexdigit(c);
3255 if (d == EOF) {
3256 termch = c;
3257 *vp = 0;
3258 return 1;
3259 }
3260 }
3261 } else if (c == '$') {
3262 int i;
3263 for (i=0; i<63; i++) {
3264 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02003265 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 termch = c;
3267 break;
3268 }
3269 tmpstr[i] = c;
3270 }
3271 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07003272 *vp = 0;
3273 if (setjmp(bus_error_jmp) == 0) {
3274 catch_memory_errors = 1;
3275 sync();
3276 *vp = kallsyms_lookup_name(tmpstr);
3277 sync();
3278 }
3279 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 if (!(*vp)) {
3281 printf("unknown symbol '%s'\n", tmpstr);
3282 return 0;
3283 }
3284 return 1;
3285 }
3286
3287 d = hexdigit(c);
3288 if (d == EOF) {
3289 termch = c;
3290 return 0;
3291 }
3292 v = 0;
3293 do {
3294 v = (v << 4) + d;
3295 c = inchar();
3296 d = hexdigit(c);
3297 } while (d != EOF);
3298 termch = c;
3299 *vp = v;
3300 return 1;
3301}
3302
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003303static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304scannl(void)
3305{
3306 int c;
3307
3308 c = termch;
3309 termch = 0;
3310 while( c != '\n' )
3311 c = inchar();
3312}
3313
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003314static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315{
3316 if( '0' <= c && c <= '9' )
3317 return c - '0';
3318 if( 'A' <= c && c <= 'F' )
3319 return c - ('A' - 10);
3320 if( 'a' <= c && c <= 'f' )
3321 return c - ('a' - 10);
3322 return EOF;
3323}
3324
3325void
3326getstring(char *s, int size)
3327{
3328 int c;
3329
3330 c = skipbl();
3331 do {
3332 if( size > 1 ){
3333 *s++ = c;
3334 --size;
3335 }
3336 c = inchar();
3337 } while( c != ' ' && c != '\t' && c != '\n' );
3338 termch = c;
3339 *s = 0;
3340}
3341
3342static char line[256];
3343static char *lineptr;
3344
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003345static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346flush_input(void)
3347{
3348 lineptr = NULL;
3349}
3350
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003351static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352inchar(void)
3353{
3354 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003355 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 lineptr = NULL;
3357 return EOF;
3358 }
3359 lineptr = line;
3360 }
3361 return *lineptr++;
3362}
3363
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003364static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365take_input(char *str)
3366{
3367 lineptr = str;
3368}
3369
3370
3371static void
3372symbol_lookup(void)
3373{
3374 int type = inchar();
Boqun Feng302c7b02016-11-22 17:20:09 +08003375 unsigned long addr, cpu;
3376 void __percpu *ptr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 static char tmp[64];
3378
3379 switch (type) {
3380 case 'a':
3381 if (scanhex(&addr))
3382 xmon_print_symbol(addr, ": ", "\n");
3383 termch = 0;
3384 break;
3385 case 's':
3386 getstring(tmp, 64);
3387 if (setjmp(bus_error_jmp) == 0) {
3388 catch_memory_errors = 1;
3389 sync();
3390 addr = kallsyms_lookup_name(tmp);
3391 if (addr)
3392 printf("%s: %lx\n", tmp, addr);
3393 else
3394 printf("Symbol '%s' not found.\n", tmp);
3395 sync();
3396 }
3397 catch_memory_errors = 0;
3398 termch = 0;
3399 break;
Boqun Feng302c7b02016-11-22 17:20:09 +08003400 case 'p':
3401 getstring(tmp, 64);
3402 if (setjmp(bus_error_jmp) == 0) {
3403 catch_memory_errors = 1;
3404 sync();
3405 ptr = (void __percpu *)kallsyms_lookup_name(tmp);
3406 sync();
3407 }
3408
3409 if (ptr &&
3410 ptr >= (void __percpu *)__per_cpu_start &&
3411 ptr < (void __percpu *)__per_cpu_end)
3412 {
3413 if (scanhex(&cpu) && cpu < num_possible_cpus()) {
3414 addr = (unsigned long)per_cpu_ptr(ptr, cpu);
3415 } else {
3416 cpu = raw_smp_processor_id();
3417 addr = (unsigned long)this_cpu_ptr(ptr);
3418 }
3419
3420 printf("%s for cpu 0x%lx: %lx\n", tmp, cpu, addr);
3421 } else {
3422 printf("Percpu symbol '%s' not found.\n", tmp);
3423 }
3424
3425 catch_memory_errors = 0;
3426 termch = 0;
3427 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 }
3429}
3430
3431
3432/* Print an address in numeric and symbolic form (if possible) */
3433static void xmon_print_symbol(unsigned long address, const char *mid,
3434 const char *after)
3435{
3436 char *modname;
3437 const char *name = NULL;
3438 unsigned long offset, size;
3439
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003440 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 if (setjmp(bus_error_jmp) == 0) {
3442 catch_memory_errors = 1;
3443 sync();
3444 name = kallsyms_lookup(address, &size, &offset, &modname,
3445 tmpstr);
3446 sync();
3447 /* wait a little while to see if we get a machine check */
3448 __delay(200);
3449 }
3450
3451 catch_memory_errors = 0;
3452
3453 if (name) {
3454 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
3455 if (modname)
3456 printf(" [%s]", modname);
3457 }
3458 printf("%s", after);
3459}
3460
Michael Ellerman4e003742017-10-19 15:08:43 +11003461#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10003462void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463{
3464 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05303465 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11003466 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467
Michael Ellerman736256e2014-05-26 21:02:14 +10003468 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469
Michael Neuling584f8b72007-12-06 17:24:48 +11003470 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11003471 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
3472 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Michael Ellerman85673642017-04-24 10:35:14 +10003473
3474 if (!esid && !vsid)
3475 continue;
3476
3477 printf("%02d %016lx %016lx", i, esid, vsid);
3478
3479 if (!(esid & SLB_ESID_V)) {
3480 printf("\n");
3481 continue;
3482 }
3483
3484 llp = vsid & SLB_VSID_LLP;
3485 if (vsid & SLB_VSID_B_1T) {
3486 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
3487 GET_ESID_1T(esid),
3488 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
3489 llp);
3490 } else {
3491 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
3492 GET_ESID(esid),
3493 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
3494 llp);
will schmidtb3b95952007-12-07 08:22:23 +11003495 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 }
3497}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003498#endif
3499
Christophe Leroy68289ae2018-11-17 10:25:02 +00003500#ifdef CONFIG_PPC_BOOK3S_32
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003501void dump_segments(void)
3502{
3503 int i;
3504
3505 printf("sr0-15 =");
3506 for (i = 0; i < 16; ++i)
Christophe Leroy32c8c4c2018-11-16 17:31:08 +00003507 printf(" %x", mfsrin(i << 28));
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003508 printf("\n");
3509}
3510#endif
3511
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003512#ifdef CONFIG_44x
3513static void dump_tlb_44x(void)
3514{
3515 int i;
3516
3517 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
3518 unsigned long w0,w1,w2;
3519 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
3520 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
3521 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003522 printf("[%02x] %08lx %08lx %08lx ", i, w0, w1, w2);
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003523 if (w0 & PPC44x_TLB_VALID) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003524 printf("V %08lx -> %01lx%08lx %c%c%c%c%c",
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003525 w0 & PPC44x_TLB_EPN_MASK,
3526 w1 & PPC44x_TLB_ERPN_MASK,
3527 w1 & PPC44x_TLB_RPN_MASK,
3528 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
3529 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
3530 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
3531 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
3532 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
3533 }
3534 printf("\n");
3535 }
3536}
3537#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003538
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10003539#ifdef CONFIG_PPC_BOOK3E
3540static void dump_tlb_book3e(void)
3541{
3542 u32 mmucfg, pidmask, lpidmask;
3543 u64 ramask;
3544 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3545 int mmu_version;
3546 static const char *pgsz_names[] = {
3547 " 1K",
3548 " 2K",
3549 " 4K",
3550 " 8K",
3551 " 16K",
3552 " 32K",
3553 " 64K",
3554 "128K",
3555 "256K",
3556 "512K",
3557 " 1M",
3558 " 2M",
3559 " 4M",
3560 " 8M",
3561 " 16M",
3562 " 32M",
3563 " 64M",
3564 "128M",
3565 "256M",
3566 "512M",
3567 " 1G",
3568 " 2G",
3569 " 4G",
3570 " 8G",
3571 " 16G",
3572 " 32G",
3573 " 64G",
3574 "128G",
3575 "256G",
3576 "512G",
3577 " 1T",
3578 " 2T",
3579 };
3580
3581 /* Gather some infos about the MMU */
3582 mmucfg = mfspr(SPRN_MMUCFG);
3583 mmu_version = (mmucfg & 3) + 1;
3584 ntlbs = ((mmucfg >> 2) & 3) + 1;
3585 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3586 lpidsz = (mmucfg >> 24) & 0xf;
3587 rasz = (mmucfg >> 16) & 0x7f;
3588 if ((mmu_version > 1) && (mmucfg & 0x10000))
3589 lrat = 1;
3590 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3591 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3592 pidmask = (1ul << pidsz) - 1;
3593 lpidmask = (1ul << lpidsz) - 1;
3594 ramask = (1ull << rasz) - 1;
3595
3596 for (tlb = 0; tlb < ntlbs; tlb++) {
3597 u32 tlbcfg;
3598 int nent, assoc, new_cc = 1;
3599 printf("TLB %d:\n------\n", tlb);
3600 switch(tlb) {
3601 case 0:
3602 tlbcfg = mfspr(SPRN_TLB0CFG);
3603 break;
3604 case 1:
3605 tlbcfg = mfspr(SPRN_TLB1CFG);
3606 break;
3607 case 2:
3608 tlbcfg = mfspr(SPRN_TLB2CFG);
3609 break;
3610 case 3:
3611 tlbcfg = mfspr(SPRN_TLB3CFG);
3612 break;
3613 default:
3614 printf("Unsupported TLB number !\n");
3615 continue;
3616 }
3617 nent = tlbcfg & 0xfff;
3618 assoc = (tlbcfg >> 24) & 0xff;
3619 for (i = 0; i < nent; i++) {
3620 u32 mas0 = MAS0_TLBSEL(tlb);
3621 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3622 u64 mas2 = 0;
3623 u64 mas7_mas3;
3624 int esel = i, cc = i;
3625
3626 if (assoc != 0) {
3627 cc = i / assoc;
3628 esel = i % assoc;
3629 mas2 = cc * 0x1000;
3630 }
3631
3632 mas0 |= MAS0_ESEL(esel);
3633 mtspr(SPRN_MAS0, mas0);
3634 mtspr(SPRN_MAS1, mas1);
3635 mtspr(SPRN_MAS2, mas2);
3636 asm volatile("tlbre 0,0,0" : : : "memory");
3637 mas1 = mfspr(SPRN_MAS1);
3638 mas2 = mfspr(SPRN_MAS2);
3639 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3640 if (assoc && (i % assoc) == 0)
3641 new_cc = 1;
3642 if (!(mas1 & MAS1_VALID))
3643 continue;
3644 if (assoc == 0)
3645 printf("%04x- ", i);
3646 else if (new_cc)
3647 printf("%04x-%c", cc, 'A' + esel);
3648 else
3649 printf(" |%c", 'A' + esel);
3650 new_cc = 0;
3651 printf(" %016llx %04x %s %c%c AS%c",
3652 mas2 & ~0x3ffull,
3653 (mas1 >> 16) & 0x3fff,
3654 pgsz_names[(mas1 >> 7) & 0x1f],
3655 mas1 & MAS1_IND ? 'I' : ' ',
3656 mas1 & MAS1_IPROT ? 'P' : ' ',
3657 mas1 & MAS1_TS ? '1' : '0');
3658 printf(" %c%c%c%c%c%c%c",
3659 mas2 & MAS2_X0 ? 'a' : ' ',
3660 mas2 & MAS2_X1 ? 'v' : ' ',
3661 mas2 & MAS2_W ? 'w' : ' ',
3662 mas2 & MAS2_I ? 'i' : ' ',
3663 mas2 & MAS2_M ? 'm' : ' ',
3664 mas2 & MAS2_G ? 'g' : ' ',
3665 mas2 & MAS2_E ? 'e' : ' ');
3666 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3667 if (mas1 & MAS1_IND)
3668 printf(" %s\n",
3669 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3670 else
3671 printf(" U%c%c%c S%c%c%c\n",
3672 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3673 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3674 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3675 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3676 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3677 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3678 }
3679 }
3680}
3681#endif /* CONFIG_PPC_BOOK3E */
3682
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003683static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003685 if (enable) {
3686 __debugger = xmon;
3687 __debugger_ipi = xmon_ipi;
3688 __debugger_bpt = xmon_bpt;
3689 __debugger_sstep = xmon_sstep;
3690 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003691 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003692 __debugger_fault_handler = xmon_fault_handler;
Breno Leitao8d4a8622018-11-08 15:12:42 -02003693
3694#ifdef CONFIG_PPC_PSERIES
3695 /*
3696 * Get the token here to avoid trying to get a lock
3697 * during the crash, causing a deadlock.
3698 */
3699 set_indicator_token = rtas_token("set-indicator");
3700#endif
Olaf Heringb13cfd172005-08-04 19:26:42 +02003701 } else {
3702 __debugger = NULL;
3703 __debugger_ipi = NULL;
3704 __debugger_bpt = NULL;
3705 __debugger_sstep = NULL;
3706 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003707 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003708 __debugger_fault_handler = NULL;
3709 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003711
3712#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003713static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003714{
3715 /* ensure xmon is enabled */
3716 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003717 debugger(get_irq_regs());
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003718 if (!xmon_on)
3719 xmon_init(0);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003720}
3721
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003722static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003723 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003724 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003725 .action_msg = "Entering xmon",
3726};
3727
3728static int __init setup_xmon_sysrq(void)
3729{
3730 register_sysrq_key('x', &sysrq_xmon_op);
3731 return 0;
3732}
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003733device_initcall(setup_xmon_sysrq);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003734#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003735
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003736#ifdef CONFIG_DEBUG_FS
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05303737static void clear_all_bpt(void)
3738{
3739 int i;
3740
3741 /* clear/unpatch all breakpoints */
3742 remove_bpts();
3743 remove_cpu_bpts();
3744
3745 /* Disable all breakpoints */
3746 for (i = 0; i < NBPTS; ++i)
3747 bpts[i].enabled = 0;
3748
3749 /* Clear any data or iabr breakpoints */
3750 if (iabr || dabr.enabled) {
3751 iabr = NULL;
3752 dabr.enabled = 0;
3753 }
3754
3755 printf("xmon: All breakpoints cleared\n");
3756}
3757
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003758static int xmon_dbgfs_set(void *data, u64 val)
3759{
3760 xmon_on = !!val;
3761 xmon_init(xmon_on);
3762
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05303763 /* make sure all breakpoints removed when disabling */
3764 if (!xmon_on)
3765 clear_all_bpt();
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003766 return 0;
3767}
3768
3769static int xmon_dbgfs_get(void *data, u64 *val)
3770{
3771 *val = xmon_on;
3772 return 0;
3773}
3774
3775DEFINE_SIMPLE_ATTRIBUTE(xmon_dbgfs_ops, xmon_dbgfs_get,
3776 xmon_dbgfs_set, "%llu\n");
3777
3778static int __init setup_xmon_dbgfs(void)
3779{
3780 debugfs_create_file("xmon", 0600, powerpc_debugfs_root, NULL,
3781 &xmon_dbgfs_ops);
3782 return 0;
3783}
3784device_initcall(setup_xmon_dbgfs);
3785#endif /* CONFIG_DEBUG_FS */
3786
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003787static int xmon_early __initdata;
Michael Ellerman476792832006-10-03 14:12:08 +10003788
3789static int __init early_parse_xmon(char *p)
3790{
3791 if (!p || strncmp(p, "early", 5) == 0) {
3792 /* just "xmon" is equivalent to "xmon=early" */
3793 xmon_init(1);
3794 xmon_early = 1;
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003795 xmon_on = 1;
3796 } else if (strncmp(p, "on", 2) == 0) {
Michael Ellerman476792832006-10-03 14:12:08 +10003797 xmon_init(1);
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003798 xmon_on = 1;
3799 } else if (strncmp(p, "off", 3) == 0)
3800 xmon_on = 0;
Michael Ellerman476792832006-10-03 14:12:08 +10003801 else
3802 return 1;
3803
3804 return 0;
3805}
3806early_param("xmon", early_parse_xmon);
3807
3808void __init xmon_setup(void)
3809{
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003810 if (xmon_on)
Michael Ellerman476792832006-10-03 14:12:08 +10003811 xmon_init(1);
Michael Ellerman476792832006-10-03 14:12:08 +10003812 if (xmon_early)
3813 debugger(NULL);
3814}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003815
Arnd Bergmanne0555952006-11-27 19:18:55 +01003816#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003817
3818struct spu_info {
3819 struct spu *spu;
3820 u64 saved_mfc_sr1_RW;
3821 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003822 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003823 u8 stopped_ok;
3824};
3825
3826#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3827
3828static struct spu_info spu_info[XMON_NUM_SPUS];
3829
3830void xmon_register_spus(struct list_head *list)
3831{
3832 struct spu *spu;
3833
3834 list_for_each_entry(spu, list, full_list) {
3835 if (spu->number >= XMON_NUM_SPUS) {
3836 WARN_ON(1);
3837 continue;
3838 }
3839
3840 spu_info[spu->number].spu = spu;
3841 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003842 spu_info[spu->number].dump_addr = (unsigned long)
3843 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003844 }
3845}
3846
3847static void stop_spus(void)
3848{
3849 struct spu *spu;
3850 int i;
3851 u64 tmp;
3852
3853 for (i = 0; i < XMON_NUM_SPUS; i++) {
3854 if (!spu_info[i].spu)
3855 continue;
3856
3857 if (setjmp(bus_error_jmp) == 0) {
3858 catch_memory_errors = 1;
3859 sync();
3860
3861 spu = spu_info[i].spu;
3862
3863 spu_info[i].saved_spu_runcntl_RW =
3864 in_be32(&spu->problem->spu_runcntl_RW);
3865
3866 tmp = spu_mfc_sr1_get(spu);
3867 spu_info[i].saved_mfc_sr1_RW = tmp;
3868
3869 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3870 spu_mfc_sr1_set(spu, tmp);
3871
3872 sync();
3873 __delay(200);
3874
3875 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003876
3877 printf("Stopped spu %.2d (was %s)\n", i,
3878 spu_info[i].saved_spu_runcntl_RW ?
3879 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003880 } else {
3881 catch_memory_errors = 0;
3882 printf("*** Error stopping spu %.2d\n", i);
3883 }
3884 catch_memory_errors = 0;
3885 }
3886}
3887
3888static void restart_spus(void)
3889{
3890 struct spu *spu;
3891 int i;
3892
3893 for (i = 0; i < XMON_NUM_SPUS; i++) {
3894 if (!spu_info[i].spu)
3895 continue;
3896
3897 if (!spu_info[i].stopped_ok) {
3898 printf("*** Error, spu %d was not successfully stopped"
3899 ", not restarting\n", i);
3900 continue;
3901 }
3902
3903 if (setjmp(bus_error_jmp) == 0) {
3904 catch_memory_errors = 1;
3905 sync();
3906
3907 spu = spu_info[i].spu;
3908 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3909 out_be32(&spu->problem->spu_runcntl_RW,
3910 spu_info[i].saved_spu_runcntl_RW);
3911
3912 sync();
3913 __delay(200);
3914
3915 printf("Restarted spu %.2d\n", i);
3916 } else {
3917 catch_memory_errors = 0;
3918 printf("*** Error restarting spu %.2d\n", i);
3919 }
3920 catch_memory_errors = 0;
3921 }
3922}
3923
Michael Ellermana8984972006-10-24 18:31:28 +02003924#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003925#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003926do { \
3927 if (setjmp(bus_error_jmp) == 0) { \
3928 catch_memory_errors = 1; \
3929 sync(); \
3930 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003931 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003932 sync(); \
3933 __delay(200); \
3934 } else { \
3935 catch_memory_errors = 0; \
3936 printf(" %-*s = *** Error reading field.\n", \
3937 DUMP_WIDTH, #field); \
3938 } \
3939 catch_memory_errors = 0; \
3940} while (0)
3941
Michael Ellerman437a0702006-11-23 00:46:39 +01003942#define DUMP_FIELD(obj, format, field) \
3943 DUMP_VALUE(format, field, obj->field)
3944
Michael Ellermana8984972006-10-24 18:31:28 +02003945static void dump_spu_fields(struct spu *spu)
3946{
3947 printf("Dumping spu fields at address %p:\n", spu);
3948
3949 DUMP_FIELD(spu, "0x%x", number);
3950 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003951 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3952 DUMP_FIELD(spu, "0x%p", local_store);
3953 DUMP_FIELD(spu, "0x%lx", ls_size);
3954 DUMP_FIELD(spu, "0x%x", node);
3955 DUMP_FIELD(spu, "0x%lx", flags);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003956 DUMP_FIELD(spu, "%llu", class_0_pending);
3957 DUMP_FIELD(spu, "0x%llx", class_0_dar);
3958 DUMP_FIELD(spu, "0x%llx", class_1_dar);
3959 DUMP_FIELD(spu, "0x%llx", class_1_dsisr);
3960 DUMP_FIELD(spu, "0x%x", irqs[0]);
3961 DUMP_FIELD(spu, "0x%x", irqs[1]);
3962 DUMP_FIELD(spu, "0x%x", irqs[2]);
Michael Ellermana8984972006-10-24 18:31:28 +02003963 DUMP_FIELD(spu, "0x%x", slb_replace);
3964 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003965 DUMP_FIELD(spu, "0x%p", mm);
3966 DUMP_FIELD(spu, "0x%p", ctx);
3967 DUMP_FIELD(spu, "0x%p", rq);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003968 DUMP_FIELD(spu, "0x%llx", timestamp);
Michael Ellermana8984972006-10-24 18:31:28 +02003969 DUMP_FIELD(spu, "0x%lx", problem_phys);
3970 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003971 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3972 in_be32(&spu->problem->spu_runcntl_RW));
3973 DUMP_VALUE("0x%x", problem->spu_status_R,
3974 in_be32(&spu->problem->spu_status_R));
3975 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3976 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003977 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003978 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003979}
3980
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003981int
3982spu_inst_dump(unsigned long adr, long count, int praddr)
3983{
3984 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3985}
3986
3987static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003988{
3989 unsigned long offset, addr, ls_addr;
3990
3991 if (setjmp(bus_error_jmp) == 0) {
3992 catch_memory_errors = 1;
3993 sync();
3994 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3995 sync();
3996 __delay(200);
3997 } else {
3998 catch_memory_errors = 0;
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003999 printf("*** Error: accessing spu info for spu %ld\n", num);
Michael Ellerman24a24c82006-11-23 00:46:41 +01004000 return;
4001 }
4002 catch_memory_errors = 0;
4003
4004 if (scanhex(&offset))
4005 addr = ls_addr + offset;
4006 else
4007 addr = spu_info[num].dump_addr;
4008
4009 if (addr >= ls_addr + LS_SIZE) {
4010 printf("*** Error: address outside of local store\n");
4011 return;
4012 }
4013
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004014 switch (subcmd) {
4015 case 'i':
4016 addr += spu_inst_dump(addr, 16, 1);
4017 last_cmd = "sdi\n";
4018 break;
4019 default:
4020 prdump(addr, 64);
4021 addr += 64;
4022 last_cmd = "sd\n";
4023 break;
4024 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01004025
4026 spu_info[num].dump_addr = addr;
4027}
4028
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004029static int do_spu_cmd(void)
4030{
Michael Ellerman24a24c82006-11-23 00:46:41 +01004031 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004032 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004033
4034 cmd = inchar();
4035 switch (cmd) {
4036 case 's':
4037 stop_spus();
4038 break;
4039 case 'r':
4040 restart_spus();
4041 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01004042 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004043 subcmd = inchar();
4044 if (isxdigit(subcmd) || subcmd == '\n')
4045 termch = subcmd;
Stephen Rothwell8ad94022018-11-29 09:28:30 +11004046 /* fall through */
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004047 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01004048 scanhex(&num);
4049 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02004050 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01004051 return 0;
4052 }
4053
4054 switch (cmd) {
4055 case 'f':
4056 dump_spu_fields(spu_info[num].spu);
4057 break;
4058 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004059 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01004060 break;
4061 }
4062
Michael Ellermana8984972006-10-24 18:31:28 +02004063 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004064 default:
4065 return -1;
4066 }
4067
4068 return 0;
4069}
Arnd Bergmanne0555952006-11-27 19:18:55 +01004070#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004071static int do_spu_cmd(void)
4072{
4073 return -1;
4074}
4075#endif