blob: c5e155108be5ac65dc3de9f0b9eb469aa1eb3d26 [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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/smp.h>
16#include <linux/mm.h>
17#include <linux/reboot.h>
18#include <linux/delay.h>
19#include <linux/kallsyms.h>
Michael Ellermanca5dd392012-08-23 22:09:12 +000020#include <linux/kmsg_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040022#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110023#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080024#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010025#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080026#include <linux/bug.h>
Anton Blancharda71d64b2014-08-05 14:55:00 +100027#include <linux/nmi.h>
Vincent Bernat05b981f2014-07-15 13:43:47 +020028#include <linux/ctype.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <asm/ptrace.h>
31#include <asm/string.h>
32#include <asm/prom.h>
33#include <asm/machdep.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100034#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/processor.h>
36#include <asm/pgtable.h>
37#include <asm/mmu.h>
38#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/cputable.h>
40#include <asm/rtas.h>
41#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100042#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020043#include <asm/spu.h>
44#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110045#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000046#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010047#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000048#include <asm/hw_breakpoint.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100049
Andrew Donnellanfde93a02016-02-09 18:17:49 +110050#include <asm/opal.h>
51#include <asm/firmware.h>
52
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100053#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100055#include <asm/paca.h>
56#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Anshuman Khandual1ad7d702014-11-28 10:06:42 +053058#if defined(CONFIG_PPC_SPLPAR)
59#include <asm/plpar_wrappers.h>
60#else
61static inline long plapr_set_ciabr(unsigned long ciabr) {return 0; };
62#endif
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010065#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100068static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069static unsigned long xmon_taken = 1;
70static int xmon_owner;
71static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000072#else
73#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#endif /* CONFIG_SMP */
75
Anton Blanchard5be34922010-01-12 00:50:14 +000076static unsigned long in_xmon __read_mostly = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78static unsigned long adrs;
79static int size = 1;
80#define MAX_DUMP (128 * 1024)
81static unsigned long ndump = 64;
82static unsigned long nidump = 16;
83static unsigned long ncsum = 4096;
84static int termch;
85static char tmpstr[128];
86
Linus Torvalds1da177e2005-04-16 15:20:36 -070087static long bus_error_jmp[JMP_BUF_LEN];
88static int catch_memory_errors;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +100089static int catch_spr_faults;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92/* Breakpoint stuff */
93struct bpt {
94 unsigned long address;
95 unsigned int instr[2];
96 atomic_t ref_count;
97 int enabled;
98 unsigned long pad;
99};
100
101/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100102#define BP_CIABR 1
103#define BP_TRAP 2
104#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
106#define NBPTS 256
107static struct bpt bpts[NBPTS];
108static struct bpt dabr;
109static struct bpt *iabr;
110static unsigned bpinstr = 0x7fe00008; /* trap */
111
112#define BP_NUM(bp) ((bp) - bpts + 1)
113
114/* Prototypes */
115static int cmds(struct pt_regs *);
116static int mread(unsigned long, void *, int);
117static int mwrite(unsigned long, void *, int);
118static int handle_fault(struct pt_regs *);
119static void byterev(unsigned char *, int);
120static void memex(void);
121static int bsesc(void);
122static void dump(void);
123static void prdump(unsigned long, long);
124static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000125static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100126
127#ifdef CONFIG_PPC_POWERNV
128static void dump_opal_msglog(void);
129#else
130static inline void dump_opal_msglog(void)
131{
132 printf("Machine is not running OPAL firmware.\n");
133}
134#endif
135
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136static void backtrace(struct pt_regs *);
137static void excprint(struct pt_regs *);
138static void prregs(struct pt_regs *);
139static void memops(int);
140static void memlocate(void);
141static void memzcan(void);
142static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
143int skipbl(void);
144int scanhex(unsigned long *valp);
145static void scannl(void);
146static int hexdigit(int);
147void getstring(char *, int);
148static void flush_input(void);
149static int inchar(void);
150static void take_input(char *);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000151static int read_spr(int, unsigned long *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static void write_spr(int, unsigned long);
153static void super_regs(void);
154static void remove_bpts(void);
155static void insert_bpts(void);
156static void remove_cpu_bpts(void);
157static void insert_cpu_bpts(void);
158static struct bpt *at_breakpoint(unsigned long pc);
159static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
160static int do_step(struct pt_regs *);
161static void bpt_cmds(void);
162static void cacheflush(void);
163static int cpu_cmd(void);
164static void csum(void);
165static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000166static void proccall(void);
Douglas Miller6dfb5402015-11-23 09:01:15 -0600167static void show_tasks(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168void dump_segments(void);
169static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200170static void xmon_show_stack(unsigned long sp, unsigned long lr,
171 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static void xmon_print_symbol(unsigned long address, const char *mid,
173 const char *after);
174static const char *getvecname(unsigned long vec);
175
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200176static int do_spu_cmd(void);
177
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100178#ifdef CONFIG_44x
179static void dump_tlb_44x(void);
180#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000181#ifdef CONFIG_PPC_BOOK3E
182static void dump_tlb_book3e(void);
183#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100184
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000185static int xmon_no_auto_backtrace;
Olaf Hering26c8af52006-09-08 16:29:21 +0200186
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000187extern void xmon_enter(void);
188extern void xmon_leave(void);
189
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\
216 di dump instructions\n\
217 df dump float values\n\
218 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000219 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100220#ifdef CONFIG_PPC_POWERNV
221 "\
222 do dump the OPAL message log\n"
223#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000224#ifdef CONFIG_PPC64
225 "\
226 dp[#] dump paca for current cpu, or cpu #\n\
227 dpa dump paca for all possible cpus\n"
228#endif
229 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100230 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 e print exception information\n\
232 f flush cache\n\
233 la lookup symbol+offset of specified address\n\
234 ls lookup address of specified symbol\n\
235 m examine/change memory\n\
236 mm move a block of memory\n\
237 ms set a block of memory\n\
238 md compare two blocks of memory\n\
239 ml locate a block of memory\n\
240 mz zero a block of memory\n\
241 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000242 p call a procedure\n\
Douglas Miller6dfb5402015-11-23 09:01:15 -0600243 P list processes/tasks\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200245 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100246#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200247" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200248 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100249 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900250 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100251 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200252#endif
253" S print special registers\n\
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000254 Sa print all SPRs\n\
255 Sr # read SPR #\n\
256 Sw #v write v to SPR #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100259 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000260#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000261" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000262#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000263" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000264#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100265" u dump TLB\n"
266#endif
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000267" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100268" # n limit output to n lines per page (for dp, dpa, dl)\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000269" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 zh halt\n"
271;
272
273static struct pt_regs *xmon_regs;
274
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000275static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
277 asm volatile("sync; isync");
278}
279
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000280static inline void store_inst(void *p)
281{
282 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
283}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000285static inline void cflush(void *p)
286{
287 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
288}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000290static inline void cinval(void *p)
291{
292 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
293}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530295/**
296 * write_ciabr() - write the CIABR SPR
297 * @ciabr: The value to write.
298 *
299 * This function writes a value to the CIARB register either directly
300 * through mtspr instruction if the kernel is in HV privilege mode or
301 * call a hypervisor function to achieve the same in case the kernel
302 * is in supervisor privilege mode.
303 */
304static void write_ciabr(unsigned long ciabr)
305{
306 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
307 return;
308
309 if (cpu_has_feature(CPU_FTR_HVMODE)) {
310 mtspr(SPRN_CIABR, ciabr);
311 return;
312 }
313 plapr_set_ciabr(ciabr);
314}
315
316/**
317 * set_ciabr() - set the CIABR
318 * @addr: The value to set.
319 *
320 * This function sets the correct privilege value into the the HW
321 * breakpoint address before writing it up in the CIABR register.
322 */
323static void set_ciabr(unsigned long addr)
324{
325 addr &= ~CIABR_PRIV;
326
327 if (cpu_has_feature(CPU_FTR_HVMODE))
328 addr |= CIABR_PRIV_HYPER;
329 else
330 addr |= CIABR_PRIV_SUPER;
331 write_ciabr(addr);
332}
333
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334/*
335 * Disable surveillance (the service processor watchdog function)
336 * while we are in xmon.
337 * XXX we should re-enable it when we leave. :)
338 */
339#define SURVEILLANCE_TOKEN 9000
340
341static inline void disable_surveillance(void)
342{
343#ifdef CONFIG_PPC_PSERIES
344 /* Since this can't be a module, args should end up below 4GB. */
345 static struct rtas_args args;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100346 int token;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
348 /*
349 * At this point we have got all the cpus we can into
350 * xmon, so there is hopefully no other cpu calling RTAS
351 * at the moment, even though we don't take rtas.lock.
352 * If we did try to take rtas.lock there would be a
353 * real possibility of deadlock.
354 */
Michael Ellerman08eb1052015-11-24 22:26:09 +1100355 token = rtas_token("set-indicator");
356 if (token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100358
359 rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0);
360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361#endif /* CONFIG_PPC_PSERIES */
362}
363
364#ifdef CONFIG_SMP
365static int xmon_speaker;
366
367static void get_output_lock(void)
368{
369 int me = smp_processor_id() + 0x100;
370 int last_speaker = 0, prev;
371 long timeout;
372
373 if (xmon_speaker == me)
374 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100375
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100377 last_speaker = cmpxchg(&xmon_speaker, 0, me);
378 if (last_speaker == 0)
379 return;
380
Michael Ellerman15075892013-12-23 23:46:05 +1100381 /*
382 * Wait a full second for the lock, we might be on a slow
383 * console, but check every 100us.
384 */
385 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100387 if (--timeout > 0) {
388 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100390 }
391
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 /* hostile takeover */
393 prev = cmpxchg(&xmon_speaker, last_speaker, me);
394 if (prev == last_speaker)
395 return;
396 break;
397 }
398 }
399}
400
401static void release_output_lock(void)
402{
403 xmon_speaker = 0;
404}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000405
406int cpus_are_in_xmon(void)
407{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000408 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000409}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410#endif
411
Josh Boyerdaf8f402009-09-23 03:51:04 +0000412static inline int unrecoverable_excp(struct pt_regs *regs)
413{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000414#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000415 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000416 return 0;
417#else
418 return ((regs->msr & MSR_RI) == 0);
419#endif
420}
421
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000422static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423{
424 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 struct bpt *bp;
426 long recurse_jmp[JMP_BUF_LEN];
427 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100428 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429#ifdef CONFIG_SMP
430 int cpu;
431 int secondary;
432 unsigned long timeout;
433#endif
434
Anton Blanchardf13659e2007-03-21 01:48:34 +1100435 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000436 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
438 bp = in_breakpoint_table(regs->nip, &offset);
439 if (bp != NULL) {
440 regs->nip = bp->address + offset;
441 atomic_dec(&bp->ref_count);
442 }
443
444 remove_cpu_bpts();
445
446#ifdef CONFIG_SMP
447 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000448 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000449 /*
450 * We catch SPR read/write faults here because the 0x700, 0xf60
451 * etc. handlers don't call debugger_fault_handler().
452 */
453 if (catch_spr_faults)
454 longjmp(bus_error_jmp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 get_output_lock();
456 excprint(regs);
457 printf("cpu 0x%x: Exception %lx %s in xmon, "
458 "returning to main loop\n",
459 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000460 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 longjmp(xmon_fault_jmp[cpu], 1);
462 }
463
464 if (setjmp(recurse_jmp) != 0) {
465 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000466 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 printf("xmon: WARNING: bad recursive fault "
468 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000469 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 goto waiting;
471 }
472 secondary = !(xmon_taken && cpu == xmon_owner);
473 goto cmdloop;
474 }
475
476 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477
478 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000479 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000481 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 fromipi = 0;
483
484 if (!fromipi) {
485 get_output_lock();
486 excprint(regs);
487 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000488 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 cpu, BP_NUM(bp));
490 xmon_print_symbol(regs->nip, " ", ")\n");
491 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000492 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 printf("WARNING: exception is not recoverable, "
494 "can't continue\n");
495 release_output_lock();
496 }
497
Michael Ellermand2b496e2013-12-23 23:46:06 +1100498 cpumask_set_cpu(cpu, &cpus_in_xmon);
499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 waiting:
501 secondary = 1;
502 while (secondary && !xmon_gate) {
503 if (in_xmon == 0) {
504 if (fromipi)
505 goto leave;
506 secondary = test_and_set_bit(0, &in_xmon);
507 }
508 barrier();
509 }
510
511 if (!secondary && !xmon_gate) {
512 /* we are the first cpu to come in */
513 /* interrupt other cpu(s) */
514 int ncpus = num_online_cpus();
515
516 xmon_owner = cpu;
517 mb();
518 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000519 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 /* wait for other cpus to come in */
521 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000522 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 break;
524 barrier();
525 }
526 }
527 remove_bpts();
528 disable_surveillance();
529 /* for breakpoint or single step, print the current instr. */
530 if (bp || TRAP(regs) == 0xd00)
531 ppc_inst_dump(regs->nip, 1, 0);
532 printf("enter ? for help\n");
533 mb();
534 xmon_gate = 1;
535 barrier();
536 }
537
538 cmdloop:
539 while (in_xmon) {
540 if (secondary) {
541 if (cpu == xmon_owner) {
542 if (!test_and_set_bit(0, &xmon_taken)) {
543 secondary = 0;
544 continue;
545 }
546 /* missed it */
547 while (cpu == xmon_owner)
548 barrier();
549 }
550 barrier();
551 } else {
552 cmd = cmds(regs);
553 if (cmd != 0) {
554 /* exiting xmon */
555 insert_bpts();
556 xmon_gate = 0;
557 wmb();
558 in_xmon = 0;
559 break;
560 }
561 /* have switched to some other cpu */
562 secondary = 1;
563 }
564 }
565 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000566 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568#else
569 /* UP is simple... */
570 if (in_xmon) {
571 printf("Exception %lx %s in xmon, returning to main loop\n",
572 regs->trap, getvecname(TRAP(regs)));
573 longjmp(xmon_fault_jmp[0], 1);
574 }
575 if (setjmp(recurse_jmp) == 0) {
576 xmon_fault_jmp[0] = recurse_jmp;
577 in_xmon = 1;
578
579 excprint(regs);
580 bp = at_breakpoint(regs->nip);
581 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000582 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 xmon_print_symbol(regs->nip, " ", ")\n");
584 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000585 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 printf("WARNING: exception is not recoverable, "
587 "can't continue\n");
588 remove_bpts();
589 disable_surveillance();
590 /* for breakpoint or single step, print the current instr. */
591 if (bp || TRAP(regs) == 0xd00)
592 ppc_inst_dump(regs->nip, 1, 0);
593 printf("enter ? for help\n");
594 }
595
596 cmd = cmds(regs);
597
598 insert_bpts();
599 in_xmon = 0;
600#endif
601
Josh Boyercdd39042009-10-05 04:46:05 +0000602#ifdef CONFIG_BOOKE
603 if (regs->msr & MSR_DE) {
604 bp = at_breakpoint(regs->nip);
605 if (bp != NULL) {
606 regs->nip = (unsigned long) &bp->instr[0];
607 atomic_inc(&bp->ref_count);
608 }
609 }
610#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000611 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 bp = at_breakpoint(regs->nip);
613 if (bp != NULL) {
614 int stepped = emulate_step(regs, bp->instr[0]);
615 if (stepped == 0) {
616 regs->nip = (unsigned long) &bp->instr[0];
617 atomic_inc(&bp->ref_count);
618 } else if (stepped < 0) {
619 printf("Couldn't single-step %s instruction\n",
620 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
621 }
622 }
623 }
Josh Boyercdd39042009-10-05 04:46:05 +0000624#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 insert_cpu_bpts();
626
Anton Blancharda71d64b2014-08-05 14:55:00 +1000627 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100628 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000630 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632
633int xmon(struct pt_regs *excp)
634{
635 struct pt_regs regs;
636
637 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000638 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 excp = &regs;
640 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200641
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 return xmon_core(excp, 0);
643}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000644EXPORT_SYMBOL(xmon);
645
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000646irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000647{
648 unsigned long flags;
649 local_irq_save(flags);
650 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000651 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000652 local_irq_restore(flags);
653 return IRQ_HANDLED;
654}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000656static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657{
658 struct bpt *bp;
659 unsigned long offset;
660
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000661 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 return 0;
663
664 /* Are we at the trap at bp->instr[1] for some bp? */
665 bp = in_breakpoint_table(regs->nip, &offset);
666 if (bp != NULL && offset == 4) {
667 regs->nip = bp->address + 4;
668 atomic_dec(&bp->ref_count);
669 return 1;
670 }
671
672 /* Are we at a breakpoint? */
673 bp = at_breakpoint(regs->nip);
674 if (!bp)
675 return 0;
676
677 xmon_core(regs, 0);
678
679 return 1;
680}
681
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000682static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683{
684 if (user_mode(regs))
685 return 0;
686 xmon_core(regs, 0);
687 return 1;
688}
689
Michael Neuling9422de32012-12-20 14:06:44 +0000690static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000692 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000694 if (dabr.enabled == 0)
695 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 xmon_core(regs, 0);
697 return 1;
698}
699
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000700static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000702 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000704 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 return 0;
706 xmon_core(regs, 0);
707 return 1;
708}
709
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000710static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{
712#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000713 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 xmon_core(regs, 1);
715#endif
716 return 0;
717}
718
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000719static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720{
721 struct bpt *bp;
722 unsigned long offset;
723
724 if (in_xmon && catch_memory_errors)
725 handle_fault(regs); /* doesn't return */
726
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000727 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 bp = in_breakpoint_table(regs->nip, &offset);
729 if (bp != NULL) {
730 regs->nip = bp->address + offset;
731 atomic_dec(&bp->ref_count);
732 }
733 }
734
735 return 0;
736}
737
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738static struct bpt *at_breakpoint(unsigned long pc)
739{
740 int i;
741 struct bpt *bp;
742
743 bp = bpts;
744 for (i = 0; i < NBPTS; ++i, ++bp)
745 if (bp->enabled && pc == bp->address)
746 return bp;
747 return NULL;
748}
749
750static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
751{
752 unsigned long off;
753
754 off = nip - (unsigned long) bpts;
755 if (off >= sizeof(bpts))
756 return NULL;
757 off %= sizeof(struct bpt);
758 if (off != offsetof(struct bpt, instr[0])
759 && off != offsetof(struct bpt, instr[1]))
760 return NULL;
761 *offp = off - offsetof(struct bpt, instr[0]);
762 return (struct bpt *) (nip - off);
763}
764
765static struct bpt *new_breakpoint(unsigned long a)
766{
767 struct bpt *bp;
768
769 a &= ~3UL;
770 bp = at_breakpoint(a);
771 if (bp)
772 return bp;
773
774 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
775 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
776 bp->address = a;
777 bp->instr[1] = bpinstr;
778 store_inst(&bp->instr[1]);
779 return bp;
780 }
781 }
782
783 printf("Sorry, no free breakpoints. Please clear one first.\n");
784 return NULL;
785}
786
787static void insert_bpts(void)
788{
789 int i;
790 struct bpt *bp;
791
792 bp = bpts;
793 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100794 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 continue;
796 if (mread(bp->address, &bp->instr[0], 4) != 4) {
797 printf("Couldn't read instruction at %lx, "
798 "disabling breakpoint there\n", bp->address);
799 bp->enabled = 0;
800 continue;
801 }
802 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
803 printf("Breakpoint at %lx is on an mtmsrd or rfid "
804 "instruction, disabling it\n", bp->address);
805 bp->enabled = 0;
806 continue;
807 }
808 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100809 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 continue;
811 if (mwrite(bp->address, &bpinstr, 4) != 4) {
812 printf("Couldn't write instruction at %lx, "
813 "disabling breakpoint there\n", bp->address);
814 bp->enabled &= ~BP_TRAP;
815 continue;
816 }
817 store_inst((void *)bp->address);
818 }
819}
820
821static void insert_cpu_bpts(void)
822{
Michael Neuling9422de32012-12-20 14:06:44 +0000823 struct arch_hw_breakpoint brk;
824
825 if (dabr.enabled) {
826 brk.address = dabr.address;
827 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
828 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400829 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000830 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530831
832 if (iabr)
833 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834}
835
836static void remove_bpts(void)
837{
838 int i;
839 struct bpt *bp;
840 unsigned instr;
841
842 bp = bpts;
843 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100844 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 continue;
846 if (mread(bp->address, &instr, 4) == 4
847 && instr == bpinstr
848 && mwrite(bp->address, &bp->instr, 4) != 4)
849 printf("Couldn't remove breakpoint at %lx\n",
850 bp->address);
851 else
852 store_inst((void *)bp->address);
853 }
854}
855
856static void remove_cpu_bpts(void)
857{
Michael Neuling9422de32012-12-20 14:06:44 +0000858 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530859 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
Sam bobroff958b7c82015-10-08 11:50:23 +1100862static void set_lpp_cmd(void)
863{
864 unsigned long lpp;
865
866 if (!scanhex(&lpp)) {
867 printf("Invalid number.\n");
868 lpp = 0;
869 }
870 xmon_set_pagination_lpp(lpp);
871}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872/* Command interpreting routine */
873static char *last_cmd;
874
875static int
876cmds(struct pt_regs *excp)
877{
878 int cmd = 0;
879
880 last_cmd = NULL;
881 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200882
883 if (!xmon_no_auto_backtrace) {
884 xmon_no_auto_backtrace = 1;
885 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
886 }
887
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 for(;;) {
889#ifdef CONFIG_SMP
890 printf("%x:", smp_processor_id());
891#endif /* CONFIG_SMP */
892 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 flush_input();
894 termch = 0;
895 cmd = skipbl();
896 if( cmd == '\n' ) {
897 if (last_cmd == NULL)
898 continue;
899 take_input(last_cmd);
900 last_cmd = NULL;
901 cmd = inchar();
902 }
903 switch (cmd) {
904 case 'm':
905 cmd = inchar();
906 switch (cmd) {
907 case 'm':
908 case 's':
909 case 'd':
910 memops(cmd);
911 break;
912 case 'l':
913 memlocate();
914 break;
915 case 'z':
916 memzcan();
917 break;
918 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700919 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 break;
921 default:
922 termch = cmd;
923 memex();
924 }
925 break;
926 case 'd':
927 dump();
928 break;
929 case 'l':
930 symbol_lookup();
931 break;
932 case 'r':
933 prregs(excp); /* print regs */
934 break;
935 case 'e':
936 excprint(excp);
937 break;
938 case 'S':
939 super_regs();
940 break;
941 case 't':
942 backtrace(excp);
943 break;
944 case 'f':
945 cacheflush();
946 break;
947 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200948 if (do_spu_cmd() == 0)
949 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 if (do_step(excp))
951 return cmd;
952 break;
953 case 'x':
954 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100955 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100957 printf(" <no input ...>\n");
958 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 return cmd;
960 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000961 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 break;
Sam bobroff958b7c82015-10-08 11:50:23 +1100963 case '#':
964 set_lpp_cmd();
965 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 case 'b':
967 bpt_cmds();
968 break;
969 case 'C':
970 csum();
971 break;
972 case 'c':
973 if (cpu_cmd())
974 return 0;
975 break;
976 case 'z':
977 bootcmds();
978 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000979 case 'p':
980 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -0600982 case 'P':
983 show_tasks();
984 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000985#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 case 'u':
987 dump_segments();
988 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +1100989#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100990 case 'u':
991 dump_tlb_44x();
992 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000993#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000994 case 'u':
995 dump_tlb_book3e();
996 break;
997#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 default:
999 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +00001000 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 if (' ' < cmd && cmd <= '~')
1002 putchar(cmd);
1003 else
1004 printf("\\x%x", cmd);
1005 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +00001006 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 printf(" (type ? for help)\n");
1008 break;
1009 }
1010 }
1011}
1012
Josh Boyercdd39042009-10-05 04:46:05 +00001013#ifdef CONFIG_BOOKE
1014static int do_step(struct pt_regs *regs)
1015{
1016 regs->msr |= MSR_DE;
1017 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1018 return 1;
1019}
1020#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021/*
1022 * Step a single instruction.
1023 * Some instructions we emulate, others we execute with MSR_SE set.
1024 */
1025static int do_step(struct pt_regs *regs)
1026{
1027 unsigned int instr;
1028 int stepped;
1029
1030 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001031 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 if (mread(regs->nip, &instr, 4) == 4) {
1033 stepped = emulate_step(regs, instr);
1034 if (stepped < 0) {
1035 printf("Couldn't single-step %s instruction\n",
1036 (IS_RFID(instr)? "rfid": "mtmsrd"));
1037 return 0;
1038 }
1039 if (stepped > 0) {
1040 regs->trap = 0xd00 | (regs->trap & 1);
1041 printf("stepped to ");
1042 xmon_print_symbol(regs->nip, " ", "\n");
1043 ppc_inst_dump(regs->nip, 1, 0);
1044 return 0;
1045 }
1046 }
1047 }
1048 regs->msr |= MSR_SE;
1049 return 1;
1050}
Josh Boyercdd39042009-10-05 04:46:05 +00001051#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
1053static void bootcmds(void)
1054{
1055 int cmd;
1056
1057 cmd = inchar();
1058 if (cmd == 'r')
1059 ppc_md.restart(NULL);
1060 else if (cmd == 'h')
1061 ppc_md.halt();
1062 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001063 if (pm_power_off)
1064 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065}
1066
1067static int cpu_cmd(void)
1068{
1069#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001070 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
1073 if (!scanhex(&cpu)) {
1074 /* print cpus waiting or in xmon */
1075 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001076 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001077 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001078 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001079 if (cpu == last_cpu + 1) {
1080 last_cpu = cpu;
1081 } else {
1082 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001083 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001084 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001085 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001086 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 }
1088 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001089 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001090 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 printf("\n");
1092 return 0;
1093 }
1094 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001095 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 printf("cpu 0x%x isn't in xmon\n", cpu);
1097 return 0;
1098 }
1099 xmon_taken = 0;
1100 mb();
1101 xmon_owner = cpu;
1102 timeout = 10000000;
1103 while (!xmon_taken) {
1104 if (--timeout == 0) {
1105 if (test_and_set_bit(0, &xmon_taken))
1106 break;
1107 /* take control back */
1108 mb();
1109 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001110 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 return 0;
1112 }
1113 barrier();
1114 }
1115 return 1;
1116#else
1117 return 0;
1118#endif /* CONFIG_SMP */
1119}
1120
1121static unsigned short fcstab[256] = {
1122 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1123 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1124 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1125 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1126 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1127 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1128 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1129 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1130 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1131 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1132 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1133 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1134 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1135 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1136 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1137 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1138 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1139 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1140 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1141 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1142 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1143 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1144 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1145 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1146 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1147 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1148 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1149 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1150 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1151 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1152 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1153 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1154};
1155
1156#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1157
1158static void
1159csum(void)
1160{
1161 unsigned int i;
1162 unsigned short fcs;
1163 unsigned char v;
1164
1165 if (!scanhex(&adrs))
1166 return;
1167 if (!scanhex(&ncsum))
1168 return;
1169 fcs = 0xffff;
1170 for (i = 0; i < ncsum; ++i) {
1171 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001172 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 break;
1174 }
1175 fcs = FCS(fcs, v);
1176 }
1177 printf("%x\n", fcs);
1178}
1179
1180/*
1181 * Check if this is a suitable place to put a breakpoint.
1182 */
1183static long check_bp_loc(unsigned long addr)
1184{
1185 unsigned int instr;
1186
1187 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001188 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 printf("Breakpoints may only be placed at kernel addresses\n");
1190 return 0;
1191 }
1192 if (!mread(addr, &instr, sizeof(instr))) {
1193 printf("Can't read instruction at address %lx\n", addr);
1194 return 0;
1195 }
1196 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1197 printf("Breakpoints may not be placed on mtmsrd or rfid "
1198 "instructions\n");
1199 return 0;
1200 }
1201 return 1;
1202}
1203
Michael Ellermane3bc8042012-08-23 22:09:13 +00001204static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 "Breakpoint command usage:\n"
1206 "b show breakpoints\n"
1207 "b <addr> [cnt] set breakpoint at given instr addr\n"
1208 "bc clear all breakpoints\n"
1209 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301210 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 "bd <addr> [cnt] set hardware data breakpoint\n"
1212 "";
1213
1214static void
1215bpt_cmds(void)
1216{
1217 int cmd;
1218 unsigned long a;
1219 int mode, i;
1220 struct bpt *bp;
1221 const char badaddr[] = "Only kernel addresses are permitted "
1222 "for breakpoints\n";
1223
1224 cmd = inchar();
1225 switch (cmd) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001226#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 case 'd': /* bd - hardware data breakpoint */
1228 mode = 7;
1229 cmd = inchar();
1230 if (cmd == 'r')
1231 mode = 5;
1232 else if (cmd == 'w')
1233 mode = 6;
1234 else
1235 termch = cmd;
1236 dabr.address = 0;
1237 dabr.enabled = 0;
1238 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001239 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 printf(badaddr);
1241 break;
1242 }
Michael Neuling9422de32012-12-20 14:06:44 +00001243 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 dabr.enabled = mode | BP_DABR;
1245 }
1246 break;
1247
1248 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301249 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 printf("Hardware instruction breakpoint "
1251 "not supported on this cpu\n");
1252 break;
1253 }
1254 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001255 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 iabr = NULL;
1257 }
1258 if (!scanhex(&a))
1259 break;
1260 if (!check_bp_loc(a))
1261 break;
1262 bp = new_breakpoint(a);
1263 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001264 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 iabr = bp;
1266 }
1267 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001268#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270 case 'c':
1271 if (!scanhex(&a)) {
1272 /* clear all breakpoints */
1273 for (i = 0; i < NBPTS; ++i)
1274 bpts[i].enabled = 0;
1275 iabr = NULL;
1276 dabr.enabled = 0;
1277 printf("All breakpoints cleared\n");
1278 break;
1279 }
1280
1281 if (a <= NBPTS && a >= 1) {
1282 /* assume a breakpoint number */
1283 bp = &bpts[a-1]; /* bp nums are 1 based */
1284 } else {
1285 /* assume a breakpoint address */
1286 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001287 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001288 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 break;
1290 }
1291 }
1292
Michael Ellerman736256e2014-05-26 21:02:14 +10001293 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 xmon_print_symbol(bp->address, " ", ")\n");
1295 bp->enabled = 0;
1296 break;
1297
1298 default:
1299 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001300 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 if (cmd == '?') {
1302 printf(breakpoint_help_string);
1303 break;
1304 }
1305 termch = cmd;
1306 if (!scanhex(&a)) {
1307 /* print all breakpoints */
1308 printf(" type address\n");
1309 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001310 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 if (dabr.enabled & 1)
1312 printf("r");
1313 if (dabr.enabled & 2)
1314 printf("w");
1315 printf("]\n");
1316 }
1317 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1318 if (!bp->enabled)
1319 continue;
1320 printf("%2x %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001321 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 xmon_print_symbol(bp->address, " ", "\n");
1323 }
1324 break;
1325 }
1326
1327 if (!check_bp_loc(a))
1328 break;
1329 bp = new_breakpoint(a);
1330 if (bp != NULL)
1331 bp->enabled |= BP_TRAP;
1332 break;
1333 }
1334}
1335
1336/* Very cheap human name for vector lookup. */
1337static
1338const char *getvecname(unsigned long vec)
1339{
1340 char *ret;
1341
1342 switch (vec) {
1343 case 0x100: ret = "(System Reset)"; break;
1344 case 0x200: ret = "(Machine Check)"; break;
1345 case 0x300: ret = "(Data Access)"; break;
1346 case 0x380: ret = "(Data SLB Access)"; break;
1347 case 0x400: ret = "(Instruction Access)"; break;
1348 case 0x480: ret = "(Instruction SLB Access)"; break;
1349 case 0x500: ret = "(Hardware Interrupt)"; break;
1350 case 0x600: ret = "(Alignment)"; break;
1351 case 0x700: ret = "(Program Check)"; break;
1352 case 0x800: ret = "(FPU Unavailable)"; break;
1353 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001354 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1355 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 case 0xc00: ret = "(System Call)"; break;
1357 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001358 case 0xe40: ret = "(Emulation Assist)"; break;
1359 case 0xe60: ret = "(HMI)"; break;
1360 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 case 0xf00: ret = "(Performance Monitor)"; break;
1362 case 0xf20: ret = "(Altivec Unavailable)"; break;
1363 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001364 case 0x1500: ret = "(Denormalisation)"; break;
1365 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 default: ret = "";
1367 }
1368 return ret;
1369}
1370
1371static void get_function_bounds(unsigned long pc, unsigned long *startp,
1372 unsigned long *endp)
1373{
1374 unsigned long size, offset;
1375 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
1377 *startp = *endp = 0;
1378 if (pc == 0)
1379 return;
1380 if (setjmp(bus_error_jmp) == 0) {
1381 catch_memory_errors = 1;
1382 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001383 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 if (name != NULL) {
1385 *startp = pc - offset;
1386 *endp = pc - offset + size;
1387 }
1388 sync();
1389 }
1390 catch_memory_errors = 0;
1391}
1392
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001393#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1394#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396static void xmon_show_stack(unsigned long sp, unsigned long lr,
1397 unsigned long pc)
1398{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001399 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 unsigned long ip;
1401 unsigned long newsp;
1402 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 struct pt_regs regs;
1404
Michael Ellerman0104cd62012-10-09 04:20:36 +00001405 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 if (sp < PAGE_OFFSET) {
1407 if (sp != 0)
1408 printf("SP (%lx) is in userspace\n", sp);
1409 break;
1410 }
1411
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001412 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 || !mread(sp, &newsp, sizeof(unsigned long))) {
1414 printf("Couldn't read stack frame at %lx\n", sp);
1415 break;
1416 }
1417
1418 /*
1419 * For the first stack frame, try to work out if
1420 * LR and/or the saved LR value in the bottommost
1421 * stack frame are valid.
1422 */
1423 if ((pc | lr) != 0) {
1424 unsigned long fnstart, fnend;
1425 unsigned long nextip;
1426 int printip = 1;
1427
1428 get_function_bounds(pc, &fnstart, &fnend);
1429 nextip = 0;
1430 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001431 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 sizeof(unsigned long));
1433 if (lr == ip) {
1434 if (lr < PAGE_OFFSET
1435 || (fnstart <= lr && lr < fnend))
1436 printip = 0;
1437 } else if (lr == nextip) {
1438 printip = 0;
1439 } else if (lr >= PAGE_OFFSET
1440 && !(fnstart <= lr && lr < fnend)) {
1441 printf("[link register ] ");
1442 xmon_print_symbol(lr, " ", "\n");
1443 }
1444 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001445 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 xmon_print_symbol(ip, " ", " (unreliable)\n");
1447 }
1448 pc = lr = 0;
1449
1450 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001451 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 xmon_print_symbol(ip, " ", "\n");
1453 }
1454
1455 /* Look for "regshere" marker to see if this is
1456 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001457 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001458 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001459 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 != sizeof(regs)) {
1461 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001462 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 break;
1464 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001465 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 getvecname(TRAP(&regs)));
1467 pc = regs.nip;
1468 lr = regs.link;
1469 xmon_print_symbol(pc, " ", "\n");
1470 }
1471
1472 if (newsp == 0)
1473 break;
1474
1475 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477}
1478
1479static void backtrace(struct pt_regs *excp)
1480{
1481 unsigned long sp;
1482
1483 if (scanhex(&sp))
1484 xmon_show_stack(sp, 0, 0);
1485 else
1486 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1487 scannl();
1488}
1489
1490static void print_bug_trap(struct pt_regs *regs)
1491{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001492#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001493 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 unsigned long addr;
1495
1496 if (regs->msr & MSR_PR)
1497 return; /* not in kernel */
1498 addr = regs->nip; /* address of trap instruction */
1499 if (addr < PAGE_OFFSET)
1500 return;
1501 bug = find_bug(regs->nip);
1502 if (bug == NULL)
1503 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001504 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 return;
1506
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001507#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001508 printf("kernel BUG at %s:%u!\n",
1509 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001510#else
1511 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1512#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001513#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514}
1515
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001516static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517{
1518 unsigned long trap;
1519
1520#ifdef CONFIG_SMP
1521 printf("cpu 0x%x: ", smp_processor_id());
1522#endif /* CONFIG_SMP */
1523
1524 trap = TRAP(fp);
1525 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1526 printf(" pc: ");
1527 xmon_print_symbol(fp->nip, ": ", "\n");
1528
1529 printf(" lr: ", fp->link);
1530 xmon_print_symbol(fp->link, ": ", "\n");
1531
1532 printf(" sp: %lx\n", fp->gpr[1]);
1533 printf(" msr: %lx\n", fp->msr);
1534
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001535 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 printf(" dar: %lx\n", fp->dar);
1537 if (trap != 0x380)
1538 printf(" dsisr: %lx\n", fp->dsisr);
1539 }
1540
1541 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001542#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001543 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1544 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001545#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 if (current) {
1547 printf(" pid = %ld, comm = %s\n",
1548 current->pid, current->comm);
1549 }
1550
1551 if (trap == 0x700)
1552 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001553
1554 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555}
1556
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001557static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001559 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 unsigned long base;
1561 struct pt_regs regs;
1562
1563 if (scanhex(&base)) {
1564 if (setjmp(bus_error_jmp) == 0) {
1565 catch_memory_errors = 1;
1566 sync();
1567 regs = *(struct pt_regs *)base;
1568 sync();
1569 __delay(200);
1570 } else {
1571 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001572 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 base);
1574 return;
1575 }
1576 catch_memory_errors = 0;
1577 fp = &regs;
1578 }
1579
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001580#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 if (FULL_REGS(fp)) {
1582 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001583 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1585 } else {
1586 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001587 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1589 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001590#else
1591 for (n = 0; n < 32; ++n) {
1592 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1593 (n & 3) == 3? "\n": " ");
1594 if (n == 12 && !FULL_REGS(fp)) {
1595 printf("\n");
1596 break;
1597 }
1598 }
1599#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 printf("pc = ");
1601 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001602 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1603 printf("cfar= ");
1604 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 printf("lr = ");
1607 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001608 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1609 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001611 trap = TRAP(fp);
1612 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1613 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614}
1615
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001616static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617{
1618 int cmd;
1619 unsigned long nflush;
1620
1621 cmd = inchar();
1622 if (cmd != 'i')
1623 termch = cmd;
1624 scanhex((void *)&adrs);
1625 if (termch != '\n')
1626 termch = 0;
1627 nflush = 1;
1628 scanhex(&nflush);
1629 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1630 if (setjmp(bus_error_jmp) == 0) {
1631 catch_memory_errors = 1;
1632 sync();
1633
1634 if (cmd != 'i') {
1635 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1636 cflush((void *) adrs);
1637 } else {
1638 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1639 cinval((void *) adrs);
1640 }
1641 sync();
1642 /* wait a little while to see if we get a machine check */
1643 __delay(200);
1644 }
1645 catch_memory_errors = 0;
1646}
1647
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001648extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1649extern void xmon_mtspr(int spr, unsigned long value);
1650
1651static int
1652read_spr(int n, unsigned long *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 unsigned long ret = -1UL;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001655 int ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
1657 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001658 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 sync();
1660
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001661 ret = xmon_mfspr(n, *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
1663 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001664 *vp = ret;
1665 ok = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001667 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001669 return ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670}
1671
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001672static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673write_spr(int n, unsigned long val)
1674{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001676 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 sync();
1678
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001679 xmon_mtspr(n, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680
1681 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001682 } else {
1683 printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001685 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686}
1687
1688static unsigned long regno;
1689extern char exc_prolog;
1690extern char dec_exc;
1691
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001692static void dump_one_spr(int spr, bool show_unimplemented)
1693{
1694 unsigned long val;
1695
1696 val = 0xdeadbeef;
1697 if (!read_spr(spr, &val)) {
1698 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1699 return;
1700 }
1701
1702 if (val == 0xdeadbeef) {
1703 /* Looks like read was a nop, confirm */
1704 val = 0x0badcafe;
1705 if (!read_spr(spr, &val)) {
1706 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1707 return;
1708 }
1709
1710 if (val == 0x0badcafe) {
1711 if (show_unimplemented)
1712 printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
1713 return;
1714 }
1715 }
1716
1717 printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
1718}
1719
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001720static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721{
1722 int cmd;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001723 int spr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
1725 cmd = skipbl();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001726
1727 switch (cmd) {
1728 case '\n': {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001729 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 asm("mr %0,1" : "=r" (sp) :);
1731 asm("mr %0,2" : "=r" (toc) :);
1732
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001733 printf("msr = "REG" sprg0= "REG"\n",
1734 mfmsr(), mfspr(SPRN_SPRG0));
1735 printf("pvr = "REG" sprg1= "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001736 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001737 printf("dec = "REG" sprg2= "REG"\n",
1738 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1739 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1740 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 return;
1742 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001743 case 'w': {
1744 unsigned long val;
1745 scanhex(&regno);
1746 val = 0;
1747 read_spr(regno, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 scanhex(&val);
1749 write_spr(regno, val);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001750 dump_one_spr(regno, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001753 case 'r':
1754 scanhex(&regno);
1755 dump_one_spr(regno, true);
1756 break;
1757 case 'a':
1758 /* dump ALL SPRs */
1759 for (spr = 1; spr < 1024; ++spr)
1760 dump_one_spr(spr, false);
1761 break;
1762 }
1763
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 scannl();
1765}
1766
1767/*
1768 * Stuff for reading and writing memory safely
1769 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001770static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771mread(unsigned long adrs, void *buf, int size)
1772{
1773 volatile int n;
1774 char *p, *q;
1775
1776 n = 0;
1777 if (setjmp(bus_error_jmp) == 0) {
1778 catch_memory_errors = 1;
1779 sync();
1780 p = (char *)adrs;
1781 q = (char *)buf;
1782 switch (size) {
1783 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001784 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 break;
1786 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001787 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 break;
1789 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001790 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 break;
1792 default:
1793 for( ; n < size; ++n) {
1794 *q++ = *p++;
1795 sync();
1796 }
1797 }
1798 sync();
1799 /* wait a little while to see if we get a machine check */
1800 __delay(200);
1801 n = size;
1802 }
1803 catch_memory_errors = 0;
1804 return n;
1805}
1806
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001807static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808mwrite(unsigned long adrs, void *buf, int size)
1809{
1810 volatile int n;
1811 char *p, *q;
1812
1813 n = 0;
1814 if (setjmp(bus_error_jmp) == 0) {
1815 catch_memory_errors = 1;
1816 sync();
1817 p = (char *) adrs;
1818 q = (char *) buf;
1819 switch (size) {
1820 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001821 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 break;
1823 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001824 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 break;
1826 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001827 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 break;
1829 default:
1830 for ( ; n < size; ++n) {
1831 *p++ = *q++;
1832 sync();
1833 }
1834 }
1835 sync();
1836 /* wait a little while to see if we get a machine check */
1837 __delay(200);
1838 n = size;
1839 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10001840 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 }
1842 catch_memory_errors = 0;
1843 return n;
1844}
1845
1846static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001847static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848static char *fault_chars[] = { "--", "**", "##" };
1849
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001850static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001852 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 switch (TRAP(regs)) {
1854 case 0x200:
1855 fault_type = 0;
1856 break;
1857 case 0x300:
1858 case 0x380:
1859 fault_type = 1;
1860 break;
1861 default:
1862 fault_type = 2;
1863 }
1864
1865 longjmp(bus_error_jmp, 1);
1866
1867 return 0;
1868}
1869
1870#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1871
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001872static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873byterev(unsigned char *val, int size)
1874{
1875 int t;
1876
1877 switch (size) {
1878 case 2:
1879 SWAP(val[0], val[1], t);
1880 break;
1881 case 4:
1882 SWAP(val[0], val[3], t);
1883 SWAP(val[1], val[2], t);
1884 break;
1885 case 8: /* is there really any use for this? */
1886 SWAP(val[0], val[7], t);
1887 SWAP(val[1], val[6], t);
1888 SWAP(val[2], val[5], t);
1889 SWAP(val[3], val[4], t);
1890 break;
1891 }
1892}
1893
1894static int brev;
1895static int mnoread;
1896
Michael Ellermane3bc8042012-08-23 22:09:13 +00001897static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 "Memory examine command usage:\n"
1899 "m [addr] [flags] examine/change memory\n"
1900 " addr is optional. will start where left off.\n"
1901 " flags may include chars from this set:\n"
1902 " b modify by bytes (default)\n"
1903 " w modify by words (2 byte)\n"
1904 " l modify by longs (4 byte)\n"
1905 " d modify by doubleword (8 byte)\n"
1906 " r toggle reverse byte order mode\n"
1907 " n do not read memory (for i/o spaces)\n"
1908 " . ok to read (default)\n"
1909 "NOTE: flags are saved as defaults\n"
1910 "";
1911
Michael Ellermane3bc8042012-08-23 22:09:13 +00001912static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 "Memory examine subcommands:\n"
1914 " hexval write this val to current location\n"
1915 " 'string' write chars from string to this location\n"
1916 " ' increment address\n"
1917 " ^ decrement address\n"
1918 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1919 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1920 " ` clear no-read flag\n"
1921 " ; stay at this addr\n"
1922 " v change to byte mode\n"
1923 " w change to word (2 byte) mode\n"
1924 " l change to long (4 byte) mode\n"
1925 " u change to doubleword (8 byte) mode\n"
1926 " m addr change current addr\n"
1927 " n toggle no-read flag\n"
1928 " r toggle byte reverse flag\n"
1929 " < count back up count bytes\n"
1930 " > count skip forward count bytes\n"
1931 " x exit this mode\n"
1932 "";
1933
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001934static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935memex(void)
1936{
1937 int cmd, inc, i, nslash;
1938 unsigned long n;
1939 unsigned char val[16];
1940
1941 scanhex((void *)&adrs);
1942 cmd = skipbl();
1943 if (cmd == '?') {
1944 printf(memex_help_string);
1945 return;
1946 } else {
1947 termch = cmd;
1948 }
1949 last_cmd = "m\n";
1950 while ((cmd = skipbl()) != '\n') {
1951 switch( cmd ){
1952 case 'b': size = 1; break;
1953 case 'w': size = 2; break;
1954 case 'l': size = 4; break;
1955 case 'd': size = 8; break;
1956 case 'r': brev = !brev; break;
1957 case 'n': mnoread = 1; break;
1958 case '.': mnoread = 0; break;
1959 }
1960 }
1961 if( size <= 0 )
1962 size = 1;
1963 else if( size > 8 )
1964 size = 8;
1965 for(;;){
1966 if (!mnoread)
1967 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001968 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 if (!mnoread) {
1970 if (brev)
1971 byterev(val, size);
1972 putchar(' ');
1973 for (i = 0; i < n; ++i)
1974 printf("%.2x", val[i]);
1975 for (; i < size; ++i)
1976 printf("%s", fault_chars[fault_type]);
1977 }
1978 putchar(' ');
1979 inc = size;
1980 nslash = 0;
1981 for(;;){
1982 if( scanhex(&n) ){
1983 for (i = 0; i < size; ++i)
1984 val[i] = n >> (i * 8);
1985 if (!brev)
1986 byterev(val, size);
1987 mwrite(adrs, val, size);
1988 inc = size;
1989 }
1990 cmd = skipbl();
1991 if (cmd == '\n')
1992 break;
1993 inc = 0;
1994 switch (cmd) {
1995 case '\'':
1996 for(;;){
1997 n = inchar();
1998 if( n == '\\' )
1999 n = bsesc();
2000 else if( n == '\'' )
2001 break;
2002 for (i = 0; i < size; ++i)
2003 val[i] = n >> (i * 8);
2004 if (!brev)
2005 byterev(val, size);
2006 mwrite(adrs, val, size);
2007 adrs += size;
2008 }
2009 adrs -= size;
2010 inc = size;
2011 break;
2012 case ',':
2013 adrs += size;
2014 break;
2015 case '.':
2016 mnoread = 0;
2017 break;
2018 case ';':
2019 break;
2020 case 'x':
2021 case EOF:
2022 scannl();
2023 return;
2024 case 'b':
2025 case 'v':
2026 size = 1;
2027 break;
2028 case 'w':
2029 size = 2;
2030 break;
2031 case 'l':
2032 size = 4;
2033 break;
2034 case 'u':
2035 size = 8;
2036 break;
2037 case '^':
2038 adrs -= size;
2039 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 case '/':
2041 if (nslash > 0)
2042 adrs -= 1 << nslash;
2043 else
2044 nslash = 0;
2045 nslash += 4;
2046 adrs += 1 << nslash;
2047 break;
2048 case '\\':
2049 if (nslash < 0)
2050 adrs += 1 << -nslash;
2051 else
2052 nslash = 0;
2053 nslash -= 4;
2054 adrs -= 1 << -nslash;
2055 break;
2056 case 'm':
2057 scanhex((void *)&adrs);
2058 break;
2059 case 'n':
2060 mnoread = 1;
2061 break;
2062 case 'r':
2063 brev = !brev;
2064 break;
2065 case '<':
2066 n = size;
2067 scanhex(&n);
2068 adrs -= n;
2069 break;
2070 case '>':
2071 n = size;
2072 scanhex(&n);
2073 adrs += n;
2074 break;
2075 case '?':
2076 printf(memex_subcmd_help_string);
2077 break;
2078 }
2079 }
2080 adrs += inc;
2081 }
2082}
2083
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002084static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085bsesc(void)
2086{
2087 int c;
2088
2089 c = inchar();
2090 switch( c ){
2091 case 'n': c = '\n'; break;
2092 case 'r': c = '\r'; break;
2093 case 'b': c = '\b'; break;
2094 case 't': c = '\t'; break;
2095 }
2096 return c;
2097}
2098
Olaf Hering7e5b5932006-03-08 20:40:28 +01002099static void xmon_rawdump (unsigned long adrs, long ndump)
2100{
2101 long n, m, r, nr;
2102 unsigned char temp[16];
2103
2104 for (n = ndump; n > 0;) {
2105 r = n < 16? n: 16;
2106 nr = mread(adrs, temp, r);
2107 adrs += nr;
2108 for (m = 0; m < r; ++m) {
2109 if (m < nr)
2110 printf("%.2x", temp[m]);
2111 else
2112 printf("%s", fault_chars[fault_type]);
2113 }
2114 n -= r;
2115 if (nr < r)
2116 break;
2117 }
2118 printf("\n");
2119}
2120
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002121#ifdef CONFIG_PPC64
2122static void dump_one_paca(int cpu)
2123{
2124 struct paca_struct *p;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002125#ifdef CONFIG_PPC_STD_MMU_64
2126 int i = 0;
2127#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002128
2129 if (setjmp(bus_error_jmp) != 0) {
2130 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2131 return;
2132 }
2133
2134 catch_memory_errors = 1;
2135 sync();
2136
2137 p = &paca[cpu];
2138
2139 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2140
Michael Ellermanad987fc2015-10-14 16:58:36 +11002141 printf(" %-*s = %s\n", 20, "possible", cpu_possible(cpu) ? "yes" : "no");
2142 printf(" %-*s = %s\n", 20, "present", cpu_present(cpu) ? "yes" : "no");
2143 printf(" %-*s = %s\n", 20, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002144
2145#define DUMP(paca, name, format) \
Michael Ellermanad987fc2015-10-14 16:58:36 +11002146 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 20, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002147 offsetof(struct paca_struct, name));
2148
2149 DUMP(p, lock_token, "x");
2150 DUMP(p, paca_index, "x");
2151 DUMP(p, kernel_toc, "lx");
2152 DUMP(p, kernelbase, "lx");
2153 DUMP(p, kernel_msr, "lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002154 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302155#ifdef CONFIG_PPC_BOOK3S_64
2156 DUMP(p, mc_emergency_sp, "p");
2157 DUMP(p, in_mce, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002158 DUMP(p, hmi_event_available, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302159#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002160 DUMP(p, data_offset, "lx");
2161 DUMP(p, hw_cpu_id, "x");
2162 DUMP(p, cpu_start, "x");
2163 DUMP(p, kexec_state, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002164#ifdef CONFIG_PPC_STD_MMU_64
2165 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2166 u64 esid, vsid;
2167
2168 if (!p->slb_shadow_ptr)
2169 continue;
2170
2171 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2172 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
2173
2174 if (esid || vsid) {
2175 printf(" slb_shadow[%d]: = 0x%016lx 0x%016lx\n",
2176 i, esid, vsid);
2177 }
2178 }
2179 DUMP(p, vmalloc_sllp, "x");
2180 DUMP(p, slb_cache_ptr, "x");
2181 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2182 printf(" slb_cache[%d]: = 0x%016lx\n", i, p->slb_cache[i]);
2183#endif
2184 DUMP(p, dscr_default, "llx");
2185#ifdef CONFIG_PPC_BOOK3E
2186 DUMP(p, pgd, "p");
2187 DUMP(p, kernel_pgd, "p");
2188 DUMP(p, tcd_ptr, "p");
2189 DUMP(p, mc_kstack, "p");
2190 DUMP(p, crit_kstack, "p");
2191 DUMP(p, dbg_kstack, "p");
2192#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002193 DUMP(p, __current, "p");
2194 DUMP(p, kstack, "lx");
2195 DUMP(p, stab_rr, "lx");
2196 DUMP(p, saved_r1, "lx");
2197 DUMP(p, trap_save, "x");
2198 DUMP(p, soft_enabled, "x");
2199 DUMP(p, irq_happened, "x");
2200 DUMP(p, io_sync, "x");
2201 DUMP(p, irq_work_pending, "x");
2202 DUMP(p, nap_state_lost, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002203 DUMP(p, sprg_vdso, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002204
Michael Ellermanad987fc2015-10-14 16:58:36 +11002205#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
2206 DUMP(p, tm_scratch, "llx");
2207#endif
2208
2209#ifdef CONFIG_PPC_POWERNV
2210 DUMP(p, core_idle_state_ptr, "p");
2211 DUMP(p, thread_idle_state, "x");
2212 DUMP(p, thread_mask, "x");
2213 DUMP(p, subcore_sibling_mask, "x");
2214#endif
2215
2216 DUMP(p, user_time, "llx");
2217 DUMP(p, system_time, "llx");
2218 DUMP(p, user_time_scaled, "llx");
2219 DUMP(p, starttime, "llx");
2220 DUMP(p, starttime_user, "llx");
2221 DUMP(p, startspurr, "llx");
2222 DUMP(p, utime_sspurr, "llx");
2223 DUMP(p, stolen_time, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002224#undef DUMP
2225
2226 catch_memory_errors = 0;
2227 sync();
2228}
2229
2230static void dump_all_pacas(void)
2231{
2232 int cpu;
2233
2234 if (num_possible_cpus() == 0) {
2235 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2236 return;
2237 }
2238
2239 for_each_possible_cpu(cpu)
2240 dump_one_paca(cpu);
2241}
2242
2243static void dump_pacas(void)
2244{
2245 unsigned long num;
2246 int c;
2247
2248 c = inchar();
2249 if (c == 'a') {
2250 dump_all_pacas();
2251 return;
2252 }
2253
2254 termch = c; /* Put c back, it wasn't 'a' */
2255
2256 if (scanhex(&num))
2257 dump_one_paca(num);
2258 else
2259 dump_one_paca(xmon_owner);
2260}
2261#endif
2262
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002263static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264dump(void)
2265{
2266 int c;
2267
2268 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002269
2270#ifdef CONFIG_PPC64
2271 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002272 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002273 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002274 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002275 return;
2276 }
2277#endif
2278
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2280 termch = c;
2281 scanhex((void *)&adrs);
2282 if (termch != '\n')
2283 termch = 0;
2284 if (c == 'i') {
2285 scanhex(&nidump);
2286 if (nidump == 0)
2287 nidump = 16;
2288 else if (nidump > MAX_DUMP)
2289 nidump = MAX_DUMP;
2290 adrs += ppc_inst_dump(adrs, nidump, 1);
2291 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002292 } else if (c == 'l') {
2293 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002294 } else if (c == 'o') {
2295 dump_opal_msglog();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002296 } else if (c == 'r') {
2297 scanhex(&ndump);
2298 if (ndump == 0)
2299 ndump = 64;
2300 xmon_rawdump(adrs, ndump);
2301 adrs += ndump;
2302 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 } else {
2304 scanhex(&ndump);
2305 if (ndump == 0)
2306 ndump = 64;
2307 else if (ndump > MAX_DUMP)
2308 ndump = MAX_DUMP;
2309 prdump(adrs, ndump);
2310 adrs += ndump;
2311 last_cmd = "d\n";
2312 }
2313}
2314
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002315static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316prdump(unsigned long adrs, long ndump)
2317{
2318 long n, m, c, r, nr;
2319 unsigned char temp[16];
2320
2321 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002322 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 putchar(' ');
2324 r = n < 16? n: 16;
2325 nr = mread(adrs, temp, r);
2326 adrs += nr;
2327 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002328 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002329 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 if (m < nr)
2331 printf("%.2x", temp[m]);
2332 else
2333 printf("%s", fault_chars[fault_type]);
2334 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002335 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002336 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002337 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 printf(" |");
2341 for (m = 0; m < r; ++m) {
2342 if (m < nr) {
2343 c = temp[m];
2344 putchar(' ' <= c && c <= '~'? c: '.');
2345 } else
2346 putchar(' ');
2347 }
2348 n -= r;
2349 for (; m < 16; ++m)
2350 putchar(' ');
2351 printf("|\n");
2352 if (nr < r)
2353 break;
2354 }
2355}
2356
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002357typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2358
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002359static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002360generic_inst_dump(unsigned long adr, long count, int praddr,
2361 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362{
2363 int nr, dotted;
2364 unsigned long first_adr;
2365 unsigned long inst, last_inst = 0;
2366 unsigned char val[4];
2367
2368 dotted = 0;
2369 for (first_adr = adr; count > 0; --count, adr += 4) {
2370 nr = mread(adr, val, 4);
2371 if (nr == 0) {
2372 if (praddr) {
2373 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002374 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 }
2376 break;
2377 }
2378 inst = GETWORD(val);
2379 if (adr > first_adr && inst == last_inst) {
2380 if (!dotted) {
2381 printf(" ...\n");
2382 dotted = 1;
2383 }
2384 continue;
2385 }
2386 dotted = 0;
2387 last_inst = inst;
2388 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002389 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002391 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 printf("\n");
2393 }
2394 return adr - first_adr;
2395}
2396
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002397static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002398ppc_inst_dump(unsigned long adr, long count, int praddr)
2399{
2400 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2401}
2402
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403void
2404print_address(unsigned long addr)
2405{
2406 xmon_print_symbol(addr, "\t# ", "");
2407}
2408
Vinay Sridharf312deb2009-05-14 23:13:07 +00002409void
2410dump_log_buf(void)
2411{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002412 struct kmsg_dumper dumper = { .active = 1 };
2413 unsigned char buf[128];
2414 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002415
Michael Ellermane3bc8042012-08-23 22:09:13 +00002416 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002417 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002418 return;
2419 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002420
Michael Ellermane3bc8042012-08-23 22:09:13 +00002421 catch_memory_errors = 1;
2422 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002423
Michael Ellermanca5dd392012-08-23 22:09:12 +00002424 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002425 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002426 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2427 buf[len] = '\0';
2428 printf("%s", buf);
2429 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002430 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002431
Michael Ellermane3bc8042012-08-23 22:09:13 +00002432 sync();
2433 /* wait a little while to see if we get a machine check */
2434 __delay(200);
2435 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002436}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002438#ifdef CONFIG_PPC_POWERNV
2439static void dump_opal_msglog(void)
2440{
2441 unsigned char buf[128];
2442 ssize_t res;
2443 loff_t pos = 0;
2444
2445 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2446 printf("Machine is not running OPAL firmware.\n");
2447 return;
2448 }
2449
2450 if (setjmp(bus_error_jmp) != 0) {
2451 printf("Error dumping OPAL msglog!\n");
2452 return;
2453 }
2454
2455 catch_memory_errors = 1;
2456 sync();
2457
2458 xmon_start_pagination();
2459 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2460 if (res < 0) {
2461 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2462 break;
2463 }
2464 buf[res] = '\0';
2465 printf("%s", buf);
2466 pos += res;
2467 }
2468 xmon_end_pagination();
2469
2470 sync();
2471 /* wait a little while to see if we get a machine check */
2472 __delay(200);
2473 catch_memory_errors = 0;
2474}
2475#endif
2476
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477/*
2478 * Memory operations - move, set, print differences
2479 */
2480static unsigned long mdest; /* destination address */
2481static unsigned long msrc; /* source address */
2482static unsigned long mval; /* byte value to set memory to */
2483static unsigned long mcount; /* # bytes to affect */
2484static unsigned long mdiffs; /* max # differences to print */
2485
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002486static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487memops(int cmd)
2488{
2489 scanhex((void *)&mdest);
2490 if( termch != '\n' )
2491 termch = 0;
2492 scanhex((void *)(cmd == 's'? &mval: &msrc));
2493 if( termch != '\n' )
2494 termch = 0;
2495 scanhex((void *)&mcount);
2496 switch( cmd ){
2497 case 'm':
2498 memmove((void *)mdest, (void *)msrc, mcount);
2499 break;
2500 case 's':
2501 memset((void *)mdest, mval, mcount);
2502 break;
2503 case 'd':
2504 if( termch != '\n' )
2505 termch = 0;
2506 scanhex((void *)&mdiffs);
2507 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2508 break;
2509 }
2510}
2511
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002512static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2514{
2515 unsigned n, prt;
2516
2517 prt = 0;
2518 for( n = nb; n > 0; --n )
2519 if( *p1++ != *p2++ )
2520 if( ++prt <= maxpr )
2521 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2522 p1[-1], p2 - 1, p2[-1]);
2523 if( prt > maxpr )
2524 printf("Total of %d differences\n", prt);
2525}
2526
2527static unsigned mend;
2528static unsigned mask;
2529
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002530static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531memlocate(void)
2532{
2533 unsigned a, n;
2534 unsigned char val[4];
2535
2536 last_cmd = "ml";
2537 scanhex((void *)&mdest);
2538 if (termch != '\n') {
2539 termch = 0;
2540 scanhex((void *)&mend);
2541 if (termch != '\n') {
2542 termch = 0;
2543 scanhex((void *)&mval);
2544 mask = ~0;
2545 if (termch != '\n') termch = 0;
2546 scanhex((void *)&mask);
2547 }
2548 }
2549 n = 0;
2550 for (a = mdest; a < mend; a += 4) {
2551 if (mread(a, val, 4) == 4
2552 && ((GETWORD(val) ^ mval) & mask) == 0) {
2553 printf("%.16x: %.16x\n", a, GETWORD(val));
2554 if (++n >= 10)
2555 break;
2556 }
2557 }
2558}
2559
2560static unsigned long mskip = 0x1000;
2561static unsigned long mlim = 0xffffffff;
2562
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002563static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564memzcan(void)
2565{
2566 unsigned char v;
2567 unsigned a;
2568 int ok, ook;
2569
2570 scanhex(&mdest);
2571 if (termch != '\n') termch = 0;
2572 scanhex(&mskip);
2573 if (termch != '\n') termch = 0;
2574 scanhex(&mlim);
2575 ook = 0;
2576 for (a = mdest; a < mlim; a += mskip) {
2577 ok = mread(a, &v, 1);
2578 if (ok && !ook) {
2579 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 } else if (!ok && ook)
2581 printf("%.8x\n", a - mskip);
2582 ook = ok;
2583 if (a + mskip < a)
2584 break;
2585 }
2586 if (ook)
2587 printf("%.8x\n", a - mskip);
2588}
2589
Douglas Miller6dfb5402015-11-23 09:01:15 -06002590static void show_task(struct task_struct *tsk)
2591{
2592 char state;
2593
2594 /*
2595 * Cloned from kdb_task_state_char(), which is not entirely
2596 * appropriate for calling from xmon. This could be moved
2597 * to a common, generic, routine used by both.
2598 */
2599 state = (tsk->state == 0) ? 'R' :
2600 (tsk->state < 0) ? 'U' :
2601 (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
2602 (tsk->state & TASK_STOPPED) ? 'T' :
2603 (tsk->state & TASK_TRACED) ? 'C' :
2604 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
2605 (tsk->exit_state & EXIT_DEAD) ? 'E' :
2606 (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
2607
2608 printf("%p %016lx %6d %6d %c %2d %s\n", tsk,
2609 tsk->thread.ksp,
2610 tsk->pid, tsk->parent->pid,
2611 state, task_thread_info(tsk)->cpu,
2612 tsk->comm);
2613}
2614
2615static void show_tasks(void)
2616{
2617 unsigned long tskv;
2618 struct task_struct *tsk = NULL;
2619
2620 printf(" task_struct ->thread.ksp PID PPID S P CMD\n");
2621
2622 if (scanhex(&tskv))
2623 tsk = (struct task_struct *)tskv;
2624
2625 if (setjmp(bus_error_jmp) != 0) {
2626 catch_memory_errors = 0;
2627 printf("*** Error dumping task %p\n", tsk);
2628 return;
2629 }
2630
2631 catch_memory_errors = 1;
2632 sync();
2633
2634 if (tsk)
2635 show_task(tsk);
2636 else
2637 for_each_process(tsk)
2638 show_task(tsk);
2639
2640 sync();
2641 __delay(200);
2642 catch_memory_errors = 0;
2643}
2644
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002645static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002646{
2647 unsigned long args[8];
2648 unsigned long ret;
2649 int i;
2650 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2651 unsigned long, unsigned long, unsigned long,
2652 unsigned long, unsigned long, unsigned long);
2653 callfunc_t func;
2654
2655 if (!scanhex(&adrs))
2656 return;
2657 if (termch != '\n')
2658 termch = 0;
2659 for (i = 0; i < 8; ++i)
2660 args[i] = 0;
2661 for (i = 0; i < 8; ++i) {
2662 if (!scanhex(&args[i]) || termch == '\n')
2663 break;
2664 termch = 0;
2665 }
2666 func = (callfunc_t) adrs;
2667 ret = 0;
2668 if (setjmp(bus_error_jmp) == 0) {
2669 catch_memory_errors = 1;
2670 sync();
2671 ret = func(args[0], args[1], args[2], args[3],
2672 args[4], args[5], args[6], args[7]);
2673 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10002674 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002675 } else {
2676 printf("*** %x exception occurred\n", fault_except);
2677 }
2678 catch_memory_errors = 0;
2679}
2680
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681/* Input scanning routines */
2682int
2683skipbl(void)
2684{
2685 int c;
2686
2687 if( termch != 0 ){
2688 c = termch;
2689 termch = 0;
2690 } else
2691 c = inchar();
2692 while( c == ' ' || c == '\t' )
2693 c = inchar();
2694 return c;
2695}
2696
2697#define N_PTREGS 44
2698static char *regnames[N_PTREGS] = {
2699 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2700 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2701 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2702 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002703 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2704#ifdef CONFIG_PPC64
2705 "softe",
2706#else
2707 "mq",
2708#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 "trap", "dar", "dsisr", "res"
2710};
2711
2712int
2713scanhex(unsigned long *vp)
2714{
2715 int c, d;
2716 unsigned long v;
2717
2718 c = skipbl();
2719 if (c == '%') {
2720 /* parse register name */
2721 char regname[8];
2722 int i;
2723
2724 for (i = 0; i < sizeof(regname) - 1; ++i) {
2725 c = inchar();
2726 if (!isalnum(c)) {
2727 termch = c;
2728 break;
2729 }
2730 regname[i] = c;
2731 }
2732 regname[i] = 0;
2733 for (i = 0; i < N_PTREGS; ++i) {
2734 if (strcmp(regnames[i], regname) == 0) {
2735 if (xmon_regs == NULL) {
2736 printf("regs not available\n");
2737 return 0;
2738 }
2739 *vp = ((unsigned long *)xmon_regs)[i];
2740 return 1;
2741 }
2742 }
2743 printf("invalid register name '%%%s'\n", regname);
2744 return 0;
2745 }
2746
2747 /* skip leading "0x" if any */
2748
2749 if (c == '0') {
2750 c = inchar();
2751 if (c == 'x') {
2752 c = inchar();
2753 } else {
2754 d = hexdigit(c);
2755 if (d == EOF) {
2756 termch = c;
2757 *vp = 0;
2758 return 1;
2759 }
2760 }
2761 } else if (c == '$') {
2762 int i;
2763 for (i=0; i<63; i++) {
2764 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02002765 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 termch = c;
2767 break;
2768 }
2769 tmpstr[i] = c;
2770 }
2771 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002772 *vp = 0;
2773 if (setjmp(bus_error_jmp) == 0) {
2774 catch_memory_errors = 1;
2775 sync();
2776 *vp = kallsyms_lookup_name(tmpstr);
2777 sync();
2778 }
2779 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 if (!(*vp)) {
2781 printf("unknown symbol '%s'\n", tmpstr);
2782 return 0;
2783 }
2784 return 1;
2785 }
2786
2787 d = hexdigit(c);
2788 if (d == EOF) {
2789 termch = c;
2790 return 0;
2791 }
2792 v = 0;
2793 do {
2794 v = (v << 4) + d;
2795 c = inchar();
2796 d = hexdigit(c);
2797 } while (d != EOF);
2798 termch = c;
2799 *vp = v;
2800 return 1;
2801}
2802
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002803static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804scannl(void)
2805{
2806 int c;
2807
2808 c = termch;
2809 termch = 0;
2810 while( c != '\n' )
2811 c = inchar();
2812}
2813
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002814static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815{
2816 if( '0' <= c && c <= '9' )
2817 return c - '0';
2818 if( 'A' <= c && c <= 'F' )
2819 return c - ('A' - 10);
2820 if( 'a' <= c && c <= 'f' )
2821 return c - ('a' - 10);
2822 return EOF;
2823}
2824
2825void
2826getstring(char *s, int size)
2827{
2828 int c;
2829
2830 c = skipbl();
2831 do {
2832 if( size > 1 ){
2833 *s++ = c;
2834 --size;
2835 }
2836 c = inchar();
2837 } while( c != ' ' && c != '\t' && c != '\n' );
2838 termch = c;
2839 *s = 0;
2840}
2841
2842static char line[256];
2843static char *lineptr;
2844
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002845static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846flush_input(void)
2847{
2848 lineptr = NULL;
2849}
2850
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002851static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852inchar(void)
2853{
2854 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002855 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 lineptr = NULL;
2857 return EOF;
2858 }
2859 lineptr = line;
2860 }
2861 return *lineptr++;
2862}
2863
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002864static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865take_input(char *str)
2866{
2867 lineptr = str;
2868}
2869
2870
2871static void
2872symbol_lookup(void)
2873{
2874 int type = inchar();
2875 unsigned long addr;
2876 static char tmp[64];
2877
2878 switch (type) {
2879 case 'a':
2880 if (scanhex(&addr))
2881 xmon_print_symbol(addr, ": ", "\n");
2882 termch = 0;
2883 break;
2884 case 's':
2885 getstring(tmp, 64);
2886 if (setjmp(bus_error_jmp) == 0) {
2887 catch_memory_errors = 1;
2888 sync();
2889 addr = kallsyms_lookup_name(tmp);
2890 if (addr)
2891 printf("%s: %lx\n", tmp, addr);
2892 else
2893 printf("Symbol '%s' not found.\n", tmp);
2894 sync();
2895 }
2896 catch_memory_errors = 0;
2897 termch = 0;
2898 break;
2899 }
2900}
2901
2902
2903/* Print an address in numeric and symbolic form (if possible) */
2904static void xmon_print_symbol(unsigned long address, const char *mid,
2905 const char *after)
2906{
2907 char *modname;
2908 const char *name = NULL;
2909 unsigned long offset, size;
2910
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002911 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 if (setjmp(bus_error_jmp) == 0) {
2913 catch_memory_errors = 1;
2914 sync();
2915 name = kallsyms_lookup(address, &size, &offset, &modname,
2916 tmpstr);
2917 sync();
2918 /* wait a little while to see if we get a machine check */
2919 __delay(200);
2920 }
2921
2922 catch_memory_errors = 0;
2923
2924 if (name) {
2925 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2926 if (modname)
2927 printf(" [%s]", modname);
2928 }
2929 printf("%s", after);
2930}
2931
Aneesh Kumar K.Vcaca2852016-04-29 23:26:07 +10002932#ifdef CONFIG_PPC_STD_MMU_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10002933void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934{
2935 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05302936 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11002937 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938
Michael Ellerman736256e2014-05-26 21:02:14 +10002939 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940
Michael Neuling584f8b72007-12-06 17:24:48 +11002941 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002942 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2943 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Anshuman Khandual8218a302015-07-29 12:40:04 +05302944 if (esid || vsid) {
will schmidtb3b95952007-12-07 08:22:23 +11002945 printf("%02d %016lx %016lx", i, esid, vsid);
Anshuman Khandual8218a302015-07-29 12:40:04 +05302946 if (esid & SLB_ESID_V) {
will schmidtb3b95952007-12-07 08:22:23 +11002947 llp = vsid & SLB_VSID_LLP;
2948 if (vsid & SLB_VSID_B_1T) {
2949 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2950 GET_ESID_1T(esid),
2951 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2952 llp);
2953 } else {
2954 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2955 GET_ESID(esid),
2956 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2957 llp);
2958 }
2959 } else
2960 printf("\n");
2961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 }
2963}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002964#endif
2965
2966#ifdef CONFIG_PPC_STD_MMU_32
2967void dump_segments(void)
2968{
2969 int i;
2970
2971 printf("sr0-15 =");
2972 for (i = 0; i < 16; ++i)
2973 printf(" %x", mfsrin(i));
2974 printf("\n");
2975}
2976#endif
2977
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002978#ifdef CONFIG_44x
2979static void dump_tlb_44x(void)
2980{
2981 int i;
2982
2983 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2984 unsigned long w0,w1,w2;
2985 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2986 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2987 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2988 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2989 if (w0 & PPC44x_TLB_VALID) {
2990 printf("V %08x -> %01x%08x %c%c%c%c%c",
2991 w0 & PPC44x_TLB_EPN_MASK,
2992 w1 & PPC44x_TLB_ERPN_MASK,
2993 w1 & PPC44x_TLB_RPN_MASK,
2994 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2995 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2996 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2997 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2998 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2999 }
3000 printf("\n");
3001 }
3002}
3003#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003004
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10003005#ifdef CONFIG_PPC_BOOK3E
3006static void dump_tlb_book3e(void)
3007{
3008 u32 mmucfg, pidmask, lpidmask;
3009 u64 ramask;
3010 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3011 int mmu_version;
3012 static const char *pgsz_names[] = {
3013 " 1K",
3014 " 2K",
3015 " 4K",
3016 " 8K",
3017 " 16K",
3018 " 32K",
3019 " 64K",
3020 "128K",
3021 "256K",
3022 "512K",
3023 " 1M",
3024 " 2M",
3025 " 4M",
3026 " 8M",
3027 " 16M",
3028 " 32M",
3029 " 64M",
3030 "128M",
3031 "256M",
3032 "512M",
3033 " 1G",
3034 " 2G",
3035 " 4G",
3036 " 8G",
3037 " 16G",
3038 " 32G",
3039 " 64G",
3040 "128G",
3041 "256G",
3042 "512G",
3043 " 1T",
3044 " 2T",
3045 };
3046
3047 /* Gather some infos about the MMU */
3048 mmucfg = mfspr(SPRN_MMUCFG);
3049 mmu_version = (mmucfg & 3) + 1;
3050 ntlbs = ((mmucfg >> 2) & 3) + 1;
3051 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3052 lpidsz = (mmucfg >> 24) & 0xf;
3053 rasz = (mmucfg >> 16) & 0x7f;
3054 if ((mmu_version > 1) && (mmucfg & 0x10000))
3055 lrat = 1;
3056 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3057 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3058 pidmask = (1ul << pidsz) - 1;
3059 lpidmask = (1ul << lpidsz) - 1;
3060 ramask = (1ull << rasz) - 1;
3061
3062 for (tlb = 0; tlb < ntlbs; tlb++) {
3063 u32 tlbcfg;
3064 int nent, assoc, new_cc = 1;
3065 printf("TLB %d:\n------\n", tlb);
3066 switch(tlb) {
3067 case 0:
3068 tlbcfg = mfspr(SPRN_TLB0CFG);
3069 break;
3070 case 1:
3071 tlbcfg = mfspr(SPRN_TLB1CFG);
3072 break;
3073 case 2:
3074 tlbcfg = mfspr(SPRN_TLB2CFG);
3075 break;
3076 case 3:
3077 tlbcfg = mfspr(SPRN_TLB3CFG);
3078 break;
3079 default:
3080 printf("Unsupported TLB number !\n");
3081 continue;
3082 }
3083 nent = tlbcfg & 0xfff;
3084 assoc = (tlbcfg >> 24) & 0xff;
3085 for (i = 0; i < nent; i++) {
3086 u32 mas0 = MAS0_TLBSEL(tlb);
3087 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3088 u64 mas2 = 0;
3089 u64 mas7_mas3;
3090 int esel = i, cc = i;
3091
3092 if (assoc != 0) {
3093 cc = i / assoc;
3094 esel = i % assoc;
3095 mas2 = cc * 0x1000;
3096 }
3097
3098 mas0 |= MAS0_ESEL(esel);
3099 mtspr(SPRN_MAS0, mas0);
3100 mtspr(SPRN_MAS1, mas1);
3101 mtspr(SPRN_MAS2, mas2);
3102 asm volatile("tlbre 0,0,0" : : : "memory");
3103 mas1 = mfspr(SPRN_MAS1);
3104 mas2 = mfspr(SPRN_MAS2);
3105 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3106 if (assoc && (i % assoc) == 0)
3107 new_cc = 1;
3108 if (!(mas1 & MAS1_VALID))
3109 continue;
3110 if (assoc == 0)
3111 printf("%04x- ", i);
3112 else if (new_cc)
3113 printf("%04x-%c", cc, 'A' + esel);
3114 else
3115 printf(" |%c", 'A' + esel);
3116 new_cc = 0;
3117 printf(" %016llx %04x %s %c%c AS%c",
3118 mas2 & ~0x3ffull,
3119 (mas1 >> 16) & 0x3fff,
3120 pgsz_names[(mas1 >> 7) & 0x1f],
3121 mas1 & MAS1_IND ? 'I' : ' ',
3122 mas1 & MAS1_IPROT ? 'P' : ' ',
3123 mas1 & MAS1_TS ? '1' : '0');
3124 printf(" %c%c%c%c%c%c%c",
3125 mas2 & MAS2_X0 ? 'a' : ' ',
3126 mas2 & MAS2_X1 ? 'v' : ' ',
3127 mas2 & MAS2_W ? 'w' : ' ',
3128 mas2 & MAS2_I ? 'i' : ' ',
3129 mas2 & MAS2_M ? 'm' : ' ',
3130 mas2 & MAS2_G ? 'g' : ' ',
3131 mas2 & MAS2_E ? 'e' : ' ');
3132 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3133 if (mas1 & MAS1_IND)
3134 printf(" %s\n",
3135 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3136 else
3137 printf(" U%c%c%c S%c%c%c\n",
3138 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3139 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3140 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3141 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3142 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3143 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3144 }
3145 }
3146}
3147#endif /* CONFIG_PPC_BOOK3E */
3148
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003149static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003151 if (enable) {
3152 __debugger = xmon;
3153 __debugger_ipi = xmon_ipi;
3154 __debugger_bpt = xmon_bpt;
3155 __debugger_sstep = xmon_sstep;
3156 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003157 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003158 __debugger_fault_handler = xmon_fault_handler;
3159 } else {
3160 __debugger = NULL;
3161 __debugger_ipi = NULL;
3162 __debugger_bpt = NULL;
3163 __debugger_sstep = NULL;
3164 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003165 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003166 __debugger_fault_handler = NULL;
3167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003169
3170#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003171static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003172{
3173 /* ensure xmon is enabled */
3174 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003175 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003176}
3177
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003178static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003179 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003180 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003181 .action_msg = "Entering xmon",
3182};
3183
3184static int __init setup_xmon_sysrq(void)
3185{
3186 register_sysrq_key('x', &sysrq_xmon_op);
3187 return 0;
3188}
3189__initcall(setup_xmon_sysrq);
3190#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003191
Olaf Heringf5e6a282007-06-24 16:57:08 +10003192static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10003193
3194static int __init early_parse_xmon(char *p)
3195{
3196 if (!p || strncmp(p, "early", 5) == 0) {
3197 /* just "xmon" is equivalent to "xmon=early" */
3198 xmon_init(1);
3199 xmon_early = 1;
3200 } else if (strncmp(p, "on", 2) == 0)
3201 xmon_init(1);
3202 else if (strncmp(p, "off", 3) == 0)
3203 xmon_off = 1;
3204 else if (strncmp(p, "nobt", 4) == 0)
3205 xmon_no_auto_backtrace = 1;
3206 else
3207 return 1;
3208
3209 return 0;
3210}
3211early_param("xmon", early_parse_xmon);
3212
3213void __init xmon_setup(void)
3214{
3215#ifdef CONFIG_XMON_DEFAULT
3216 if (!xmon_off)
3217 xmon_init(1);
3218#endif
3219 if (xmon_early)
3220 debugger(NULL);
3221}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003222
Arnd Bergmanne0555952006-11-27 19:18:55 +01003223#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003224
3225struct spu_info {
3226 struct spu *spu;
3227 u64 saved_mfc_sr1_RW;
3228 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003229 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003230 u8 stopped_ok;
3231};
3232
3233#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3234
3235static struct spu_info spu_info[XMON_NUM_SPUS];
3236
3237void xmon_register_spus(struct list_head *list)
3238{
3239 struct spu *spu;
3240
3241 list_for_each_entry(spu, list, full_list) {
3242 if (spu->number >= XMON_NUM_SPUS) {
3243 WARN_ON(1);
3244 continue;
3245 }
3246
3247 spu_info[spu->number].spu = spu;
3248 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003249 spu_info[spu->number].dump_addr = (unsigned long)
3250 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003251 }
3252}
3253
3254static void stop_spus(void)
3255{
3256 struct spu *spu;
3257 int i;
3258 u64 tmp;
3259
3260 for (i = 0; i < XMON_NUM_SPUS; i++) {
3261 if (!spu_info[i].spu)
3262 continue;
3263
3264 if (setjmp(bus_error_jmp) == 0) {
3265 catch_memory_errors = 1;
3266 sync();
3267
3268 spu = spu_info[i].spu;
3269
3270 spu_info[i].saved_spu_runcntl_RW =
3271 in_be32(&spu->problem->spu_runcntl_RW);
3272
3273 tmp = spu_mfc_sr1_get(spu);
3274 spu_info[i].saved_mfc_sr1_RW = tmp;
3275
3276 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3277 spu_mfc_sr1_set(spu, tmp);
3278
3279 sync();
3280 __delay(200);
3281
3282 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003283
3284 printf("Stopped spu %.2d (was %s)\n", i,
3285 spu_info[i].saved_spu_runcntl_RW ?
3286 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003287 } else {
3288 catch_memory_errors = 0;
3289 printf("*** Error stopping spu %.2d\n", i);
3290 }
3291 catch_memory_errors = 0;
3292 }
3293}
3294
3295static void restart_spus(void)
3296{
3297 struct spu *spu;
3298 int i;
3299
3300 for (i = 0; i < XMON_NUM_SPUS; i++) {
3301 if (!spu_info[i].spu)
3302 continue;
3303
3304 if (!spu_info[i].stopped_ok) {
3305 printf("*** Error, spu %d was not successfully stopped"
3306 ", not restarting\n", i);
3307 continue;
3308 }
3309
3310 if (setjmp(bus_error_jmp) == 0) {
3311 catch_memory_errors = 1;
3312 sync();
3313
3314 spu = spu_info[i].spu;
3315 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3316 out_be32(&spu->problem->spu_runcntl_RW,
3317 spu_info[i].saved_spu_runcntl_RW);
3318
3319 sync();
3320 __delay(200);
3321
3322 printf("Restarted spu %.2d\n", i);
3323 } else {
3324 catch_memory_errors = 0;
3325 printf("*** Error restarting spu %.2d\n", i);
3326 }
3327 catch_memory_errors = 0;
3328 }
3329}
3330
Michael Ellermana8984972006-10-24 18:31:28 +02003331#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003332#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003333do { \
3334 if (setjmp(bus_error_jmp) == 0) { \
3335 catch_memory_errors = 1; \
3336 sync(); \
3337 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003338 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003339 sync(); \
3340 __delay(200); \
3341 } else { \
3342 catch_memory_errors = 0; \
3343 printf(" %-*s = *** Error reading field.\n", \
3344 DUMP_WIDTH, #field); \
3345 } \
3346 catch_memory_errors = 0; \
3347} while (0)
3348
Michael Ellerman437a0702006-11-23 00:46:39 +01003349#define DUMP_FIELD(obj, format, field) \
3350 DUMP_VALUE(format, field, obj->field)
3351
Michael Ellermana8984972006-10-24 18:31:28 +02003352static void dump_spu_fields(struct spu *spu)
3353{
3354 printf("Dumping spu fields at address %p:\n", spu);
3355
3356 DUMP_FIELD(spu, "0x%x", number);
3357 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003358 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3359 DUMP_FIELD(spu, "0x%p", local_store);
3360 DUMP_FIELD(spu, "0x%lx", ls_size);
3361 DUMP_FIELD(spu, "0x%x", node);
3362 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003363 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003364 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003365 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3366 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003367 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3368 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3369 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3370 DUMP_FIELD(spu, "0x%x", slb_replace);
3371 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003372 DUMP_FIELD(spu, "0x%p", mm);
3373 DUMP_FIELD(spu, "0x%p", ctx);
3374 DUMP_FIELD(spu, "0x%p", rq);
3375 DUMP_FIELD(spu, "0x%p", timestamp);
3376 DUMP_FIELD(spu, "0x%lx", problem_phys);
3377 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003378 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3379 in_be32(&spu->problem->spu_runcntl_RW));
3380 DUMP_VALUE("0x%x", problem->spu_status_R,
3381 in_be32(&spu->problem->spu_status_R));
3382 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3383 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003384 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003385 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003386}
3387
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003388int
3389spu_inst_dump(unsigned long adr, long count, int praddr)
3390{
3391 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3392}
3393
3394static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003395{
3396 unsigned long offset, addr, ls_addr;
3397
3398 if (setjmp(bus_error_jmp) == 0) {
3399 catch_memory_errors = 1;
3400 sync();
3401 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3402 sync();
3403 __delay(200);
3404 } else {
3405 catch_memory_errors = 0;
3406 printf("*** Error: accessing spu info for spu %d\n", num);
3407 return;
3408 }
3409 catch_memory_errors = 0;
3410
3411 if (scanhex(&offset))
3412 addr = ls_addr + offset;
3413 else
3414 addr = spu_info[num].dump_addr;
3415
3416 if (addr >= ls_addr + LS_SIZE) {
3417 printf("*** Error: address outside of local store\n");
3418 return;
3419 }
3420
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003421 switch (subcmd) {
3422 case 'i':
3423 addr += spu_inst_dump(addr, 16, 1);
3424 last_cmd = "sdi\n";
3425 break;
3426 default:
3427 prdump(addr, 64);
3428 addr += 64;
3429 last_cmd = "sd\n";
3430 break;
3431 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003432
3433 spu_info[num].dump_addr = addr;
3434}
3435
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003436static int do_spu_cmd(void)
3437{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003438 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003439 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003440
3441 cmd = inchar();
3442 switch (cmd) {
3443 case 's':
3444 stop_spus();
3445 break;
3446 case 'r':
3447 restart_spus();
3448 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003449 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003450 subcmd = inchar();
3451 if (isxdigit(subcmd) || subcmd == '\n')
3452 termch = subcmd;
3453 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003454 scanhex(&num);
3455 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003456 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003457 return 0;
3458 }
3459
3460 switch (cmd) {
3461 case 'f':
3462 dump_spu_fields(spu_info[num].spu);
3463 break;
3464 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003465 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003466 break;
3467 }
3468
Michael Ellermana8984972006-10-24 18:31:28 +02003469 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003470 default:
3471 return -1;
3472 }
3473
3474 return 0;
3475}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003476#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003477static int do_spu_cmd(void)
3478{
3479 return -1;
3480}
3481#endif