blob: a728e191961330183df1c53d5158e45ab60ba480 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Routines providing a simple monitor for use on the PowerMac.
3 *
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004 * Copyright (C) 1996-2005 Paul Mackerras.
Michael Ellerman476792832006-10-03 14:12:08 +10005 * Copyright (C) 2001 PPC64 Team, IBM Corp
6 * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
Michael Ellerman56144ec2015-11-06 13:21:17 +110013
14#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/errno.h>
Ingo Molnar3f07c012017-02-08 18:51:30 +010016#include <linux/sched/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/smp.h>
18#include <linux/mm.h>
19#include <linux/reboot.h>
20#include <linux/delay.h>
21#include <linux/kallsyms.h>
Michael Ellermanca5dd392012-08-23 22:09:12 +000022#include <linux/kmsg_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040024#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110025#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080026#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010027#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080028#include <linux/bug.h>
Anton Blancharda71d64b2014-08-05 14:55:00 +100029#include <linux/nmi.h>
Vincent Bernat05b981f2014-07-15 13:43:47 +020030#include <linux/ctype.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
Michael Ellerman7644d582017-02-10 12:04:56 +110032#include <asm/debugfs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/ptrace.h>
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +100034#include <asm/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/string.h>
36#include <asm/prom.h>
37#include <asm/machdep.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100038#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/processor.h>
40#include <asm/pgtable.h>
41#include <asm/mmu.h>
42#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <asm/cputable.h>
44#include <asm/rtas.h>
45#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100046#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020047#include <asm/spu.h>
48#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110049#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000050#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010051#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000052#include <asm/hw_breakpoint.h>
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +100053#include <asm/xive.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110054#include <asm/opal.h>
55#include <asm/firmware.h>
56
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100057#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100059#include <asm/paca.h>
60#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Anshuman Khandual1ad7d702014-11-28 10:06:42 +053062#if defined(CONFIG_PPC_SPLPAR)
63#include <asm/plpar_wrappers.h>
64#else
65static inline long plapr_set_ciabr(unsigned long ciabr) {return 0; };
66#endif
67
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010069#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100072static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073static unsigned long xmon_taken = 1;
74static int xmon_owner;
75static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000076#else
77#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070078#endif /* CONFIG_SMP */
79
Anton Blanchard5be34922010-01-12 00:50:14 +000080static unsigned long in_xmon __read_mostly = 0;
Pan Xinhui3b5bf422017-03-22 16:27:49 -030081static int xmon_on = IS_ENABLED(CONFIG_XMON_DEFAULT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83static unsigned long adrs;
84static int size = 1;
85#define MAX_DUMP (128 * 1024)
86static unsigned long ndump = 64;
87static unsigned long nidump = 16;
88static unsigned long ncsum = 4096;
89static int termch;
90static char tmpstr[128];
91
Linus Torvalds1da177e2005-04-16 15:20:36 -070092static long bus_error_jmp[JMP_BUF_LEN];
93static int catch_memory_errors;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +100094static int catch_spr_faults;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97/* Breakpoint stuff */
98struct bpt {
99 unsigned long address;
100 unsigned int instr[2];
101 atomic_t ref_count;
102 int enabled;
103 unsigned long pad;
104};
105
106/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100107#define BP_CIABR 1
108#define BP_TRAP 2
109#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
111#define NBPTS 256
112static struct bpt bpts[NBPTS];
113static struct bpt dabr;
114static struct bpt *iabr;
115static unsigned bpinstr = 0x7fe00008; /* trap */
116
117#define BP_NUM(bp) ((bp) - bpts + 1)
118
119/* Prototypes */
120static int cmds(struct pt_regs *);
121static int mread(unsigned long, void *, int);
122static int mwrite(unsigned long, void *, int);
123static int handle_fault(struct pt_regs *);
124static void byterev(unsigned char *, int);
125static void memex(void);
126static int bsesc(void);
127static void dump(void);
128static void prdump(unsigned long, long);
129static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000130static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100131
132#ifdef CONFIG_PPC_POWERNV
133static void dump_opal_msglog(void);
134#else
135static inline void dump_opal_msglog(void)
136{
137 printf("Machine is not running OPAL firmware.\n");
138}
139#endif
140
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static void backtrace(struct pt_regs *);
142static void excprint(struct pt_regs *);
143static void prregs(struct pt_regs *);
144static void memops(int);
145static void memlocate(void);
146static void memzcan(void);
147static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
148int skipbl(void);
149int scanhex(unsigned long *valp);
150static void scannl(void);
151static int hexdigit(int);
152void getstring(char *, int);
153static void flush_input(void);
154static int inchar(void);
155static void take_input(char *);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000156static int read_spr(int, unsigned long *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157static void write_spr(int, unsigned long);
158static void super_regs(void);
159static void remove_bpts(void);
160static void insert_bpts(void);
161static void remove_cpu_bpts(void);
162static void insert_cpu_bpts(void);
163static struct bpt *at_breakpoint(unsigned long pc);
164static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
165static int do_step(struct pt_regs *);
166static void bpt_cmds(void);
167static void cacheflush(void);
168static int cpu_cmd(void);
169static void csum(void);
170static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000171static void proccall(void);
Douglas Miller6dfb5402015-11-23 09:01:15 -0600172static void show_tasks(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173void dump_segments(void);
174static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200175static void xmon_show_stack(unsigned long sp, unsigned long lr,
176 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177static void xmon_print_symbol(unsigned long address, const char *mid,
178 const char *after);
179static const char *getvecname(unsigned long vec);
180
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200181static int do_spu_cmd(void);
182
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100183#ifdef CONFIG_44x
184static void dump_tlb_44x(void);
185#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000186#ifdef CONFIG_PPC_BOOK3E
187static void dump_tlb_book3e(void);
188#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100189
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000190#ifdef CONFIG_PPC64
191#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000192#else
193#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000194#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100196#ifdef __LITTLE_ENDIAN__
197#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
198#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100200#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202static char *help_string = "\
203Commands:\n\
204 b show breakpoints\n\
205 bd set data breakpoint\n\
206 bi set instruction breakpoint\n\
207 bc clear breakpoint\n"
208#ifdef CONFIG_SMP
209 "\
210 c print cpus stopped in xmon\n\
211 c# try to switch to cpu number h (in hex)\n"
212#endif
213 "\
214 C checksum\n\
215 d dump bytes\n\
Douglas Miller5e48dc02017-02-07 07:40:44 -0600216 d1 dump 1 byte values\n\
217 d2 dump 2 byte values\n\
218 d4 dump 4 byte values\n\
219 d8 dump 8 byte values\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 di dump instructions\n\
221 df dump float values\n\
222 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000223 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100224#ifdef CONFIG_PPC_POWERNV
225 "\
226 do dump the OPAL message log\n"
227#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000228#ifdef CONFIG_PPC64
229 "\
230 dp[#] dump paca for current cpu, or cpu #\n\
231 dpa dump paca for all possible cpus\n"
232#endif
233 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100234 dr dump stream of raw bytes\n\
Michael Ellerman56144ec2015-11-06 13:21:17 +1100235 dt dump the tracing buffers (uses printk)\n\
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +1000236"
237#ifdef CONFIG_PPC_POWERNV
238" dx# dump xive on CPU #\n\
239 dxi# dump xive irq state #\n\
240 dxa dump xive on all CPUs\n"
241#endif
242" e print exception information\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 f flush cache\n\
244 la lookup symbol+offset of specified address\n\
245 ls lookup address of specified symbol\n\
246 m examine/change memory\n\
247 mm move a block of memory\n\
248 ms set a block of memory\n\
249 md compare two blocks of memory\n\
250 ml locate a block of memory\n\
251 mz zero a block of memory\n\
252 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000253 p call a procedure\n\
Douglas Miller6dfb5402015-11-23 09:01:15 -0600254 P list processes/tasks\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200256 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100257#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200258" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200259 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100260 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900261 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100262 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200263#endif
264" S print special registers\n\
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000265 Sa print all SPRs\n\
266 Sr # read SPR #\n\
267 Sw #v write v to SPR #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100270 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000271#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000272" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000273#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000274" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000275#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100276" u dump TLB\n"
277#endif
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000278" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100279" # n limit output to n lines per page (for dp, dpa, dl)\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000280" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 zh halt\n"
282;
283
284static struct pt_regs *xmon_regs;
285
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000286static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
288 asm volatile("sync; isync");
289}
290
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000291static inline void store_inst(void *p)
292{
293 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
294}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000296static inline void cflush(void *p)
297{
298 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
299}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000301static inline void cinval(void *p)
302{
303 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
304}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530306/**
307 * write_ciabr() - write the CIABR SPR
308 * @ciabr: The value to write.
309 *
310 * This function writes a value to the CIARB register either directly
311 * through mtspr instruction if the kernel is in HV privilege mode or
312 * call a hypervisor function to achieve the same in case the kernel
313 * is in supervisor privilege mode.
314 */
315static void write_ciabr(unsigned long ciabr)
316{
317 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
318 return;
319
320 if (cpu_has_feature(CPU_FTR_HVMODE)) {
321 mtspr(SPRN_CIABR, ciabr);
322 return;
323 }
324 plapr_set_ciabr(ciabr);
325}
326
327/**
328 * set_ciabr() - set the CIABR
329 * @addr: The value to set.
330 *
331 * This function sets the correct privilege value into the the HW
332 * breakpoint address before writing it up in the CIABR register.
333 */
334static void set_ciabr(unsigned long addr)
335{
336 addr &= ~CIABR_PRIV;
337
338 if (cpu_has_feature(CPU_FTR_HVMODE))
339 addr |= CIABR_PRIV_HYPER;
340 else
341 addr |= CIABR_PRIV_SUPER;
342 write_ciabr(addr);
343}
344
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345/*
346 * Disable surveillance (the service processor watchdog function)
347 * while we are in xmon.
348 * XXX we should re-enable it when we leave. :)
349 */
350#define SURVEILLANCE_TOKEN 9000
351
352static inline void disable_surveillance(void)
353{
354#ifdef CONFIG_PPC_PSERIES
355 /* Since this can't be a module, args should end up below 4GB. */
356 static struct rtas_args args;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100357 int token;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
359 /*
360 * At this point we have got all the cpus we can into
361 * xmon, so there is hopefully no other cpu calling RTAS
362 * at the moment, even though we don't take rtas.lock.
363 * If we did try to take rtas.lock there would be a
364 * real possibility of deadlock.
365 */
Michael Ellerman08eb1052015-11-24 22:26:09 +1100366 token = rtas_token("set-indicator");
367 if (token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100369
370 rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0);
371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372#endif /* CONFIG_PPC_PSERIES */
373}
374
375#ifdef CONFIG_SMP
376static int xmon_speaker;
377
378static void get_output_lock(void)
379{
380 int me = smp_processor_id() + 0x100;
381 int last_speaker = 0, prev;
382 long timeout;
383
384 if (xmon_speaker == me)
385 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100388 last_speaker = cmpxchg(&xmon_speaker, 0, me);
389 if (last_speaker == 0)
390 return;
391
Michael Ellerman15075892013-12-23 23:46:05 +1100392 /*
393 * Wait a full second for the lock, we might be on a slow
394 * console, but check every 100us.
395 */
396 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100398 if (--timeout > 0) {
399 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100401 }
402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 /* hostile takeover */
404 prev = cmpxchg(&xmon_speaker, last_speaker, me);
405 if (prev == last_speaker)
406 return;
407 break;
408 }
409 }
410}
411
412static void release_output_lock(void)
413{
414 xmon_speaker = 0;
415}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000416
417int cpus_are_in_xmon(void)
418{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000419 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000420}
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000421
422static bool wait_for_other_cpus(int ncpus)
423{
424 unsigned long timeout;
425
426 /* We wait for 2s, which is a metric "little while" */
427 for (timeout = 20000; timeout != 0; --timeout) {
428 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
429 return true;
430 udelay(100);
431 barrier();
432 }
433
434 return false;
435}
436#endif /* CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
Josh Boyerdaf8f402009-09-23 03:51:04 +0000438static inline int unrecoverable_excp(struct pt_regs *regs)
439{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000440#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000441 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000442 return 0;
443#else
444 return ((regs->msr & MSR_RI) == 0);
445#endif
446}
447
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000448static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
450 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 struct bpt *bp;
452 long recurse_jmp[JMP_BUF_LEN];
453 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100454 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455#ifdef CONFIG_SMP
456 int cpu;
457 int secondary;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458#endif
459
Anton Blanchardf13659e2007-03-21 01:48:34 +1100460 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000461 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
463 bp = in_breakpoint_table(regs->nip, &offset);
464 if (bp != NULL) {
465 regs->nip = bp->address + offset;
466 atomic_dec(&bp->ref_count);
467 }
468
469 remove_cpu_bpts();
470
471#ifdef CONFIG_SMP
472 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000473 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000474 /*
475 * We catch SPR read/write faults here because the 0x700, 0xf60
476 * etc. handlers don't call debugger_fault_handler().
477 */
478 if (catch_spr_faults)
479 longjmp(bus_error_jmp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 get_output_lock();
481 excprint(regs);
482 printf("cpu 0x%x: Exception %lx %s in xmon, "
483 "returning to main loop\n",
484 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000485 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 longjmp(xmon_fault_jmp[cpu], 1);
487 }
488
489 if (setjmp(recurse_jmp) != 0) {
490 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000491 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 printf("xmon: WARNING: bad recursive fault "
493 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000494 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 goto waiting;
496 }
497 secondary = !(xmon_taken && cpu == xmon_owner);
498 goto cmdloop;
499 }
500
501 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
503 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000504 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000506 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 fromipi = 0;
508
509 if (!fromipi) {
510 get_output_lock();
511 excprint(regs);
512 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000513 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 cpu, BP_NUM(bp));
515 xmon_print_symbol(regs->nip, " ", ")\n");
516 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000517 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 printf("WARNING: exception is not recoverable, "
519 "can't continue\n");
520 release_output_lock();
521 }
522
Michael Ellermand2b496e2013-12-23 23:46:06 +1100523 cpumask_set_cpu(cpu, &cpus_in_xmon);
524
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 waiting:
526 secondary = 1;
527 while (secondary && !xmon_gate) {
528 if (in_xmon == 0) {
529 if (fromipi)
530 goto leave;
531 secondary = test_and_set_bit(0, &in_xmon);
532 }
533 barrier();
534 }
535
536 if (!secondary && !xmon_gate) {
537 /* we are the first cpu to come in */
538 /* interrupt other cpu(s) */
539 int ncpus = num_online_cpus();
540
541 xmon_owner = cpu;
542 mb();
543 if (ncpus > 1) {
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000544 /*
545 * A system reset (trap == 0x100) can be triggered on
546 * all CPUs, so when we come in via 0x100 try waiting
547 * for the other CPUs to come in before we send the
548 * debugger break (IPI). This is similar to
549 * crash_kexec_secondary().
550 */
551 if (TRAP(regs) != 0x100 || !wait_for_other_cpus(ncpus))
552 smp_send_debugger_break();
553
554 wait_for_other_cpus(ncpus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 }
556 remove_bpts();
557 disable_surveillance();
558 /* for breakpoint or single step, print the current instr. */
559 if (bp || TRAP(regs) == 0xd00)
560 ppc_inst_dump(regs->nip, 1, 0);
561 printf("enter ? for help\n");
562 mb();
563 xmon_gate = 1;
564 barrier();
565 }
566
567 cmdloop:
568 while (in_xmon) {
569 if (secondary) {
570 if (cpu == xmon_owner) {
571 if (!test_and_set_bit(0, &xmon_taken)) {
572 secondary = 0;
573 continue;
574 }
575 /* missed it */
576 while (cpu == xmon_owner)
577 barrier();
578 }
579 barrier();
580 } else {
581 cmd = cmds(regs);
582 if (cmd != 0) {
583 /* exiting xmon */
584 insert_bpts();
585 xmon_gate = 0;
586 wmb();
587 in_xmon = 0;
588 break;
589 }
590 /* have switched to some other cpu */
591 secondary = 1;
592 }
593 }
594 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000595 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597#else
598 /* UP is simple... */
599 if (in_xmon) {
600 printf("Exception %lx %s in xmon, returning to main loop\n",
601 regs->trap, getvecname(TRAP(regs)));
602 longjmp(xmon_fault_jmp[0], 1);
603 }
604 if (setjmp(recurse_jmp) == 0) {
605 xmon_fault_jmp[0] = recurse_jmp;
606 in_xmon = 1;
607
608 excprint(regs);
609 bp = at_breakpoint(regs->nip);
610 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000611 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 xmon_print_symbol(regs->nip, " ", ")\n");
613 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000614 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 printf("WARNING: exception is not recoverable, "
616 "can't continue\n");
617 remove_bpts();
618 disable_surveillance();
619 /* for breakpoint or single step, print the current instr. */
620 if (bp || TRAP(regs) == 0xd00)
621 ppc_inst_dump(regs->nip, 1, 0);
622 printf("enter ? for help\n");
623 }
624
625 cmd = cmds(regs);
626
627 insert_bpts();
628 in_xmon = 0;
629#endif
630
Josh Boyercdd39042009-10-05 04:46:05 +0000631#ifdef CONFIG_BOOKE
632 if (regs->msr & MSR_DE) {
633 bp = at_breakpoint(regs->nip);
634 if (bp != NULL) {
635 regs->nip = (unsigned long) &bp->instr[0];
636 atomic_inc(&bp->ref_count);
637 }
638 }
639#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000640 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 bp = at_breakpoint(regs->nip);
642 if (bp != NULL) {
643 int stepped = emulate_step(regs, bp->instr[0]);
644 if (stepped == 0) {
645 regs->nip = (unsigned long) &bp->instr[0];
646 atomic_inc(&bp->ref_count);
647 } else if (stepped < 0) {
648 printf("Couldn't single-step %s instruction\n",
649 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
650 }
651 }
652 }
Josh Boyercdd39042009-10-05 04:46:05 +0000653#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 insert_cpu_bpts();
655
Anton Blancharda71d64b2014-08-05 14:55:00 +1000656 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100657 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000659 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660}
661
662int xmon(struct pt_regs *excp)
663{
664 struct pt_regs regs;
665
666 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000667 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 excp = &regs;
669 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 return xmon_core(excp, 0);
672}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000673EXPORT_SYMBOL(xmon);
674
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000675irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000676{
677 unsigned long flags;
678 local_irq_save(flags);
679 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000680 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000681 local_irq_restore(flags);
682 return IRQ_HANDLED;
683}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000685static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
687 struct bpt *bp;
688 unsigned long offset;
689
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000690 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 return 0;
692
693 /* Are we at the trap at bp->instr[1] for some bp? */
694 bp = in_breakpoint_table(regs->nip, &offset);
695 if (bp != NULL && offset == 4) {
696 regs->nip = bp->address + 4;
697 atomic_dec(&bp->ref_count);
698 return 1;
699 }
700
701 /* Are we at a breakpoint? */
702 bp = at_breakpoint(regs->nip);
703 if (!bp)
704 return 0;
705
706 xmon_core(regs, 0);
707
708 return 1;
709}
710
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000711static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712{
713 if (user_mode(regs))
714 return 0;
715 xmon_core(regs, 0);
716 return 1;
717}
718
Michael Neuling9422de32012-12-20 14:06:44 +0000719static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000721 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000723 if (dabr.enabled == 0)
724 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 xmon_core(regs, 0);
726 return 1;
727}
728
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000729static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000731 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000733 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 return 0;
735 xmon_core(regs, 0);
736 return 1;
737}
738
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000739static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
741#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000742 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 xmon_core(regs, 1);
744#endif
745 return 0;
746}
747
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000748static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749{
750 struct bpt *bp;
751 unsigned long offset;
752
753 if (in_xmon && catch_memory_errors)
754 handle_fault(regs); /* doesn't return */
755
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000756 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 bp = in_breakpoint_table(regs->nip, &offset);
758 if (bp != NULL) {
759 regs->nip = bp->address + offset;
760 atomic_dec(&bp->ref_count);
761 }
762 }
763
764 return 0;
765}
766
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767static struct bpt *at_breakpoint(unsigned long pc)
768{
769 int i;
770 struct bpt *bp;
771
772 bp = bpts;
773 for (i = 0; i < NBPTS; ++i, ++bp)
774 if (bp->enabled && pc == bp->address)
775 return bp;
776 return NULL;
777}
778
779static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
780{
781 unsigned long off;
782
783 off = nip - (unsigned long) bpts;
784 if (off >= sizeof(bpts))
785 return NULL;
786 off %= sizeof(struct bpt);
787 if (off != offsetof(struct bpt, instr[0])
788 && off != offsetof(struct bpt, instr[1]))
789 return NULL;
790 *offp = off - offsetof(struct bpt, instr[0]);
791 return (struct bpt *) (nip - off);
792}
793
794static struct bpt *new_breakpoint(unsigned long a)
795{
796 struct bpt *bp;
797
798 a &= ~3UL;
799 bp = at_breakpoint(a);
800 if (bp)
801 return bp;
802
803 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
804 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
805 bp->address = a;
806 bp->instr[1] = bpinstr;
807 store_inst(&bp->instr[1]);
808 return bp;
809 }
810 }
811
812 printf("Sorry, no free breakpoints. Please clear one first.\n");
813 return NULL;
814}
815
816static void insert_bpts(void)
817{
818 int i;
819 struct bpt *bp;
820
821 bp = bpts;
822 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100823 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 continue;
825 if (mread(bp->address, &bp->instr[0], 4) != 4) {
826 printf("Couldn't read instruction at %lx, "
827 "disabling breakpoint there\n", bp->address);
828 bp->enabled = 0;
829 continue;
830 }
831 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
832 printf("Breakpoint at %lx is on an mtmsrd or rfid "
833 "instruction, disabling it\n", bp->address);
834 bp->enabled = 0;
835 continue;
836 }
837 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100838 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 continue;
840 if (mwrite(bp->address, &bpinstr, 4) != 4) {
841 printf("Couldn't write instruction at %lx, "
842 "disabling breakpoint there\n", bp->address);
843 bp->enabled &= ~BP_TRAP;
844 continue;
845 }
846 store_inst((void *)bp->address);
847 }
848}
849
850static void insert_cpu_bpts(void)
851{
Michael Neuling9422de32012-12-20 14:06:44 +0000852 struct arch_hw_breakpoint brk;
853
854 if (dabr.enabled) {
855 brk.address = dabr.address;
856 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
857 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400858 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000859 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530860
861 if (iabr)
862 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863}
864
865static void remove_bpts(void)
866{
867 int i;
868 struct bpt *bp;
869 unsigned instr;
870
871 bp = bpts;
872 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100873 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 continue;
875 if (mread(bp->address, &instr, 4) == 4
876 && instr == bpinstr
877 && mwrite(bp->address, &bp->instr, 4) != 4)
878 printf("Couldn't remove breakpoint at %lx\n",
879 bp->address);
880 else
881 store_inst((void *)bp->address);
882 }
883}
884
885static void remove_cpu_bpts(void)
886{
Michael Neuling9422de32012-12-20 14:06:44 +0000887 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530888 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889}
890
Sam bobroff958b7c82015-10-08 11:50:23 +1100891static void set_lpp_cmd(void)
892{
893 unsigned long lpp;
894
895 if (!scanhex(&lpp)) {
896 printf("Invalid number.\n");
897 lpp = 0;
898 }
899 xmon_set_pagination_lpp(lpp);
900}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901/* Command interpreting routine */
902static char *last_cmd;
903
904static int
905cmds(struct pt_regs *excp)
906{
907 int cmd = 0;
908
909 last_cmd = NULL;
910 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200911
Guilherme G. Piccolib5617832017-03-22 16:27:50 -0300912 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
Olaf Hering26c8af52006-09-08 16:29:21 +0200913
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 for(;;) {
915#ifdef CONFIG_SMP
916 printf("%x:", smp_processor_id());
917#endif /* CONFIG_SMP */
918 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 flush_input();
920 termch = 0;
921 cmd = skipbl();
922 if( cmd == '\n' ) {
923 if (last_cmd == NULL)
924 continue;
925 take_input(last_cmd);
926 last_cmd = NULL;
927 cmd = inchar();
928 }
929 switch (cmd) {
930 case 'm':
931 cmd = inchar();
932 switch (cmd) {
933 case 'm':
934 case 's':
935 case 'd':
936 memops(cmd);
937 break;
938 case 'l':
939 memlocate();
940 break;
941 case 'z':
942 memzcan();
943 break;
944 case 'i':
Michal Hocko9af744d2017-02-22 15:46:16 -0800945 show_mem(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 break;
947 default:
948 termch = cmd;
949 memex();
950 }
951 break;
952 case 'd':
953 dump();
954 break;
955 case 'l':
956 symbol_lookup();
957 break;
958 case 'r':
959 prregs(excp); /* print regs */
960 break;
961 case 'e':
962 excprint(excp);
963 break;
964 case 'S':
965 super_regs();
966 break;
967 case 't':
968 backtrace(excp);
969 break;
970 case 'f':
971 cacheflush();
972 break;
973 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200974 if (do_spu_cmd() == 0)
975 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 if (do_step(excp))
977 return cmd;
978 break;
979 case 'x':
980 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100981 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100983 printf(" <no input ...>\n");
984 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 return cmd;
986 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000987 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 break;
Sam bobroff958b7c82015-10-08 11:50:23 +1100989 case '#':
990 set_lpp_cmd();
991 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 case 'b':
993 bpt_cmds();
994 break;
995 case 'C':
996 csum();
997 break;
998 case 'c':
999 if (cpu_cmd())
1000 return 0;
1001 break;
1002 case 'z':
1003 bootcmds();
1004 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001005 case 'p':
1006 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -06001008 case 'P':
1009 show_tasks();
1010 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001011#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 case 'u':
1013 dump_segments();
1014 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +11001015#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11001016 case 'u':
1017 dump_tlb_44x();
1018 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +00001019#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10001020 case 'u':
1021 dump_tlb_book3e();
1022 break;
1023#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 default:
1025 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +00001026 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 if (' ' < cmd && cmd <= '~')
1028 putchar(cmd);
1029 else
1030 printf("\\x%x", cmd);
1031 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +00001032 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 printf(" (type ? for help)\n");
1034 break;
1035 }
1036 }
1037}
1038
Josh Boyercdd39042009-10-05 04:46:05 +00001039#ifdef CONFIG_BOOKE
1040static int do_step(struct pt_regs *regs)
1041{
1042 regs->msr |= MSR_DE;
1043 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1044 return 1;
1045}
1046#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047/*
1048 * Step a single instruction.
1049 * Some instructions we emulate, others we execute with MSR_SE set.
1050 */
1051static int do_step(struct pt_regs *regs)
1052{
1053 unsigned int instr;
1054 int stepped;
1055
1056 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001057 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 if (mread(regs->nip, &instr, 4) == 4) {
1059 stepped = emulate_step(regs, instr);
1060 if (stepped < 0) {
1061 printf("Couldn't single-step %s instruction\n",
1062 (IS_RFID(instr)? "rfid": "mtmsrd"));
1063 return 0;
1064 }
1065 if (stepped > 0) {
1066 regs->trap = 0xd00 | (regs->trap & 1);
1067 printf("stepped to ");
1068 xmon_print_symbol(regs->nip, " ", "\n");
1069 ppc_inst_dump(regs->nip, 1, 0);
1070 return 0;
1071 }
1072 }
1073 }
1074 regs->msr |= MSR_SE;
1075 return 1;
1076}
Josh Boyercdd39042009-10-05 04:46:05 +00001077#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
1079static void bootcmds(void)
1080{
1081 int cmd;
1082
1083 cmd = inchar();
1084 if (cmd == 'r')
1085 ppc_md.restart(NULL);
1086 else if (cmd == 'h')
1087 ppc_md.halt();
1088 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001089 if (pm_power_off)
1090 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091}
1092
1093static int cpu_cmd(void)
1094{
1095#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001096 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099 if (!scanhex(&cpu)) {
1100 /* print cpus waiting or in xmon */
1101 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001102 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001103 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001104 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001105 if (cpu == last_cpu + 1) {
1106 last_cpu = cpu;
1107 } else {
1108 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001109 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001110 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001111 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 }
1114 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001115 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001116 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 printf("\n");
1118 return 0;
1119 }
1120 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001121 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 printf("cpu 0x%x isn't in xmon\n", cpu);
1123 return 0;
1124 }
1125 xmon_taken = 0;
1126 mb();
1127 xmon_owner = cpu;
1128 timeout = 10000000;
1129 while (!xmon_taken) {
1130 if (--timeout == 0) {
1131 if (test_and_set_bit(0, &xmon_taken))
1132 break;
1133 /* take control back */
1134 mb();
1135 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001136 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 return 0;
1138 }
1139 barrier();
1140 }
1141 return 1;
1142#else
1143 return 0;
1144#endif /* CONFIG_SMP */
1145}
1146
1147static unsigned short fcstab[256] = {
1148 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1149 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1150 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1151 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1152 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1153 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1154 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1155 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1156 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1157 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1158 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1159 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1160 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1161 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1162 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1163 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1164 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1165 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1166 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1167 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1168 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1169 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1170 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1171 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1172 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1173 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1174 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1175 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1176 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1177 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1178 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1179 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1180};
1181
1182#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1183
1184static void
1185csum(void)
1186{
1187 unsigned int i;
1188 unsigned short fcs;
1189 unsigned char v;
1190
1191 if (!scanhex(&adrs))
1192 return;
1193 if (!scanhex(&ncsum))
1194 return;
1195 fcs = 0xffff;
1196 for (i = 0; i < ncsum; ++i) {
1197 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001198 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 break;
1200 }
1201 fcs = FCS(fcs, v);
1202 }
1203 printf("%x\n", fcs);
1204}
1205
1206/*
1207 * Check if this is a suitable place to put a breakpoint.
1208 */
1209static long check_bp_loc(unsigned long addr)
1210{
1211 unsigned int instr;
1212
1213 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001214 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 printf("Breakpoints may only be placed at kernel addresses\n");
1216 return 0;
1217 }
1218 if (!mread(addr, &instr, sizeof(instr))) {
1219 printf("Can't read instruction at address %lx\n", addr);
1220 return 0;
1221 }
1222 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1223 printf("Breakpoints may not be placed on mtmsrd or rfid "
1224 "instructions\n");
1225 return 0;
1226 }
1227 return 1;
1228}
1229
Michael Ellermane3bc8042012-08-23 22:09:13 +00001230static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 "Breakpoint command usage:\n"
1232 "b show breakpoints\n"
1233 "b <addr> [cnt] set breakpoint at given instr addr\n"
1234 "bc clear all breakpoints\n"
1235 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301236 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 "bd <addr> [cnt] set hardware data breakpoint\n"
1238 "";
1239
1240static void
1241bpt_cmds(void)
1242{
1243 int cmd;
1244 unsigned long a;
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001245 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 struct bpt *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
1248 cmd = inchar();
1249 switch (cmd) {
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001250#ifndef CONFIG_PPC_8xx
1251 static const char badaddr[] = "Only kernel addresses are permitted for breakpoints\n";
1252 int mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 case 'd': /* bd - hardware data breakpoint */
1254 mode = 7;
1255 cmd = inchar();
1256 if (cmd == 'r')
1257 mode = 5;
1258 else if (cmd == 'w')
1259 mode = 6;
1260 else
1261 termch = cmd;
1262 dabr.address = 0;
1263 dabr.enabled = 0;
1264 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001265 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 printf(badaddr);
1267 break;
1268 }
Michael Neuling9422de32012-12-20 14:06:44 +00001269 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 dabr.enabled = mode | BP_DABR;
1271 }
1272 break;
1273
1274 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301275 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 printf("Hardware instruction breakpoint "
1277 "not supported on this cpu\n");
1278 break;
1279 }
1280 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001281 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 iabr = NULL;
1283 }
1284 if (!scanhex(&a))
1285 break;
1286 if (!check_bp_loc(a))
1287 break;
1288 bp = new_breakpoint(a);
1289 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001290 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 iabr = bp;
1292 }
1293 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001294#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
1296 case 'c':
1297 if (!scanhex(&a)) {
1298 /* clear all breakpoints */
1299 for (i = 0; i < NBPTS; ++i)
1300 bpts[i].enabled = 0;
1301 iabr = NULL;
1302 dabr.enabled = 0;
1303 printf("All breakpoints cleared\n");
1304 break;
1305 }
1306
1307 if (a <= NBPTS && a >= 1) {
1308 /* assume a breakpoint number */
1309 bp = &bpts[a-1]; /* bp nums are 1 based */
1310 } else {
1311 /* assume a breakpoint address */
1312 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001313 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001314 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 break;
1316 }
1317 }
1318
Michael Ellerman736256e2014-05-26 21:02:14 +10001319 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 xmon_print_symbol(bp->address, " ", ")\n");
1321 bp->enabled = 0;
1322 break;
1323
1324 default:
1325 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001326 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 if (cmd == '?') {
1328 printf(breakpoint_help_string);
1329 break;
1330 }
1331 termch = cmd;
1332 if (!scanhex(&a)) {
1333 /* print all breakpoints */
1334 printf(" type address\n");
1335 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001336 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 if (dabr.enabled & 1)
1338 printf("r");
1339 if (dabr.enabled & 2)
1340 printf("w");
1341 printf("]\n");
1342 }
1343 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1344 if (!bp->enabled)
1345 continue;
1346 printf("%2x %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001347 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 xmon_print_symbol(bp->address, " ", "\n");
1349 }
1350 break;
1351 }
1352
1353 if (!check_bp_loc(a))
1354 break;
1355 bp = new_breakpoint(a);
1356 if (bp != NULL)
1357 bp->enabled |= BP_TRAP;
1358 break;
1359 }
1360}
1361
1362/* Very cheap human name for vector lookup. */
1363static
1364const char *getvecname(unsigned long vec)
1365{
1366 char *ret;
1367
1368 switch (vec) {
1369 case 0x100: ret = "(System Reset)"; break;
1370 case 0x200: ret = "(Machine Check)"; break;
1371 case 0x300: ret = "(Data Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001372 case 0x380:
1373 if (radix_enabled())
1374 ret = "(Data Access Out of Range)";
1375 else
1376 ret = "(Data SLB Access)";
1377 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 case 0x400: ret = "(Instruction Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001379 case 0x480:
1380 if (radix_enabled())
1381 ret = "(Instruction Access Out of Range)";
1382 else
1383 ret = "(Instruction SLB Access)";
1384 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 case 0x500: ret = "(Hardware Interrupt)"; break;
1386 case 0x600: ret = "(Alignment)"; break;
1387 case 0x700: ret = "(Program Check)"; break;
1388 case 0x800: ret = "(FPU Unavailable)"; break;
1389 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001390 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1391 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 case 0xc00: ret = "(System Call)"; break;
1393 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001394 case 0xe40: ret = "(Emulation Assist)"; break;
1395 case 0xe60: ret = "(HMI)"; break;
1396 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 case 0xf00: ret = "(Performance Monitor)"; break;
1398 case 0xf20: ret = "(Altivec Unavailable)"; break;
1399 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001400 case 0x1500: ret = "(Denormalisation)"; break;
1401 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 default: ret = "";
1403 }
1404 return ret;
1405}
1406
1407static void get_function_bounds(unsigned long pc, unsigned long *startp,
1408 unsigned long *endp)
1409{
1410 unsigned long size, offset;
1411 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
1413 *startp = *endp = 0;
1414 if (pc == 0)
1415 return;
1416 if (setjmp(bus_error_jmp) == 0) {
1417 catch_memory_errors = 1;
1418 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001419 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 if (name != NULL) {
1421 *startp = pc - offset;
1422 *endp = pc - offset + size;
1423 }
1424 sync();
1425 }
1426 catch_memory_errors = 0;
1427}
1428
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001429#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1430#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1431
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432static void xmon_show_stack(unsigned long sp, unsigned long lr,
1433 unsigned long pc)
1434{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001435 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 unsigned long ip;
1437 unsigned long newsp;
1438 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 struct pt_regs regs;
1440
Michael Ellerman0104cd62012-10-09 04:20:36 +00001441 while (max_to_print--) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301442 if (!is_kernel_addr(sp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 if (sp != 0)
1444 printf("SP (%lx) is in userspace\n", sp);
1445 break;
1446 }
1447
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001448 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 || !mread(sp, &newsp, sizeof(unsigned long))) {
1450 printf("Couldn't read stack frame at %lx\n", sp);
1451 break;
1452 }
1453
1454 /*
1455 * For the first stack frame, try to work out if
1456 * LR and/or the saved LR value in the bottommost
1457 * stack frame are valid.
1458 */
1459 if ((pc | lr) != 0) {
1460 unsigned long fnstart, fnend;
1461 unsigned long nextip;
1462 int printip = 1;
1463
1464 get_function_bounds(pc, &fnstart, &fnend);
1465 nextip = 0;
1466 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001467 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 sizeof(unsigned long));
1469 if (lr == ip) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301470 if (!is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 || (fnstart <= lr && lr < fnend))
1472 printip = 0;
1473 } else if (lr == nextip) {
1474 printip = 0;
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301475 } else if (is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 && !(fnstart <= lr && lr < fnend)) {
1477 printf("[link register ] ");
1478 xmon_print_symbol(lr, " ", "\n");
1479 }
1480 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001481 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 xmon_print_symbol(ip, " ", " (unreliable)\n");
1483 }
1484 pc = lr = 0;
1485
1486 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001487 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 xmon_print_symbol(ip, " ", "\n");
1489 }
1490
1491 /* Look for "regshere" marker to see if this is
1492 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001493 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001494 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001495 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 != sizeof(regs)) {
1497 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001498 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 break;
1500 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001501 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 getvecname(TRAP(&regs)));
1503 pc = regs.nip;
1504 lr = regs.link;
1505 xmon_print_symbol(pc, " ", "\n");
1506 }
1507
1508 if (newsp == 0)
1509 break;
1510
1511 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001512 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513}
1514
1515static void backtrace(struct pt_regs *excp)
1516{
1517 unsigned long sp;
1518
1519 if (scanhex(&sp))
1520 xmon_show_stack(sp, 0, 0);
1521 else
1522 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1523 scannl();
1524}
1525
1526static void print_bug_trap(struct pt_regs *regs)
1527{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001528#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001529 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 unsigned long addr;
1531
1532 if (regs->msr & MSR_PR)
1533 return; /* not in kernel */
1534 addr = regs->nip; /* address of trap instruction */
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301535 if (!is_kernel_addr(addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 return;
1537 bug = find_bug(regs->nip);
1538 if (bug == NULL)
1539 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001540 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 return;
1542
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001543#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001544 printf("kernel BUG at %s:%u!\n",
1545 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001546#else
1547 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1548#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001549#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550}
1551
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001552static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553{
1554 unsigned long trap;
1555
1556#ifdef CONFIG_SMP
1557 printf("cpu 0x%x: ", smp_processor_id());
1558#endif /* CONFIG_SMP */
1559
1560 trap = TRAP(fp);
1561 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1562 printf(" pc: ");
1563 xmon_print_symbol(fp->nip, ": ", "\n");
1564
1565 printf(" lr: ", fp->link);
1566 xmon_print_symbol(fp->link, ": ", "\n");
1567
1568 printf(" sp: %lx\n", fp->gpr[1]);
1569 printf(" msr: %lx\n", fp->msr);
1570
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001571 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 printf(" dar: %lx\n", fp->dar);
1573 if (trap != 0x380)
1574 printf(" dsisr: %lx\n", fp->dsisr);
1575 }
1576
1577 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001578#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001579 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1580 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001581#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 if (current) {
1583 printf(" pid = %ld, comm = %s\n",
1584 current->pid, current->comm);
1585 }
1586
1587 if (trap == 0x700)
1588 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001589
1590 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591}
1592
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001593static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001595 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 unsigned long base;
1597 struct pt_regs regs;
1598
1599 if (scanhex(&base)) {
1600 if (setjmp(bus_error_jmp) == 0) {
1601 catch_memory_errors = 1;
1602 sync();
1603 regs = *(struct pt_regs *)base;
1604 sync();
1605 __delay(200);
1606 } else {
1607 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001608 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 base);
1610 return;
1611 }
1612 catch_memory_errors = 0;
1613 fp = &regs;
1614 }
1615
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001616#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 if (FULL_REGS(fp)) {
1618 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001619 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1621 } else {
1622 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001623 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1625 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001626#else
1627 for (n = 0; n < 32; ++n) {
1628 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1629 (n & 3) == 3? "\n": " ");
1630 if (n == 12 && !FULL_REGS(fp)) {
1631 printf("\n");
1632 break;
1633 }
1634 }
1635#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 printf("pc = ");
1637 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001638 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1639 printf("cfar= ");
1640 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 printf("lr = ");
1643 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001644 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1645 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001647 trap = TRAP(fp);
1648 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1649 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650}
1651
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001652static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653{
1654 int cmd;
1655 unsigned long nflush;
1656
1657 cmd = inchar();
1658 if (cmd != 'i')
1659 termch = cmd;
1660 scanhex((void *)&adrs);
1661 if (termch != '\n')
1662 termch = 0;
1663 nflush = 1;
1664 scanhex(&nflush);
1665 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1666 if (setjmp(bus_error_jmp) == 0) {
1667 catch_memory_errors = 1;
1668 sync();
1669
1670 if (cmd != 'i') {
1671 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1672 cflush((void *) adrs);
1673 } else {
1674 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1675 cinval((void *) adrs);
1676 }
1677 sync();
1678 /* wait a little while to see if we get a machine check */
1679 __delay(200);
1680 }
1681 catch_memory_errors = 0;
1682}
1683
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001684extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1685extern void xmon_mtspr(int spr, unsigned long value);
1686
1687static int
1688read_spr(int n, unsigned long *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 unsigned long ret = -1UL;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001691 int ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
1693 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001694 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 sync();
1696
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001697 ret = xmon_mfspr(n, *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
1699 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001700 *vp = ret;
1701 ok = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001703 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001705 return ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706}
1707
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001708static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709write_spr(int n, unsigned long val)
1710{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001712 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 sync();
1714
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001715 xmon_mtspr(n, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716
1717 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001718 } else {
1719 printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001721 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722}
1723
Michael Ellerman18461932016-07-07 22:54:29 +10001724static void dump_206_sprs(void)
1725{
1726#ifdef CONFIG_PPC64
1727 if (!cpu_has_feature(CPU_FTR_ARCH_206))
1728 return;
1729
1730 /* Actually some of these pre-date 2.06, but whatevs */
1731
1732 printf("srr0 = %.16x srr1 = %.16x dsisr = %.8x\n",
1733 mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
1734 printf("dscr = %.16x ppr = %.16x pir = %.8x\n",
1735 mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
1736
1737 if (!(mfmsr() & MSR_HV))
1738 return;
1739
1740 printf("sdr1 = %.16x hdar = %.16x hdsisr = %.8x\n",
1741 mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
1742 printf("hsrr0 = %.16x hsrr1 = %.16x hdec = %.8x\n",
1743 mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
1744 printf("lpcr = %.16x pcr = %.16x lpidr = %.8x\n",
1745 mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
1746 printf("hsprg0 = %.16x hsprg1 = %.16x\n",
1747 mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1));
1748 printf("dabr = %.16x dabrx = %.16x\n",
1749 mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
1750#endif
1751}
1752
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001753static void dump_207_sprs(void)
1754{
1755#ifdef CONFIG_PPC64
1756 unsigned long msr;
1757
1758 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
1759 return;
1760
1761 printf("dpdes = %.16x tir = %.16x cir = %.8x\n",
1762 mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
1763
1764 printf("fscr = %.16x tar = %.16x pspb = %.8x\n",
1765 mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
1766
1767 msr = mfmsr();
1768 if (msr & MSR_TM) {
1769 /* Only if TM has been enabled in the kernel */
1770 printf("tfhar = %.16x tfiar = %.16x texasr = %.16x\n",
1771 mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
1772 mfspr(SPRN_TEXASR));
1773 }
1774
1775 printf("mmcr0 = %.16x mmcr1 = %.16x mmcr2 = %.16x\n",
1776 mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
1777 printf("pmc1 = %.8x pmc2 = %.8x pmc3 = %.8x pmc4 = %.8x\n",
1778 mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
1779 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
1780 printf("mmcra = %.16x siar = %.16x pmc5 = %.8x\n",
1781 mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
1782 printf("sdar = %.16x sier = %.16x pmc6 = %.8x\n",
1783 mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
1784 printf("ebbhr = %.16x ebbrr = %.16x bescr = %.16x\n",
1785 mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
1786
1787 if (!(msr & MSR_HV))
1788 return;
1789
1790 printf("hfscr = %.16x dhdes = %.16x rpr = %.16x\n",
1791 mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
1792 printf("dawr = %.16x dawrx = %.16x ciabr = %.16x\n",
1793 mfspr(SPRN_DAWR), mfspr(SPRN_DAWRX), mfspr(SPRN_CIABR));
1794#endif
1795}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001797static void dump_one_spr(int spr, bool show_unimplemented)
1798{
1799 unsigned long val;
1800
1801 val = 0xdeadbeef;
1802 if (!read_spr(spr, &val)) {
1803 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1804 return;
1805 }
1806
1807 if (val == 0xdeadbeef) {
1808 /* Looks like read was a nop, confirm */
1809 val = 0x0badcafe;
1810 if (!read_spr(spr, &val)) {
1811 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1812 return;
1813 }
1814
1815 if (val == 0x0badcafe) {
1816 if (show_unimplemented)
1817 printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
1818 return;
1819 }
1820 }
1821
1822 printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
1823}
1824
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001825static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826{
Michael Ellerman13629da2016-07-07 22:54:27 +10001827 static unsigned long regno;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 int cmd;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001829 int spr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
1831 cmd = skipbl();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001832
1833 switch (cmd) {
1834 case '\n': {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001835 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 asm("mr %0,1" : "=r" (sp) :);
1837 asm("mr %0,2" : "=r" (toc) :);
1838
Michael Ellerman56346ad2016-07-07 22:54:28 +10001839 printf("msr = "REG" sprg0 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001840 mfmsr(), mfspr(SPRN_SPRG0));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001841 printf("pvr = "REG" sprg1 = "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001842 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001843 printf("dec = "REG" sprg2 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001844 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001845 printf("sp = "REG" sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
1846 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
1847
Michael Ellerman18461932016-07-07 22:54:29 +10001848 dump_206_sprs();
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001849 dump_207_sprs();
Michael Ellerman18461932016-07-07 22:54:29 +10001850
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 return;
1852 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001853 case 'w': {
1854 unsigned long val;
1855 scanhex(&regno);
1856 val = 0;
1857 read_spr(regno, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 scanhex(&val);
1859 write_spr(regno, val);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001860 dump_one_spr(regno, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001863 case 'r':
1864 scanhex(&regno);
1865 dump_one_spr(regno, true);
1866 break;
1867 case 'a':
1868 /* dump ALL SPRs */
1869 for (spr = 1; spr < 1024; ++spr)
1870 dump_one_spr(spr, false);
1871 break;
1872 }
1873
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 scannl();
1875}
1876
1877/*
1878 * Stuff for reading and writing memory safely
1879 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001880static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881mread(unsigned long adrs, void *buf, int size)
1882{
1883 volatile int n;
1884 char *p, *q;
1885
1886 n = 0;
1887 if (setjmp(bus_error_jmp) == 0) {
1888 catch_memory_errors = 1;
1889 sync();
1890 p = (char *)adrs;
1891 q = (char *)buf;
1892 switch (size) {
1893 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001894 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 break;
1896 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001897 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 break;
1899 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001900 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 break;
1902 default:
1903 for( ; n < size; ++n) {
1904 *q++ = *p++;
1905 sync();
1906 }
1907 }
1908 sync();
1909 /* wait a little while to see if we get a machine check */
1910 __delay(200);
1911 n = size;
1912 }
1913 catch_memory_errors = 0;
1914 return n;
1915}
1916
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001917static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918mwrite(unsigned long adrs, void *buf, int size)
1919{
1920 volatile int n;
1921 char *p, *q;
1922
1923 n = 0;
1924 if (setjmp(bus_error_jmp) == 0) {
1925 catch_memory_errors = 1;
1926 sync();
1927 p = (char *) adrs;
1928 q = (char *) buf;
1929 switch (size) {
1930 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001931 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 break;
1933 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001934 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 break;
1936 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001937 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 break;
1939 default:
1940 for ( ; n < size; ++n) {
1941 *p++ = *q++;
1942 sync();
1943 }
1944 }
1945 sync();
1946 /* wait a little while to see if we get a machine check */
1947 __delay(200);
1948 n = size;
1949 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10001950 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 }
1952 catch_memory_errors = 0;
1953 return n;
1954}
1955
1956static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001957static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958static char *fault_chars[] = { "--", "**", "##" };
1959
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001960static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001962 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 switch (TRAP(regs)) {
1964 case 0x200:
1965 fault_type = 0;
1966 break;
1967 case 0x300:
1968 case 0x380:
1969 fault_type = 1;
1970 break;
1971 default:
1972 fault_type = 2;
1973 }
1974
1975 longjmp(bus_error_jmp, 1);
1976
1977 return 0;
1978}
1979
1980#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1981
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001982static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983byterev(unsigned char *val, int size)
1984{
1985 int t;
1986
1987 switch (size) {
1988 case 2:
1989 SWAP(val[0], val[1], t);
1990 break;
1991 case 4:
1992 SWAP(val[0], val[3], t);
1993 SWAP(val[1], val[2], t);
1994 break;
1995 case 8: /* is there really any use for this? */
1996 SWAP(val[0], val[7], t);
1997 SWAP(val[1], val[6], t);
1998 SWAP(val[2], val[5], t);
1999 SWAP(val[3], val[4], t);
2000 break;
2001 }
2002}
2003
2004static int brev;
2005static int mnoread;
2006
Michael Ellermane3bc8042012-08-23 22:09:13 +00002007static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 "Memory examine command usage:\n"
2009 "m [addr] [flags] examine/change memory\n"
2010 " addr is optional. will start where left off.\n"
2011 " flags may include chars from this set:\n"
2012 " b modify by bytes (default)\n"
2013 " w modify by words (2 byte)\n"
2014 " l modify by longs (4 byte)\n"
2015 " d modify by doubleword (8 byte)\n"
2016 " r toggle reverse byte order mode\n"
2017 " n do not read memory (for i/o spaces)\n"
2018 " . ok to read (default)\n"
2019 "NOTE: flags are saved as defaults\n"
2020 "";
2021
Michael Ellermane3bc8042012-08-23 22:09:13 +00002022static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 "Memory examine subcommands:\n"
2024 " hexval write this val to current location\n"
2025 " 'string' write chars from string to this location\n"
2026 " ' increment address\n"
2027 " ^ decrement address\n"
2028 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
2029 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
2030 " ` clear no-read flag\n"
2031 " ; stay at this addr\n"
2032 " v change to byte mode\n"
2033 " w change to word (2 byte) mode\n"
2034 " l change to long (4 byte) mode\n"
2035 " u change to doubleword (8 byte) mode\n"
2036 " m addr change current addr\n"
2037 " n toggle no-read flag\n"
2038 " r toggle byte reverse flag\n"
2039 " < count back up count bytes\n"
2040 " > count skip forward count bytes\n"
2041 " x exit this mode\n"
2042 "";
2043
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002044static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045memex(void)
2046{
2047 int cmd, inc, i, nslash;
2048 unsigned long n;
2049 unsigned char val[16];
2050
2051 scanhex((void *)&adrs);
2052 cmd = skipbl();
2053 if (cmd == '?') {
2054 printf(memex_help_string);
2055 return;
2056 } else {
2057 termch = cmd;
2058 }
2059 last_cmd = "m\n";
2060 while ((cmd = skipbl()) != '\n') {
2061 switch( cmd ){
2062 case 'b': size = 1; break;
2063 case 'w': size = 2; break;
2064 case 'l': size = 4; break;
2065 case 'd': size = 8; break;
2066 case 'r': brev = !brev; break;
2067 case 'n': mnoread = 1; break;
2068 case '.': mnoread = 0; break;
2069 }
2070 }
2071 if( size <= 0 )
2072 size = 1;
2073 else if( size > 8 )
2074 size = 8;
2075 for(;;){
2076 if (!mnoread)
2077 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002078 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 if (!mnoread) {
2080 if (brev)
2081 byterev(val, size);
2082 putchar(' ');
2083 for (i = 0; i < n; ++i)
2084 printf("%.2x", val[i]);
2085 for (; i < size; ++i)
2086 printf("%s", fault_chars[fault_type]);
2087 }
2088 putchar(' ');
2089 inc = size;
2090 nslash = 0;
2091 for(;;){
2092 if( scanhex(&n) ){
2093 for (i = 0; i < size; ++i)
2094 val[i] = n >> (i * 8);
2095 if (!brev)
2096 byterev(val, size);
2097 mwrite(adrs, val, size);
2098 inc = size;
2099 }
2100 cmd = skipbl();
2101 if (cmd == '\n')
2102 break;
2103 inc = 0;
2104 switch (cmd) {
2105 case '\'':
2106 for(;;){
2107 n = inchar();
2108 if( n == '\\' )
2109 n = bsesc();
2110 else if( n == '\'' )
2111 break;
2112 for (i = 0; i < size; ++i)
2113 val[i] = n >> (i * 8);
2114 if (!brev)
2115 byterev(val, size);
2116 mwrite(adrs, val, size);
2117 adrs += size;
2118 }
2119 adrs -= size;
2120 inc = size;
2121 break;
2122 case ',':
2123 adrs += size;
2124 break;
2125 case '.':
2126 mnoread = 0;
2127 break;
2128 case ';':
2129 break;
2130 case 'x':
2131 case EOF:
2132 scannl();
2133 return;
2134 case 'b':
2135 case 'v':
2136 size = 1;
2137 break;
2138 case 'w':
2139 size = 2;
2140 break;
2141 case 'l':
2142 size = 4;
2143 break;
2144 case 'u':
2145 size = 8;
2146 break;
2147 case '^':
2148 adrs -= size;
2149 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 case '/':
2151 if (nslash > 0)
2152 adrs -= 1 << nslash;
2153 else
2154 nslash = 0;
2155 nslash += 4;
2156 adrs += 1 << nslash;
2157 break;
2158 case '\\':
2159 if (nslash < 0)
2160 adrs += 1 << -nslash;
2161 else
2162 nslash = 0;
2163 nslash -= 4;
2164 adrs -= 1 << -nslash;
2165 break;
2166 case 'm':
2167 scanhex((void *)&adrs);
2168 break;
2169 case 'n':
2170 mnoread = 1;
2171 break;
2172 case 'r':
2173 brev = !brev;
2174 break;
2175 case '<':
2176 n = size;
2177 scanhex(&n);
2178 adrs -= n;
2179 break;
2180 case '>':
2181 n = size;
2182 scanhex(&n);
2183 adrs += n;
2184 break;
2185 case '?':
2186 printf(memex_subcmd_help_string);
2187 break;
2188 }
2189 }
2190 adrs += inc;
2191 }
2192}
2193
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002194static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195bsesc(void)
2196{
2197 int c;
2198
2199 c = inchar();
2200 switch( c ){
2201 case 'n': c = '\n'; break;
2202 case 'r': c = '\r'; break;
2203 case 'b': c = '\b'; break;
2204 case 't': c = '\t'; break;
2205 }
2206 return c;
2207}
2208
Olaf Hering7e5b5932006-03-08 20:40:28 +01002209static void xmon_rawdump (unsigned long adrs, long ndump)
2210{
2211 long n, m, r, nr;
2212 unsigned char temp[16];
2213
2214 for (n = ndump; n > 0;) {
2215 r = n < 16? n: 16;
2216 nr = mread(adrs, temp, r);
2217 adrs += nr;
2218 for (m = 0; m < r; ++m) {
2219 if (m < nr)
2220 printf("%.2x", temp[m]);
2221 else
2222 printf("%s", fault_chars[fault_type]);
2223 }
2224 n -= r;
2225 if (nr < r)
2226 break;
2227 }
2228 printf("\n");
2229}
2230
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002231#ifdef CONFIG_PPC64
2232static void dump_one_paca(int cpu)
2233{
2234 struct paca_struct *p;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002235#ifdef CONFIG_PPC_STD_MMU_64
2236 int i = 0;
2237#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002238
2239 if (setjmp(bus_error_jmp) != 0) {
2240 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2241 return;
2242 }
2243
2244 catch_memory_errors = 1;
2245 sync();
2246
2247 p = &paca[cpu];
2248
2249 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2250
Michael Ellermanad987fc2015-10-14 16:58:36 +11002251 printf(" %-*s = %s\n", 20, "possible", cpu_possible(cpu) ? "yes" : "no");
2252 printf(" %-*s = %s\n", 20, "present", cpu_present(cpu) ? "yes" : "no");
2253 printf(" %-*s = %s\n", 20, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002254
2255#define DUMP(paca, name, format) \
Michael Ellermanad987fc2015-10-14 16:58:36 +11002256 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 20, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002257 offsetof(struct paca_struct, name));
2258
2259 DUMP(p, lock_token, "x");
2260 DUMP(p, paca_index, "x");
2261 DUMP(p, kernel_toc, "lx");
2262 DUMP(p, kernelbase, "lx");
2263 DUMP(p, kernel_msr, "lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002264 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302265#ifdef CONFIG_PPC_BOOK3S_64
Nicholas Pigginb1ee8a32016-12-20 04:30:06 +10002266 DUMP(p, nmi_emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302267 DUMP(p, mc_emergency_sp, "p");
Nicholas Pigginc4f3b522016-12-20 04:30:05 +10002268 DUMP(p, in_nmi, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302269 DUMP(p, in_mce, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002270 DUMP(p, hmi_event_available, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302271#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002272 DUMP(p, data_offset, "lx");
2273 DUMP(p, hw_cpu_id, "x");
2274 DUMP(p, cpu_start, "x");
2275 DUMP(p, kexec_state, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002276#ifdef CONFIG_PPC_STD_MMU_64
2277 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2278 u64 esid, vsid;
2279
2280 if (!p->slb_shadow_ptr)
2281 continue;
2282
2283 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2284 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
2285
2286 if (esid || vsid) {
2287 printf(" slb_shadow[%d]: = 0x%016lx 0x%016lx\n",
2288 i, esid, vsid);
2289 }
2290 }
2291 DUMP(p, vmalloc_sllp, "x");
2292 DUMP(p, slb_cache_ptr, "x");
2293 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2294 printf(" slb_cache[%d]: = 0x%016lx\n", i, p->slb_cache[i]);
2295#endif
2296 DUMP(p, dscr_default, "llx");
2297#ifdef CONFIG_PPC_BOOK3E
2298 DUMP(p, pgd, "p");
2299 DUMP(p, kernel_pgd, "p");
2300 DUMP(p, tcd_ptr, "p");
2301 DUMP(p, mc_kstack, "p");
2302 DUMP(p, crit_kstack, "p");
2303 DUMP(p, dbg_kstack, "p");
2304#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002305 DUMP(p, __current, "p");
2306 DUMP(p, kstack, "lx");
2307 DUMP(p, stab_rr, "lx");
2308 DUMP(p, saved_r1, "lx");
2309 DUMP(p, trap_save, "x");
2310 DUMP(p, soft_enabled, "x");
2311 DUMP(p, irq_happened, "x");
2312 DUMP(p, io_sync, "x");
2313 DUMP(p, irq_work_pending, "x");
2314 DUMP(p, nap_state_lost, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002315 DUMP(p, sprg_vdso, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002316
Michael Ellermanad987fc2015-10-14 16:58:36 +11002317#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
2318 DUMP(p, tm_scratch, "llx");
2319#endif
2320
2321#ifdef CONFIG_PPC_POWERNV
2322 DUMP(p, core_idle_state_ptr, "p");
2323 DUMP(p, thread_idle_state, "x");
2324 DUMP(p, thread_mask, "x");
2325 DUMP(p, subcore_sibling_mask, "x");
2326#endif
2327
Frederic Weisbecker8c8b73c2017-01-05 18:11:45 +01002328 DUMP(p, accounting.utime, "llx");
2329 DUMP(p, accounting.stime, "llx");
2330 DUMP(p, accounting.utime_scaled, "llx");
Christophe Leroyc223c902016-05-17 08:33:46 +02002331 DUMP(p, accounting.starttime, "llx");
2332 DUMP(p, accounting.starttime_user, "llx");
2333 DUMP(p, accounting.startspurr, "llx");
2334 DUMP(p, accounting.utime_sspurr, "llx");
Frederic Weisbeckerf828c3d2017-01-05 18:11:46 +01002335 DUMP(p, accounting.steal_time, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002336#undef DUMP
2337
2338 catch_memory_errors = 0;
2339 sync();
2340}
2341
2342static void dump_all_pacas(void)
2343{
2344 int cpu;
2345
2346 if (num_possible_cpus() == 0) {
2347 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2348 return;
2349 }
2350
2351 for_each_possible_cpu(cpu)
2352 dump_one_paca(cpu);
2353}
2354
2355static void dump_pacas(void)
2356{
2357 unsigned long num;
2358 int c;
2359
2360 c = inchar();
2361 if (c == 'a') {
2362 dump_all_pacas();
2363 return;
2364 }
2365
2366 termch = c; /* Put c back, it wasn't 'a' */
2367
2368 if (scanhex(&num))
2369 dump_one_paca(num);
2370 else
2371 dump_one_paca(xmon_owner);
2372}
2373#endif
2374
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002375#ifdef CONFIG_PPC_POWERNV
2376static void dump_one_xive(int cpu)
2377{
2378 unsigned int hwid = get_hard_smp_processor_id(cpu);
2379
2380 opal_xive_dump(XIVE_DUMP_TM_HYP, hwid);
2381 opal_xive_dump(XIVE_DUMP_TM_POOL, hwid);
2382 opal_xive_dump(XIVE_DUMP_TM_OS, hwid);
2383 opal_xive_dump(XIVE_DUMP_TM_USER, hwid);
2384 opal_xive_dump(XIVE_DUMP_VP, hwid);
2385 opal_xive_dump(XIVE_DUMP_EMU_STATE, hwid);
2386
2387 if (setjmp(bus_error_jmp) != 0) {
2388 catch_memory_errors = 0;
2389 printf("*** Error dumping xive on cpu %d\n", cpu);
2390 return;
2391 }
2392
2393 catch_memory_errors = 1;
2394 sync();
2395 xmon_xive_do_dump(cpu);
2396 sync();
2397 __delay(200);
2398 catch_memory_errors = 0;
2399}
2400
2401static void dump_all_xives(void)
2402{
2403 int cpu;
2404
2405 if (num_possible_cpus() == 0) {
2406 printf("No possible cpus, use 'dx #' to dump individual cpus\n");
2407 return;
2408 }
2409
2410 for_each_possible_cpu(cpu)
2411 dump_one_xive(cpu);
2412}
2413
2414static void dump_one_xive_irq(u32 num)
2415{
2416 s64 rc;
2417 __be64 vp;
2418 u8 prio;
2419 __be32 lirq;
2420
2421 rc = opal_xive_get_irq_config(num, &vp, &prio, &lirq);
2422 xmon_printf("IRQ 0x%x config: vp=0x%llx prio=%d lirq=0x%x (rc=%lld)\n",
2423 num, be64_to_cpu(vp), prio, be32_to_cpu(lirq), rc);
2424}
2425
2426static void dump_xives(void)
2427{
2428 unsigned long num;
2429 int c;
2430
2431 c = inchar();
2432 if (c == 'a') {
2433 dump_all_xives();
2434 return;
2435 } else if (c == 'i') {
2436 if (scanhex(&num))
2437 dump_one_xive_irq(num);
2438 return;
2439 }
2440
2441 termch = c; /* Put c back, it wasn't 'a' */
2442
2443 if (scanhex(&num))
2444 dump_one_xive(num);
2445 else
2446 dump_one_xive(xmon_owner);
2447}
2448#endif /* CONFIG_PPC_POWERNV */
2449
Douglas Miller5e48dc02017-02-07 07:40:44 -06002450static void dump_by_size(unsigned long addr, long count, int size)
2451{
2452 unsigned char temp[16];
2453 int i, j;
2454 u64 val;
2455
2456 count = ALIGN(count, 16);
2457
2458 for (i = 0; i < count; i += 16, addr += 16) {
2459 printf(REG, addr);
2460
2461 if (mread(addr, temp, 16) != 16) {
2462 printf("\nFaulted reading %d bytes from 0x"REG"\n", 16, addr);
2463 return;
2464 }
2465
2466 for (j = 0; j < 16; j += size) {
2467 putchar(' ');
2468 switch (size) {
2469 case 1: val = temp[j]; break;
2470 case 2: val = *(u16 *)&temp[j]; break;
2471 case 4: val = *(u32 *)&temp[j]; break;
2472 case 8: val = *(u64 *)&temp[j]; break;
2473 default: val = 0;
2474 }
2475
2476 printf("%0*lx", size * 2, val);
2477 }
2478 printf("\n");
2479 }
2480}
2481
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002482static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483dump(void)
2484{
Douglas Miller5e48dc02017-02-07 07:40:44 -06002485 static char last[] = { "d?\n" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 int c;
2487
2488 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002489
2490#ifdef CONFIG_PPC64
2491 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002492 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002493 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002494 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002495 return;
2496 }
2497#endif
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002498#ifdef CONFIG_PPC_POWERNV
2499 if (c == 'x') {
2500 xmon_start_pagination();
2501 dump_xives();
2502 xmon_end_pagination();
2503 return;
2504 }
2505#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002506
Douglas Miller5e48dc02017-02-07 07:40:44 -06002507 if (c == '\n')
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 termch = c;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002509
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 scanhex((void *)&adrs);
2511 if (termch != '\n')
2512 termch = 0;
2513 if (c == 'i') {
2514 scanhex(&nidump);
2515 if (nidump == 0)
2516 nidump = 16;
2517 else if (nidump > MAX_DUMP)
2518 nidump = MAX_DUMP;
2519 adrs += ppc_inst_dump(adrs, nidump, 1);
2520 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002521 } else if (c == 'l') {
2522 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002523 } else if (c == 'o') {
2524 dump_opal_msglog();
Michael Ellerman56144ec2015-11-06 13:21:17 +11002525 } else if (c == 't') {
2526 ftrace_dump(DUMP_ALL);
2527 tracing_on();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002528 } else if (c == 'r') {
2529 scanhex(&ndump);
2530 if (ndump == 0)
2531 ndump = 64;
2532 xmon_rawdump(adrs, ndump);
2533 adrs += ndump;
2534 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 } else {
2536 scanhex(&ndump);
2537 if (ndump == 0)
2538 ndump = 64;
2539 else if (ndump > MAX_DUMP)
2540 ndump = MAX_DUMP;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002541
2542 switch (c) {
2543 case '8':
2544 case '4':
2545 case '2':
2546 case '1':
2547 ndump = ALIGN(ndump, 16);
2548 dump_by_size(adrs, ndump, c - '0');
2549 last[1] = c;
2550 last_cmd = last;
2551 break;
2552 default:
2553 prdump(adrs, ndump);
2554 last_cmd = "d\n";
2555 }
2556
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 adrs += ndump;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 }
2559}
2560
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002561static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562prdump(unsigned long adrs, long ndump)
2563{
2564 long n, m, c, r, nr;
2565 unsigned char temp[16];
2566
2567 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002568 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 putchar(' ');
2570 r = n < 16? n: 16;
2571 nr = mread(adrs, temp, r);
2572 adrs += nr;
2573 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002574 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002575 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 if (m < nr)
2577 printf("%.2x", temp[m]);
2578 else
2579 printf("%s", fault_chars[fault_type]);
2580 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002581 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002582 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002583 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 printf(" |");
2587 for (m = 0; m < r; ++m) {
2588 if (m < nr) {
2589 c = temp[m];
2590 putchar(' ' <= c && c <= '~'? c: '.');
2591 } else
2592 putchar(' ');
2593 }
2594 n -= r;
2595 for (; m < 16; ++m)
2596 putchar(' ');
2597 printf("|\n");
2598 if (nr < r)
2599 break;
2600 }
2601}
2602
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002603typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2604
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002605static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002606generic_inst_dump(unsigned long adr, long count, int praddr,
2607 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608{
2609 int nr, dotted;
2610 unsigned long first_adr;
2611 unsigned long inst, last_inst = 0;
2612 unsigned char val[4];
2613
2614 dotted = 0;
2615 for (first_adr = adr; count > 0; --count, adr += 4) {
2616 nr = mread(adr, val, 4);
2617 if (nr == 0) {
2618 if (praddr) {
2619 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002620 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 }
2622 break;
2623 }
2624 inst = GETWORD(val);
2625 if (adr > first_adr && inst == last_inst) {
2626 if (!dotted) {
2627 printf(" ...\n");
2628 dotted = 1;
2629 }
2630 continue;
2631 }
2632 dotted = 0;
2633 last_inst = inst;
2634 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002635 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002637 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 printf("\n");
2639 }
2640 return adr - first_adr;
2641}
2642
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002643static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002644ppc_inst_dump(unsigned long adr, long count, int praddr)
2645{
2646 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2647}
2648
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649void
2650print_address(unsigned long addr)
2651{
2652 xmon_print_symbol(addr, "\t# ", "");
2653}
2654
Vinay Sridharf312deb2009-05-14 23:13:07 +00002655void
2656dump_log_buf(void)
2657{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002658 struct kmsg_dumper dumper = { .active = 1 };
2659 unsigned char buf[128];
2660 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002661
Michael Ellermane3bc8042012-08-23 22:09:13 +00002662 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002663 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002664 return;
2665 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002666
Michael Ellermane3bc8042012-08-23 22:09:13 +00002667 catch_memory_errors = 1;
2668 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002669
Michael Ellermanca5dd392012-08-23 22:09:12 +00002670 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002671 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002672 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2673 buf[len] = '\0';
2674 printf("%s", buf);
2675 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002676 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002677
Michael Ellermane3bc8042012-08-23 22:09:13 +00002678 sync();
2679 /* wait a little while to see if we get a machine check */
2680 __delay(200);
2681 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002682}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002684#ifdef CONFIG_PPC_POWERNV
2685static void dump_opal_msglog(void)
2686{
2687 unsigned char buf[128];
2688 ssize_t res;
2689 loff_t pos = 0;
2690
2691 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2692 printf("Machine is not running OPAL firmware.\n");
2693 return;
2694 }
2695
2696 if (setjmp(bus_error_jmp) != 0) {
2697 printf("Error dumping OPAL msglog!\n");
2698 return;
2699 }
2700
2701 catch_memory_errors = 1;
2702 sync();
2703
2704 xmon_start_pagination();
2705 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2706 if (res < 0) {
2707 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2708 break;
2709 }
2710 buf[res] = '\0';
2711 printf("%s", buf);
2712 pos += res;
2713 }
2714 xmon_end_pagination();
2715
2716 sync();
2717 /* wait a little while to see if we get a machine check */
2718 __delay(200);
2719 catch_memory_errors = 0;
2720}
2721#endif
2722
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723/*
2724 * Memory operations - move, set, print differences
2725 */
2726static unsigned long mdest; /* destination address */
2727static unsigned long msrc; /* source address */
2728static unsigned long mval; /* byte value to set memory to */
2729static unsigned long mcount; /* # bytes to affect */
2730static unsigned long mdiffs; /* max # differences to print */
2731
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002732static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733memops(int cmd)
2734{
2735 scanhex((void *)&mdest);
2736 if( termch != '\n' )
2737 termch = 0;
2738 scanhex((void *)(cmd == 's'? &mval: &msrc));
2739 if( termch != '\n' )
2740 termch = 0;
2741 scanhex((void *)&mcount);
2742 switch( cmd ){
2743 case 'm':
2744 memmove((void *)mdest, (void *)msrc, mcount);
2745 break;
2746 case 's':
2747 memset((void *)mdest, mval, mcount);
2748 break;
2749 case 'd':
2750 if( termch != '\n' )
2751 termch = 0;
2752 scanhex((void *)&mdiffs);
2753 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2754 break;
2755 }
2756}
2757
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002758static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2760{
2761 unsigned n, prt;
2762
2763 prt = 0;
2764 for( n = nb; n > 0; --n )
2765 if( *p1++ != *p2++ )
2766 if( ++prt <= maxpr )
2767 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2768 p1[-1], p2 - 1, p2[-1]);
2769 if( prt > maxpr )
2770 printf("Total of %d differences\n", prt);
2771}
2772
2773static unsigned mend;
2774static unsigned mask;
2775
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002776static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777memlocate(void)
2778{
2779 unsigned a, n;
2780 unsigned char val[4];
2781
2782 last_cmd = "ml";
2783 scanhex((void *)&mdest);
2784 if (termch != '\n') {
2785 termch = 0;
2786 scanhex((void *)&mend);
2787 if (termch != '\n') {
2788 termch = 0;
2789 scanhex((void *)&mval);
2790 mask = ~0;
2791 if (termch != '\n') termch = 0;
2792 scanhex((void *)&mask);
2793 }
2794 }
2795 n = 0;
2796 for (a = mdest; a < mend; a += 4) {
2797 if (mread(a, val, 4) == 4
2798 && ((GETWORD(val) ^ mval) & mask) == 0) {
2799 printf("%.16x: %.16x\n", a, GETWORD(val));
2800 if (++n >= 10)
2801 break;
2802 }
2803 }
2804}
2805
2806static unsigned long mskip = 0x1000;
2807static unsigned long mlim = 0xffffffff;
2808
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002809static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810memzcan(void)
2811{
2812 unsigned char v;
2813 unsigned a;
2814 int ok, ook;
2815
2816 scanhex(&mdest);
2817 if (termch != '\n') termch = 0;
2818 scanhex(&mskip);
2819 if (termch != '\n') termch = 0;
2820 scanhex(&mlim);
2821 ook = 0;
2822 for (a = mdest; a < mlim; a += mskip) {
2823 ok = mread(a, &v, 1);
2824 if (ok && !ook) {
2825 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 } else if (!ok && ook)
2827 printf("%.8x\n", a - mskip);
2828 ook = ok;
2829 if (a + mskip < a)
2830 break;
2831 }
2832 if (ook)
2833 printf("%.8x\n", a - mskip);
2834}
2835
Douglas Miller6dfb5402015-11-23 09:01:15 -06002836static void show_task(struct task_struct *tsk)
2837{
2838 char state;
2839
2840 /*
2841 * Cloned from kdb_task_state_char(), which is not entirely
2842 * appropriate for calling from xmon. This could be moved
2843 * to a common, generic, routine used by both.
2844 */
2845 state = (tsk->state == 0) ? 'R' :
2846 (tsk->state < 0) ? 'U' :
2847 (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
2848 (tsk->state & TASK_STOPPED) ? 'T' :
2849 (tsk->state & TASK_TRACED) ? 'C' :
2850 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
2851 (tsk->exit_state & EXIT_DEAD) ? 'E' :
2852 (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
2853
2854 printf("%p %016lx %6d %6d %c %2d %s\n", tsk,
2855 tsk->thread.ksp,
2856 tsk->pid, tsk->parent->pid,
2857 state, task_thread_info(tsk)->cpu,
2858 tsk->comm);
2859}
2860
2861static void show_tasks(void)
2862{
2863 unsigned long tskv;
2864 struct task_struct *tsk = NULL;
2865
2866 printf(" task_struct ->thread.ksp PID PPID S P CMD\n");
2867
2868 if (scanhex(&tskv))
2869 tsk = (struct task_struct *)tskv;
2870
2871 if (setjmp(bus_error_jmp) != 0) {
2872 catch_memory_errors = 0;
2873 printf("*** Error dumping task %p\n", tsk);
2874 return;
2875 }
2876
2877 catch_memory_errors = 1;
2878 sync();
2879
2880 if (tsk)
2881 show_task(tsk);
2882 else
2883 for_each_process(tsk)
2884 show_task(tsk);
2885
2886 sync();
2887 __delay(200);
2888 catch_memory_errors = 0;
2889}
2890
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002891static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002892{
2893 unsigned long args[8];
2894 unsigned long ret;
2895 int i;
2896 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2897 unsigned long, unsigned long, unsigned long,
2898 unsigned long, unsigned long, unsigned long);
2899 callfunc_t func;
2900
2901 if (!scanhex(&adrs))
2902 return;
2903 if (termch != '\n')
2904 termch = 0;
2905 for (i = 0; i < 8; ++i)
2906 args[i] = 0;
2907 for (i = 0; i < 8; ++i) {
2908 if (!scanhex(&args[i]) || termch == '\n')
2909 break;
2910 termch = 0;
2911 }
2912 func = (callfunc_t) adrs;
2913 ret = 0;
2914 if (setjmp(bus_error_jmp) == 0) {
2915 catch_memory_errors = 1;
2916 sync();
2917 ret = func(args[0], args[1], args[2], args[3],
2918 args[4], args[5], args[6], args[7]);
2919 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10002920 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002921 } else {
2922 printf("*** %x exception occurred\n", fault_except);
2923 }
2924 catch_memory_errors = 0;
2925}
2926
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927/* Input scanning routines */
2928int
2929skipbl(void)
2930{
2931 int c;
2932
2933 if( termch != 0 ){
2934 c = termch;
2935 termch = 0;
2936 } else
2937 c = inchar();
2938 while( c == ' ' || c == '\t' )
2939 c = inchar();
2940 return c;
2941}
2942
2943#define N_PTREGS 44
2944static char *regnames[N_PTREGS] = {
2945 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2946 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2947 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2948 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002949 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2950#ifdef CONFIG_PPC64
2951 "softe",
2952#else
2953 "mq",
2954#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 "trap", "dar", "dsisr", "res"
2956};
2957
2958int
2959scanhex(unsigned long *vp)
2960{
2961 int c, d;
2962 unsigned long v;
2963
2964 c = skipbl();
2965 if (c == '%') {
2966 /* parse register name */
2967 char regname[8];
2968 int i;
2969
2970 for (i = 0; i < sizeof(regname) - 1; ++i) {
2971 c = inchar();
2972 if (!isalnum(c)) {
2973 termch = c;
2974 break;
2975 }
2976 regname[i] = c;
2977 }
2978 regname[i] = 0;
2979 for (i = 0; i < N_PTREGS; ++i) {
2980 if (strcmp(regnames[i], regname) == 0) {
2981 if (xmon_regs == NULL) {
2982 printf("regs not available\n");
2983 return 0;
2984 }
2985 *vp = ((unsigned long *)xmon_regs)[i];
2986 return 1;
2987 }
2988 }
2989 printf("invalid register name '%%%s'\n", regname);
2990 return 0;
2991 }
2992
2993 /* skip leading "0x" if any */
2994
2995 if (c == '0') {
2996 c = inchar();
2997 if (c == 'x') {
2998 c = inchar();
2999 } else {
3000 d = hexdigit(c);
3001 if (d == EOF) {
3002 termch = c;
3003 *vp = 0;
3004 return 1;
3005 }
3006 }
3007 } else if (c == '$') {
3008 int i;
3009 for (i=0; i<63; i++) {
3010 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02003011 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 termch = c;
3013 break;
3014 }
3015 tmpstr[i] = c;
3016 }
3017 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07003018 *vp = 0;
3019 if (setjmp(bus_error_jmp) == 0) {
3020 catch_memory_errors = 1;
3021 sync();
3022 *vp = kallsyms_lookup_name(tmpstr);
3023 sync();
3024 }
3025 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 if (!(*vp)) {
3027 printf("unknown symbol '%s'\n", tmpstr);
3028 return 0;
3029 }
3030 return 1;
3031 }
3032
3033 d = hexdigit(c);
3034 if (d == EOF) {
3035 termch = c;
3036 return 0;
3037 }
3038 v = 0;
3039 do {
3040 v = (v << 4) + d;
3041 c = inchar();
3042 d = hexdigit(c);
3043 } while (d != EOF);
3044 termch = c;
3045 *vp = v;
3046 return 1;
3047}
3048
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003049static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050scannl(void)
3051{
3052 int c;
3053
3054 c = termch;
3055 termch = 0;
3056 while( c != '\n' )
3057 c = inchar();
3058}
3059
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003060static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061{
3062 if( '0' <= c && c <= '9' )
3063 return c - '0';
3064 if( 'A' <= c && c <= 'F' )
3065 return c - ('A' - 10);
3066 if( 'a' <= c && c <= 'f' )
3067 return c - ('a' - 10);
3068 return EOF;
3069}
3070
3071void
3072getstring(char *s, int size)
3073{
3074 int c;
3075
3076 c = skipbl();
3077 do {
3078 if( size > 1 ){
3079 *s++ = c;
3080 --size;
3081 }
3082 c = inchar();
3083 } while( c != ' ' && c != '\t' && c != '\n' );
3084 termch = c;
3085 *s = 0;
3086}
3087
3088static char line[256];
3089static char *lineptr;
3090
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003091static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092flush_input(void)
3093{
3094 lineptr = NULL;
3095}
3096
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003097static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098inchar(void)
3099{
3100 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003101 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 lineptr = NULL;
3103 return EOF;
3104 }
3105 lineptr = line;
3106 }
3107 return *lineptr++;
3108}
3109
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003110static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111take_input(char *str)
3112{
3113 lineptr = str;
3114}
3115
3116
3117static void
3118symbol_lookup(void)
3119{
3120 int type = inchar();
3121 unsigned long addr;
3122 static char tmp[64];
3123
3124 switch (type) {
3125 case 'a':
3126 if (scanhex(&addr))
3127 xmon_print_symbol(addr, ": ", "\n");
3128 termch = 0;
3129 break;
3130 case 's':
3131 getstring(tmp, 64);
3132 if (setjmp(bus_error_jmp) == 0) {
3133 catch_memory_errors = 1;
3134 sync();
3135 addr = kallsyms_lookup_name(tmp);
3136 if (addr)
3137 printf("%s: %lx\n", tmp, addr);
3138 else
3139 printf("Symbol '%s' not found.\n", tmp);
3140 sync();
3141 }
3142 catch_memory_errors = 0;
3143 termch = 0;
3144 break;
3145 }
3146}
3147
3148
3149/* Print an address in numeric and symbolic form (if possible) */
3150static void xmon_print_symbol(unsigned long address, const char *mid,
3151 const char *after)
3152{
3153 char *modname;
3154 const char *name = NULL;
3155 unsigned long offset, size;
3156
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003157 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 if (setjmp(bus_error_jmp) == 0) {
3159 catch_memory_errors = 1;
3160 sync();
3161 name = kallsyms_lookup(address, &size, &offset, &modname,
3162 tmpstr);
3163 sync();
3164 /* wait a little while to see if we get a machine check */
3165 __delay(200);
3166 }
3167
3168 catch_memory_errors = 0;
3169
3170 if (name) {
3171 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
3172 if (modname)
3173 printf(" [%s]", modname);
3174 }
3175 printf("%s", after);
3176}
3177
Aneesh Kumar K.Vcaca2852016-04-29 23:26:07 +10003178#ifdef CONFIG_PPC_STD_MMU_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10003179void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180{
3181 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05303182 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11003183 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184
Michael Ellerman736256e2014-05-26 21:02:14 +10003185 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186
Michael Neuling584f8b72007-12-06 17:24:48 +11003187 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11003188 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
3189 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Michael Ellerman85673642017-04-24 10:35:14 +10003190
3191 if (!esid && !vsid)
3192 continue;
3193
3194 printf("%02d %016lx %016lx", i, esid, vsid);
3195
3196 if (!(esid & SLB_ESID_V)) {
3197 printf("\n");
3198 continue;
3199 }
3200
3201 llp = vsid & SLB_VSID_LLP;
3202 if (vsid & SLB_VSID_B_1T) {
3203 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
3204 GET_ESID_1T(esid),
3205 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
3206 llp);
3207 } else {
3208 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
3209 GET_ESID(esid),
3210 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
3211 llp);
will schmidtb3b95952007-12-07 08:22:23 +11003212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 }
3214}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003215#endif
3216
3217#ifdef CONFIG_PPC_STD_MMU_32
3218void dump_segments(void)
3219{
3220 int i;
3221
3222 printf("sr0-15 =");
3223 for (i = 0; i < 16; ++i)
3224 printf(" %x", mfsrin(i));
3225 printf("\n");
3226}
3227#endif
3228
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003229#ifdef CONFIG_44x
3230static void dump_tlb_44x(void)
3231{
3232 int i;
3233
3234 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
3235 unsigned long w0,w1,w2;
3236 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
3237 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
3238 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
3239 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
3240 if (w0 & PPC44x_TLB_VALID) {
3241 printf("V %08x -> %01x%08x %c%c%c%c%c",
3242 w0 & PPC44x_TLB_EPN_MASK,
3243 w1 & PPC44x_TLB_ERPN_MASK,
3244 w1 & PPC44x_TLB_RPN_MASK,
3245 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
3246 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
3247 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
3248 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
3249 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
3250 }
3251 printf("\n");
3252 }
3253}
3254#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003255
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10003256#ifdef CONFIG_PPC_BOOK3E
3257static void dump_tlb_book3e(void)
3258{
3259 u32 mmucfg, pidmask, lpidmask;
3260 u64 ramask;
3261 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3262 int mmu_version;
3263 static const char *pgsz_names[] = {
3264 " 1K",
3265 " 2K",
3266 " 4K",
3267 " 8K",
3268 " 16K",
3269 " 32K",
3270 " 64K",
3271 "128K",
3272 "256K",
3273 "512K",
3274 " 1M",
3275 " 2M",
3276 " 4M",
3277 " 8M",
3278 " 16M",
3279 " 32M",
3280 " 64M",
3281 "128M",
3282 "256M",
3283 "512M",
3284 " 1G",
3285 " 2G",
3286 " 4G",
3287 " 8G",
3288 " 16G",
3289 " 32G",
3290 " 64G",
3291 "128G",
3292 "256G",
3293 "512G",
3294 " 1T",
3295 " 2T",
3296 };
3297
3298 /* Gather some infos about the MMU */
3299 mmucfg = mfspr(SPRN_MMUCFG);
3300 mmu_version = (mmucfg & 3) + 1;
3301 ntlbs = ((mmucfg >> 2) & 3) + 1;
3302 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3303 lpidsz = (mmucfg >> 24) & 0xf;
3304 rasz = (mmucfg >> 16) & 0x7f;
3305 if ((mmu_version > 1) && (mmucfg & 0x10000))
3306 lrat = 1;
3307 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3308 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3309 pidmask = (1ul << pidsz) - 1;
3310 lpidmask = (1ul << lpidsz) - 1;
3311 ramask = (1ull << rasz) - 1;
3312
3313 for (tlb = 0; tlb < ntlbs; tlb++) {
3314 u32 tlbcfg;
3315 int nent, assoc, new_cc = 1;
3316 printf("TLB %d:\n------\n", tlb);
3317 switch(tlb) {
3318 case 0:
3319 tlbcfg = mfspr(SPRN_TLB0CFG);
3320 break;
3321 case 1:
3322 tlbcfg = mfspr(SPRN_TLB1CFG);
3323 break;
3324 case 2:
3325 tlbcfg = mfspr(SPRN_TLB2CFG);
3326 break;
3327 case 3:
3328 tlbcfg = mfspr(SPRN_TLB3CFG);
3329 break;
3330 default:
3331 printf("Unsupported TLB number !\n");
3332 continue;
3333 }
3334 nent = tlbcfg & 0xfff;
3335 assoc = (tlbcfg >> 24) & 0xff;
3336 for (i = 0; i < nent; i++) {
3337 u32 mas0 = MAS0_TLBSEL(tlb);
3338 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3339 u64 mas2 = 0;
3340 u64 mas7_mas3;
3341 int esel = i, cc = i;
3342
3343 if (assoc != 0) {
3344 cc = i / assoc;
3345 esel = i % assoc;
3346 mas2 = cc * 0x1000;
3347 }
3348
3349 mas0 |= MAS0_ESEL(esel);
3350 mtspr(SPRN_MAS0, mas0);
3351 mtspr(SPRN_MAS1, mas1);
3352 mtspr(SPRN_MAS2, mas2);
3353 asm volatile("tlbre 0,0,0" : : : "memory");
3354 mas1 = mfspr(SPRN_MAS1);
3355 mas2 = mfspr(SPRN_MAS2);
3356 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3357 if (assoc && (i % assoc) == 0)
3358 new_cc = 1;
3359 if (!(mas1 & MAS1_VALID))
3360 continue;
3361 if (assoc == 0)
3362 printf("%04x- ", i);
3363 else if (new_cc)
3364 printf("%04x-%c", cc, 'A' + esel);
3365 else
3366 printf(" |%c", 'A' + esel);
3367 new_cc = 0;
3368 printf(" %016llx %04x %s %c%c AS%c",
3369 mas2 & ~0x3ffull,
3370 (mas1 >> 16) & 0x3fff,
3371 pgsz_names[(mas1 >> 7) & 0x1f],
3372 mas1 & MAS1_IND ? 'I' : ' ',
3373 mas1 & MAS1_IPROT ? 'P' : ' ',
3374 mas1 & MAS1_TS ? '1' : '0');
3375 printf(" %c%c%c%c%c%c%c",
3376 mas2 & MAS2_X0 ? 'a' : ' ',
3377 mas2 & MAS2_X1 ? 'v' : ' ',
3378 mas2 & MAS2_W ? 'w' : ' ',
3379 mas2 & MAS2_I ? 'i' : ' ',
3380 mas2 & MAS2_M ? 'm' : ' ',
3381 mas2 & MAS2_G ? 'g' : ' ',
3382 mas2 & MAS2_E ? 'e' : ' ');
3383 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3384 if (mas1 & MAS1_IND)
3385 printf(" %s\n",
3386 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3387 else
3388 printf(" U%c%c%c S%c%c%c\n",
3389 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3390 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3391 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3392 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3393 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3394 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3395 }
3396 }
3397}
3398#endif /* CONFIG_PPC_BOOK3E */
3399
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003400static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003402 if (enable) {
3403 __debugger = xmon;
3404 __debugger_ipi = xmon_ipi;
3405 __debugger_bpt = xmon_bpt;
3406 __debugger_sstep = xmon_sstep;
3407 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003408 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003409 __debugger_fault_handler = xmon_fault_handler;
3410 } else {
3411 __debugger = NULL;
3412 __debugger_ipi = NULL;
3413 __debugger_bpt = NULL;
3414 __debugger_sstep = NULL;
3415 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003416 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003417 __debugger_fault_handler = NULL;
3418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003420
3421#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003422static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003423{
3424 /* ensure xmon is enabled */
3425 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003426 debugger(get_irq_regs());
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003427 if (!xmon_on)
3428 xmon_init(0);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003429}
3430
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003431static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003432 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003433 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003434 .action_msg = "Entering xmon",
3435};
3436
3437static int __init setup_xmon_sysrq(void)
3438{
3439 register_sysrq_key('x', &sysrq_xmon_op);
3440 return 0;
3441}
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003442device_initcall(setup_xmon_sysrq);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003443#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003444
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003445#ifdef CONFIG_DEBUG_FS
3446static int xmon_dbgfs_set(void *data, u64 val)
3447{
3448 xmon_on = !!val;
3449 xmon_init(xmon_on);
3450
3451 return 0;
3452}
3453
3454static int xmon_dbgfs_get(void *data, u64 *val)
3455{
3456 *val = xmon_on;
3457 return 0;
3458}
3459
3460DEFINE_SIMPLE_ATTRIBUTE(xmon_dbgfs_ops, xmon_dbgfs_get,
3461 xmon_dbgfs_set, "%llu\n");
3462
3463static int __init setup_xmon_dbgfs(void)
3464{
3465 debugfs_create_file("xmon", 0600, powerpc_debugfs_root, NULL,
3466 &xmon_dbgfs_ops);
3467 return 0;
3468}
3469device_initcall(setup_xmon_dbgfs);
3470#endif /* CONFIG_DEBUG_FS */
3471
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003472static int xmon_early __initdata;
Michael Ellerman476792832006-10-03 14:12:08 +10003473
3474static int __init early_parse_xmon(char *p)
3475{
3476 if (!p || strncmp(p, "early", 5) == 0) {
3477 /* just "xmon" is equivalent to "xmon=early" */
3478 xmon_init(1);
3479 xmon_early = 1;
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003480 xmon_on = 1;
3481 } else if (strncmp(p, "on", 2) == 0) {
Michael Ellerman476792832006-10-03 14:12:08 +10003482 xmon_init(1);
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003483 xmon_on = 1;
3484 } else if (strncmp(p, "off", 3) == 0)
3485 xmon_on = 0;
Michael Ellerman476792832006-10-03 14:12:08 +10003486 else
3487 return 1;
3488
3489 return 0;
3490}
3491early_param("xmon", early_parse_xmon);
3492
3493void __init xmon_setup(void)
3494{
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003495 if (xmon_on)
Michael Ellerman476792832006-10-03 14:12:08 +10003496 xmon_init(1);
Michael Ellerman476792832006-10-03 14:12:08 +10003497 if (xmon_early)
3498 debugger(NULL);
3499}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003500
Arnd Bergmanne0555952006-11-27 19:18:55 +01003501#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003502
3503struct spu_info {
3504 struct spu *spu;
3505 u64 saved_mfc_sr1_RW;
3506 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003507 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003508 u8 stopped_ok;
3509};
3510
3511#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3512
3513static struct spu_info spu_info[XMON_NUM_SPUS];
3514
3515void xmon_register_spus(struct list_head *list)
3516{
3517 struct spu *spu;
3518
3519 list_for_each_entry(spu, list, full_list) {
3520 if (spu->number >= XMON_NUM_SPUS) {
3521 WARN_ON(1);
3522 continue;
3523 }
3524
3525 spu_info[spu->number].spu = spu;
3526 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003527 spu_info[spu->number].dump_addr = (unsigned long)
3528 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003529 }
3530}
3531
3532static void stop_spus(void)
3533{
3534 struct spu *spu;
3535 int i;
3536 u64 tmp;
3537
3538 for (i = 0; i < XMON_NUM_SPUS; i++) {
3539 if (!spu_info[i].spu)
3540 continue;
3541
3542 if (setjmp(bus_error_jmp) == 0) {
3543 catch_memory_errors = 1;
3544 sync();
3545
3546 spu = spu_info[i].spu;
3547
3548 spu_info[i].saved_spu_runcntl_RW =
3549 in_be32(&spu->problem->spu_runcntl_RW);
3550
3551 tmp = spu_mfc_sr1_get(spu);
3552 spu_info[i].saved_mfc_sr1_RW = tmp;
3553
3554 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3555 spu_mfc_sr1_set(spu, tmp);
3556
3557 sync();
3558 __delay(200);
3559
3560 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003561
3562 printf("Stopped spu %.2d (was %s)\n", i,
3563 spu_info[i].saved_spu_runcntl_RW ?
3564 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003565 } else {
3566 catch_memory_errors = 0;
3567 printf("*** Error stopping spu %.2d\n", i);
3568 }
3569 catch_memory_errors = 0;
3570 }
3571}
3572
3573static void restart_spus(void)
3574{
3575 struct spu *spu;
3576 int i;
3577
3578 for (i = 0; i < XMON_NUM_SPUS; i++) {
3579 if (!spu_info[i].spu)
3580 continue;
3581
3582 if (!spu_info[i].stopped_ok) {
3583 printf("*** Error, spu %d was not successfully stopped"
3584 ", not restarting\n", i);
3585 continue;
3586 }
3587
3588 if (setjmp(bus_error_jmp) == 0) {
3589 catch_memory_errors = 1;
3590 sync();
3591
3592 spu = spu_info[i].spu;
3593 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3594 out_be32(&spu->problem->spu_runcntl_RW,
3595 spu_info[i].saved_spu_runcntl_RW);
3596
3597 sync();
3598 __delay(200);
3599
3600 printf("Restarted spu %.2d\n", i);
3601 } else {
3602 catch_memory_errors = 0;
3603 printf("*** Error restarting spu %.2d\n", i);
3604 }
3605 catch_memory_errors = 0;
3606 }
3607}
3608
Michael Ellermana8984972006-10-24 18:31:28 +02003609#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003610#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003611do { \
3612 if (setjmp(bus_error_jmp) == 0) { \
3613 catch_memory_errors = 1; \
3614 sync(); \
3615 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003616 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003617 sync(); \
3618 __delay(200); \
3619 } else { \
3620 catch_memory_errors = 0; \
3621 printf(" %-*s = *** Error reading field.\n", \
3622 DUMP_WIDTH, #field); \
3623 } \
3624 catch_memory_errors = 0; \
3625} while (0)
3626
Michael Ellerman437a0702006-11-23 00:46:39 +01003627#define DUMP_FIELD(obj, format, field) \
3628 DUMP_VALUE(format, field, obj->field)
3629
Michael Ellermana8984972006-10-24 18:31:28 +02003630static void dump_spu_fields(struct spu *spu)
3631{
3632 printf("Dumping spu fields at address %p:\n", spu);
3633
3634 DUMP_FIELD(spu, "0x%x", number);
3635 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003636 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3637 DUMP_FIELD(spu, "0x%p", local_store);
3638 DUMP_FIELD(spu, "0x%lx", ls_size);
3639 DUMP_FIELD(spu, "0x%x", node);
3640 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003641 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003642 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003643 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3644 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003645 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3646 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3647 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3648 DUMP_FIELD(spu, "0x%x", slb_replace);
3649 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003650 DUMP_FIELD(spu, "0x%p", mm);
3651 DUMP_FIELD(spu, "0x%p", ctx);
3652 DUMP_FIELD(spu, "0x%p", rq);
3653 DUMP_FIELD(spu, "0x%p", timestamp);
3654 DUMP_FIELD(spu, "0x%lx", problem_phys);
3655 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003656 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3657 in_be32(&spu->problem->spu_runcntl_RW));
3658 DUMP_VALUE("0x%x", problem->spu_status_R,
3659 in_be32(&spu->problem->spu_status_R));
3660 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3661 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003662 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003663 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003664}
3665
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003666int
3667spu_inst_dump(unsigned long adr, long count, int praddr)
3668{
3669 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3670}
3671
3672static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003673{
3674 unsigned long offset, addr, ls_addr;
3675
3676 if (setjmp(bus_error_jmp) == 0) {
3677 catch_memory_errors = 1;
3678 sync();
3679 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3680 sync();
3681 __delay(200);
3682 } else {
3683 catch_memory_errors = 0;
3684 printf("*** Error: accessing spu info for spu %d\n", num);
3685 return;
3686 }
3687 catch_memory_errors = 0;
3688
3689 if (scanhex(&offset))
3690 addr = ls_addr + offset;
3691 else
3692 addr = spu_info[num].dump_addr;
3693
3694 if (addr >= ls_addr + LS_SIZE) {
3695 printf("*** Error: address outside of local store\n");
3696 return;
3697 }
3698
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003699 switch (subcmd) {
3700 case 'i':
3701 addr += spu_inst_dump(addr, 16, 1);
3702 last_cmd = "sdi\n";
3703 break;
3704 default:
3705 prdump(addr, 64);
3706 addr += 64;
3707 last_cmd = "sd\n";
3708 break;
3709 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003710
3711 spu_info[num].dump_addr = addr;
3712}
3713
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003714static int do_spu_cmd(void)
3715{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003716 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003717 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003718
3719 cmd = inchar();
3720 switch (cmd) {
3721 case 's':
3722 stop_spus();
3723 break;
3724 case 'r':
3725 restart_spus();
3726 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003727 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003728 subcmd = inchar();
3729 if (isxdigit(subcmd) || subcmd == '\n')
3730 termch = subcmd;
3731 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003732 scanhex(&num);
3733 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003734 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003735 return 0;
3736 }
3737
3738 switch (cmd) {
3739 case 'f':
3740 dump_spu_fields(spu_info[num].spu);
3741 break;
3742 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003743 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003744 break;
3745 }
3746
Michael Ellermana8984972006-10-24 18:31:28 +02003747 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003748 default:
3749 return -1;
3750 }
3751
3752 return 0;
3753}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003754#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003755static int do_spu_cmd(void)
3756{
3757 return -1;
3758}
3759#endif