blob: 942796fa476750221133664d35d701a97b659499 [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;
89static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
91/* Breakpoint stuff */
92struct bpt {
93 unsigned long address;
94 unsigned int instr[2];
95 atomic_t ref_count;
96 int enabled;
97 unsigned long pad;
98};
99
100/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100101#define BP_CIABR 1
102#define BP_TRAP 2
103#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105#define NBPTS 256
106static struct bpt bpts[NBPTS];
107static struct bpt dabr;
108static struct bpt *iabr;
109static unsigned bpinstr = 0x7fe00008; /* trap */
110
111#define BP_NUM(bp) ((bp) - bpts + 1)
112
113/* Prototypes */
114static int cmds(struct pt_regs *);
115static int mread(unsigned long, void *, int);
116static int mwrite(unsigned long, void *, int);
117static int handle_fault(struct pt_regs *);
118static void byterev(unsigned char *, int);
119static void memex(void);
120static int bsesc(void);
121static void dump(void);
122static void prdump(unsigned long, long);
123static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000124static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100125
126#ifdef CONFIG_PPC_POWERNV
127static void dump_opal_msglog(void);
128#else
129static inline void dump_opal_msglog(void)
130{
131 printf("Machine is not running OPAL firmware.\n");
132}
133#endif
134
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135static void backtrace(struct pt_regs *);
136static void excprint(struct pt_regs *);
137static void prregs(struct pt_regs *);
138static void memops(int);
139static void memlocate(void);
140static void memzcan(void);
141static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
142int skipbl(void);
143int scanhex(unsigned long *valp);
144static void scannl(void);
145static int hexdigit(int);
146void getstring(char *, int);
147static void flush_input(void);
148static int inchar(void);
149static void take_input(char *);
150static unsigned long read_spr(int);
151static void write_spr(int, unsigned long);
152static void super_regs(void);
153static void remove_bpts(void);
154static void insert_bpts(void);
155static void remove_cpu_bpts(void);
156static void insert_cpu_bpts(void);
157static struct bpt *at_breakpoint(unsigned long pc);
158static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
159static int do_step(struct pt_regs *);
160static void bpt_cmds(void);
161static void cacheflush(void);
162static int cpu_cmd(void);
163static void csum(void);
164static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000165static void proccall(void);
Douglas Miller6dfb5402015-11-23 09:01:15 -0600166static void show_tasks(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167void dump_segments(void);
168static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200169static void xmon_show_stack(unsigned long sp, unsigned long lr,
170 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171static void xmon_print_symbol(unsigned long address, const char *mid,
172 const char *after);
173static const char *getvecname(unsigned long vec);
174
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200175static int do_spu_cmd(void);
176
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100177#ifdef CONFIG_44x
178static void dump_tlb_44x(void);
179#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000180#ifdef CONFIG_PPC_BOOK3E
181static void dump_tlb_book3e(void);
182#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100183
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000184static int xmon_no_auto_backtrace;
Olaf Hering26c8af52006-09-08 16:29:21 +0200185
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000186extern void xmon_enter(void);
187extern void xmon_leave(void);
188
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000189#ifdef CONFIG_PPC64
190#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000191#else
192#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000193#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100195#ifdef __LITTLE_ENDIAN__
196#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
197#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100199#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201static char *help_string = "\
202Commands:\n\
203 b show breakpoints\n\
204 bd set data breakpoint\n\
205 bi set instruction breakpoint\n\
206 bc clear breakpoint\n"
207#ifdef CONFIG_SMP
208 "\
209 c print cpus stopped in xmon\n\
210 c# try to switch to cpu number h (in hex)\n"
211#endif
212 "\
213 C checksum\n\
214 d dump bytes\n\
215 di dump instructions\n\
216 df dump float values\n\
217 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000218 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100219#ifdef CONFIG_PPC_POWERNV
220 "\
221 do dump the OPAL message log\n"
222#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000223#ifdef CONFIG_PPC64
224 "\
225 dp[#] dump paca for current cpu, or cpu #\n\
226 dpa dump paca for all possible cpus\n"
227#endif
228 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100229 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 e print exception information\n\
231 f flush cache\n\
232 la lookup symbol+offset of specified address\n\
233 ls lookup address of specified symbol\n\
234 m examine/change memory\n\
235 mm move a block of memory\n\
236 ms set a block of memory\n\
237 md compare two blocks of memory\n\
238 ml locate a block of memory\n\
239 mz zero a block of memory\n\
240 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000241 p call a procedure\n\
Douglas Miller6dfb5402015-11-23 09:01:15 -0600242 P list processes/tasks\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200244 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100245#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200246" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200247 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100248 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900249 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100250 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200251#endif
252" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100255 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000256#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000257" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000258#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000259" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000260#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100261" u dump TLB\n"
262#endif
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000263" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100264" # n limit output to n lines per page (for dp, dpa, dl)\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000265" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 zh halt\n"
267;
268
269static struct pt_regs *xmon_regs;
270
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000271static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272{
273 asm volatile("sync; isync");
274}
275
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000276static inline void store_inst(void *p)
277{
278 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
279}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000281static inline void cflush(void *p)
282{
283 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
284}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000286static inline void cinval(void *p)
287{
288 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
289}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530291/**
292 * write_ciabr() - write the CIABR SPR
293 * @ciabr: The value to write.
294 *
295 * This function writes a value to the CIARB register either directly
296 * through mtspr instruction if the kernel is in HV privilege mode or
297 * call a hypervisor function to achieve the same in case the kernel
298 * is in supervisor privilege mode.
299 */
300static void write_ciabr(unsigned long ciabr)
301{
302 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
303 return;
304
305 if (cpu_has_feature(CPU_FTR_HVMODE)) {
306 mtspr(SPRN_CIABR, ciabr);
307 return;
308 }
309 plapr_set_ciabr(ciabr);
310}
311
312/**
313 * set_ciabr() - set the CIABR
314 * @addr: The value to set.
315 *
316 * This function sets the correct privilege value into the the HW
317 * breakpoint address before writing it up in the CIABR register.
318 */
319static void set_ciabr(unsigned long addr)
320{
321 addr &= ~CIABR_PRIV;
322
323 if (cpu_has_feature(CPU_FTR_HVMODE))
324 addr |= CIABR_PRIV_HYPER;
325 else
326 addr |= CIABR_PRIV_SUPER;
327 write_ciabr(addr);
328}
329
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330/*
331 * Disable surveillance (the service processor watchdog function)
332 * while we are in xmon.
333 * XXX we should re-enable it when we leave. :)
334 */
335#define SURVEILLANCE_TOKEN 9000
336
337static inline void disable_surveillance(void)
338{
339#ifdef CONFIG_PPC_PSERIES
340 /* Since this can't be a module, args should end up below 4GB. */
341 static struct rtas_args args;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100342 int token;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344 /*
345 * At this point we have got all the cpus we can into
346 * xmon, so there is hopefully no other cpu calling RTAS
347 * at the moment, even though we don't take rtas.lock.
348 * If we did try to take rtas.lock there would be a
349 * real possibility of deadlock.
350 */
Michael Ellerman08eb1052015-11-24 22:26:09 +1100351 token = rtas_token("set-indicator");
352 if (token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100354
355 rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0);
356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357#endif /* CONFIG_PPC_PSERIES */
358}
359
360#ifdef CONFIG_SMP
361static int xmon_speaker;
362
363static void get_output_lock(void)
364{
365 int me = smp_processor_id() + 0x100;
366 int last_speaker = 0, prev;
367 long timeout;
368
369 if (xmon_speaker == me)
370 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100373 last_speaker = cmpxchg(&xmon_speaker, 0, me);
374 if (last_speaker == 0)
375 return;
376
Michael Ellerman15075892013-12-23 23:46:05 +1100377 /*
378 * Wait a full second for the lock, we might be on a slow
379 * console, but check every 100us.
380 */
381 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100383 if (--timeout > 0) {
384 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100386 }
387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 /* hostile takeover */
389 prev = cmpxchg(&xmon_speaker, last_speaker, me);
390 if (prev == last_speaker)
391 return;
392 break;
393 }
394 }
395}
396
397static void release_output_lock(void)
398{
399 xmon_speaker = 0;
400}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000401
402int cpus_are_in_xmon(void)
403{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000404 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000405}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406#endif
407
Josh Boyerdaf8f402009-09-23 03:51:04 +0000408static inline int unrecoverable_excp(struct pt_regs *regs)
409{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000410#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000411 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000412 return 0;
413#else
414 return ((regs->msr & MSR_RI) == 0);
415#endif
416}
417
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000418static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419{
420 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 struct bpt *bp;
422 long recurse_jmp[JMP_BUF_LEN];
423 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100424 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425#ifdef CONFIG_SMP
426 int cpu;
427 int secondary;
428 unsigned long timeout;
429#endif
430
Anton Blanchardf13659e2007-03-21 01:48:34 +1100431 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000432 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
434 bp = in_breakpoint_table(regs->nip, &offset);
435 if (bp != NULL) {
436 regs->nip = bp->address + offset;
437 atomic_dec(&bp->ref_count);
438 }
439
440 remove_cpu_bpts();
441
442#ifdef CONFIG_SMP
443 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000444 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 get_output_lock();
446 excprint(regs);
447 printf("cpu 0x%x: Exception %lx %s in xmon, "
448 "returning to main loop\n",
449 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000450 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 longjmp(xmon_fault_jmp[cpu], 1);
452 }
453
454 if (setjmp(recurse_jmp) != 0) {
455 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000456 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 printf("xmon: WARNING: bad recursive fault "
458 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000459 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 goto waiting;
461 }
462 secondary = !(xmon_taken && cpu == xmon_owner);
463 goto cmdloop;
464 }
465
466 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
468 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000469 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000471 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 fromipi = 0;
473
474 if (!fromipi) {
475 get_output_lock();
476 excprint(regs);
477 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000478 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 cpu, BP_NUM(bp));
480 xmon_print_symbol(regs->nip, " ", ")\n");
481 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000482 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 printf("WARNING: exception is not recoverable, "
484 "can't continue\n");
485 release_output_lock();
486 }
487
Michael Ellermand2b496e2013-12-23 23:46:06 +1100488 cpumask_set_cpu(cpu, &cpus_in_xmon);
489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 waiting:
491 secondary = 1;
492 while (secondary && !xmon_gate) {
493 if (in_xmon == 0) {
494 if (fromipi)
495 goto leave;
496 secondary = test_and_set_bit(0, &in_xmon);
497 }
498 barrier();
499 }
500
501 if (!secondary && !xmon_gate) {
502 /* we are the first cpu to come in */
503 /* interrupt other cpu(s) */
504 int ncpus = num_online_cpus();
505
506 xmon_owner = cpu;
507 mb();
508 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000509 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 /* wait for other cpus to come in */
511 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000512 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 break;
514 barrier();
515 }
516 }
517 remove_bpts();
518 disable_surveillance();
519 /* for breakpoint or single step, print the current instr. */
520 if (bp || TRAP(regs) == 0xd00)
521 ppc_inst_dump(regs->nip, 1, 0);
522 printf("enter ? for help\n");
523 mb();
524 xmon_gate = 1;
525 barrier();
526 }
527
528 cmdloop:
529 while (in_xmon) {
530 if (secondary) {
531 if (cpu == xmon_owner) {
532 if (!test_and_set_bit(0, &xmon_taken)) {
533 secondary = 0;
534 continue;
535 }
536 /* missed it */
537 while (cpu == xmon_owner)
538 barrier();
539 }
540 barrier();
541 } else {
542 cmd = cmds(regs);
543 if (cmd != 0) {
544 /* exiting xmon */
545 insert_bpts();
546 xmon_gate = 0;
547 wmb();
548 in_xmon = 0;
549 break;
550 }
551 /* have switched to some other cpu */
552 secondary = 1;
553 }
554 }
555 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000556 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558#else
559 /* UP is simple... */
560 if (in_xmon) {
561 printf("Exception %lx %s in xmon, returning to main loop\n",
562 regs->trap, getvecname(TRAP(regs)));
563 longjmp(xmon_fault_jmp[0], 1);
564 }
565 if (setjmp(recurse_jmp) == 0) {
566 xmon_fault_jmp[0] = recurse_jmp;
567 in_xmon = 1;
568
569 excprint(regs);
570 bp = at_breakpoint(regs->nip);
571 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000572 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 xmon_print_symbol(regs->nip, " ", ")\n");
574 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000575 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 printf("WARNING: exception is not recoverable, "
577 "can't continue\n");
578 remove_bpts();
579 disable_surveillance();
580 /* for breakpoint or single step, print the current instr. */
581 if (bp || TRAP(regs) == 0xd00)
582 ppc_inst_dump(regs->nip, 1, 0);
583 printf("enter ? for help\n");
584 }
585
586 cmd = cmds(regs);
587
588 insert_bpts();
589 in_xmon = 0;
590#endif
591
Josh Boyercdd39042009-10-05 04:46:05 +0000592#ifdef CONFIG_BOOKE
593 if (regs->msr & MSR_DE) {
594 bp = at_breakpoint(regs->nip);
595 if (bp != NULL) {
596 regs->nip = (unsigned long) &bp->instr[0];
597 atomic_inc(&bp->ref_count);
598 }
599 }
600#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000601 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 bp = at_breakpoint(regs->nip);
603 if (bp != NULL) {
604 int stepped = emulate_step(regs, bp->instr[0]);
605 if (stepped == 0) {
606 regs->nip = (unsigned long) &bp->instr[0];
607 atomic_inc(&bp->ref_count);
608 } else if (stepped < 0) {
609 printf("Couldn't single-step %s instruction\n",
610 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
611 }
612 }
613 }
Josh Boyercdd39042009-10-05 04:46:05 +0000614#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 insert_cpu_bpts();
616
Anton Blancharda71d64b2014-08-05 14:55:00 +1000617 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100618 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000620 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621}
622
623int xmon(struct pt_regs *excp)
624{
625 struct pt_regs regs;
626
627 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000628 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 excp = &regs;
630 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200631
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 return xmon_core(excp, 0);
633}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000634EXPORT_SYMBOL(xmon);
635
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000636irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000637{
638 unsigned long flags;
639 local_irq_save(flags);
640 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000641 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000642 local_irq_restore(flags);
643 return IRQ_HANDLED;
644}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000646static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647{
648 struct bpt *bp;
649 unsigned long offset;
650
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000651 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 return 0;
653
654 /* Are we at the trap at bp->instr[1] for some bp? */
655 bp = in_breakpoint_table(regs->nip, &offset);
656 if (bp != NULL && offset == 4) {
657 regs->nip = bp->address + 4;
658 atomic_dec(&bp->ref_count);
659 return 1;
660 }
661
662 /* Are we at a breakpoint? */
663 bp = at_breakpoint(regs->nip);
664 if (!bp)
665 return 0;
666
667 xmon_core(regs, 0);
668
669 return 1;
670}
671
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000672static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
674 if (user_mode(regs))
675 return 0;
676 xmon_core(regs, 0);
677 return 1;
678}
679
Michael Neuling9422de32012-12-20 14:06:44 +0000680static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000682 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000684 if (dabr.enabled == 0)
685 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 xmon_core(regs, 0);
687 return 1;
688}
689
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000690static int xmon_iabr_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;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000694 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 return 0;
696 xmon_core(regs, 0);
697 return 1;
698}
699
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000700static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701{
702#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000703 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 xmon_core(regs, 1);
705#endif
706 return 0;
707}
708
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000709static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{
711 struct bpt *bp;
712 unsigned long offset;
713
714 if (in_xmon && catch_memory_errors)
715 handle_fault(regs); /* doesn't return */
716
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000717 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 bp = in_breakpoint_table(regs->nip, &offset);
719 if (bp != NULL) {
720 regs->nip = bp->address + offset;
721 atomic_dec(&bp->ref_count);
722 }
723 }
724
725 return 0;
726}
727
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728static struct bpt *at_breakpoint(unsigned long pc)
729{
730 int i;
731 struct bpt *bp;
732
733 bp = bpts;
734 for (i = 0; i < NBPTS; ++i, ++bp)
735 if (bp->enabled && pc == bp->address)
736 return bp;
737 return NULL;
738}
739
740static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
741{
742 unsigned long off;
743
744 off = nip - (unsigned long) bpts;
745 if (off >= sizeof(bpts))
746 return NULL;
747 off %= sizeof(struct bpt);
748 if (off != offsetof(struct bpt, instr[0])
749 && off != offsetof(struct bpt, instr[1]))
750 return NULL;
751 *offp = off - offsetof(struct bpt, instr[0]);
752 return (struct bpt *) (nip - off);
753}
754
755static struct bpt *new_breakpoint(unsigned long a)
756{
757 struct bpt *bp;
758
759 a &= ~3UL;
760 bp = at_breakpoint(a);
761 if (bp)
762 return bp;
763
764 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
765 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
766 bp->address = a;
767 bp->instr[1] = bpinstr;
768 store_inst(&bp->instr[1]);
769 return bp;
770 }
771 }
772
773 printf("Sorry, no free breakpoints. Please clear one first.\n");
774 return NULL;
775}
776
777static void insert_bpts(void)
778{
779 int i;
780 struct bpt *bp;
781
782 bp = bpts;
783 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100784 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 continue;
786 if (mread(bp->address, &bp->instr[0], 4) != 4) {
787 printf("Couldn't read instruction at %lx, "
788 "disabling breakpoint there\n", bp->address);
789 bp->enabled = 0;
790 continue;
791 }
792 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
793 printf("Breakpoint at %lx is on an mtmsrd or rfid "
794 "instruction, disabling it\n", bp->address);
795 bp->enabled = 0;
796 continue;
797 }
798 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100799 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 continue;
801 if (mwrite(bp->address, &bpinstr, 4) != 4) {
802 printf("Couldn't write instruction at %lx, "
803 "disabling breakpoint there\n", bp->address);
804 bp->enabled &= ~BP_TRAP;
805 continue;
806 }
807 store_inst((void *)bp->address);
808 }
809}
810
811static void insert_cpu_bpts(void)
812{
Michael Neuling9422de32012-12-20 14:06:44 +0000813 struct arch_hw_breakpoint brk;
814
815 if (dabr.enabled) {
816 brk.address = dabr.address;
817 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
818 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400819 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000820 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530821
822 if (iabr)
823 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824}
825
826static void remove_bpts(void)
827{
828 int i;
829 struct bpt *bp;
830 unsigned instr;
831
832 bp = bpts;
833 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100834 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 continue;
836 if (mread(bp->address, &instr, 4) == 4
837 && instr == bpinstr
838 && mwrite(bp->address, &bp->instr, 4) != 4)
839 printf("Couldn't remove breakpoint at %lx\n",
840 bp->address);
841 else
842 store_inst((void *)bp->address);
843 }
844}
845
846static void remove_cpu_bpts(void)
847{
Michael Neuling9422de32012-12-20 14:06:44 +0000848 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530849 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850}
851
Sam bobroff958b7c82015-10-08 11:50:23 +1100852static void set_lpp_cmd(void)
853{
854 unsigned long lpp;
855
856 if (!scanhex(&lpp)) {
857 printf("Invalid number.\n");
858 lpp = 0;
859 }
860 xmon_set_pagination_lpp(lpp);
861}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862/* Command interpreting routine */
863static char *last_cmd;
864
865static int
866cmds(struct pt_regs *excp)
867{
868 int cmd = 0;
869
870 last_cmd = NULL;
871 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200872
873 if (!xmon_no_auto_backtrace) {
874 xmon_no_auto_backtrace = 1;
875 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
876 }
877
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 for(;;) {
879#ifdef CONFIG_SMP
880 printf("%x:", smp_processor_id());
881#endif /* CONFIG_SMP */
882 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 flush_input();
884 termch = 0;
885 cmd = skipbl();
886 if( cmd == '\n' ) {
887 if (last_cmd == NULL)
888 continue;
889 take_input(last_cmd);
890 last_cmd = NULL;
891 cmd = inchar();
892 }
893 switch (cmd) {
894 case 'm':
895 cmd = inchar();
896 switch (cmd) {
897 case 'm':
898 case 's':
899 case 'd':
900 memops(cmd);
901 break;
902 case 'l':
903 memlocate();
904 break;
905 case 'z':
906 memzcan();
907 break;
908 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700909 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 break;
911 default:
912 termch = cmd;
913 memex();
914 }
915 break;
916 case 'd':
917 dump();
918 break;
919 case 'l':
920 symbol_lookup();
921 break;
922 case 'r':
923 prregs(excp); /* print regs */
924 break;
925 case 'e':
926 excprint(excp);
927 break;
928 case 'S':
929 super_regs();
930 break;
931 case 't':
932 backtrace(excp);
933 break;
934 case 'f':
935 cacheflush();
936 break;
937 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200938 if (do_spu_cmd() == 0)
939 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 if (do_step(excp))
941 return cmd;
942 break;
943 case 'x':
944 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100945 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100947 printf(" <no input ...>\n");
948 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 return cmd;
950 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000951 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 break;
Sam bobroff958b7c82015-10-08 11:50:23 +1100953 case '#':
954 set_lpp_cmd();
955 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 case 'b':
957 bpt_cmds();
958 break;
959 case 'C':
960 csum();
961 break;
962 case 'c':
963 if (cpu_cmd())
964 return 0;
965 break;
966 case 'z':
967 bootcmds();
968 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000969 case 'p':
970 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -0600972 case 'P':
973 show_tasks();
974 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000975#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 case 'u':
977 dump_segments();
978 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +1100979#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100980 case 'u':
981 dump_tlb_44x();
982 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000983#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000984 case 'u':
985 dump_tlb_book3e();
986 break;
987#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 default:
989 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000990 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 if (' ' < cmd && cmd <= '~')
992 putchar(cmd);
993 else
994 printf("\\x%x", cmd);
995 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +0000996 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 printf(" (type ? for help)\n");
998 break;
999 }
1000 }
1001}
1002
Josh Boyercdd39042009-10-05 04:46:05 +00001003#ifdef CONFIG_BOOKE
1004static int do_step(struct pt_regs *regs)
1005{
1006 regs->msr |= MSR_DE;
1007 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1008 return 1;
1009}
1010#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011/*
1012 * Step a single instruction.
1013 * Some instructions we emulate, others we execute with MSR_SE set.
1014 */
1015static int do_step(struct pt_regs *regs)
1016{
1017 unsigned int instr;
1018 int stepped;
1019
1020 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001021 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 if (mread(regs->nip, &instr, 4) == 4) {
1023 stepped = emulate_step(regs, instr);
1024 if (stepped < 0) {
1025 printf("Couldn't single-step %s instruction\n",
1026 (IS_RFID(instr)? "rfid": "mtmsrd"));
1027 return 0;
1028 }
1029 if (stepped > 0) {
1030 regs->trap = 0xd00 | (regs->trap & 1);
1031 printf("stepped to ");
1032 xmon_print_symbol(regs->nip, " ", "\n");
1033 ppc_inst_dump(regs->nip, 1, 0);
1034 return 0;
1035 }
1036 }
1037 }
1038 regs->msr |= MSR_SE;
1039 return 1;
1040}
Josh Boyercdd39042009-10-05 04:46:05 +00001041#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
1043static void bootcmds(void)
1044{
1045 int cmd;
1046
1047 cmd = inchar();
1048 if (cmd == 'r')
1049 ppc_md.restart(NULL);
1050 else if (cmd == 'h')
1051 ppc_md.halt();
1052 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001053 if (pm_power_off)
1054 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055}
1056
1057static int cpu_cmd(void)
1058{
1059#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001060 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
1063 if (!scanhex(&cpu)) {
1064 /* print cpus waiting or in xmon */
1065 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001066 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001067 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001068 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001069 if (cpu == last_cpu + 1) {
1070 last_cpu = cpu;
1071 } else {
1072 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001073 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001074 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001075 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 }
1078 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001079 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001080 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 printf("\n");
1082 return 0;
1083 }
1084 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001085 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 printf("cpu 0x%x isn't in xmon\n", cpu);
1087 return 0;
1088 }
1089 xmon_taken = 0;
1090 mb();
1091 xmon_owner = cpu;
1092 timeout = 10000000;
1093 while (!xmon_taken) {
1094 if (--timeout == 0) {
1095 if (test_and_set_bit(0, &xmon_taken))
1096 break;
1097 /* take control back */
1098 mb();
1099 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001100 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 return 0;
1102 }
1103 barrier();
1104 }
1105 return 1;
1106#else
1107 return 0;
1108#endif /* CONFIG_SMP */
1109}
1110
1111static unsigned short fcstab[256] = {
1112 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1113 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1114 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1115 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1116 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1117 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1118 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1119 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1120 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1121 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1122 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1123 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1124 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1125 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1126 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1127 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1128 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1129 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1130 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1131 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1132 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1133 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1134 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1135 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1136 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1137 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1138 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1139 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1140 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1141 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1142 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1143 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1144};
1145
1146#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1147
1148static void
1149csum(void)
1150{
1151 unsigned int i;
1152 unsigned short fcs;
1153 unsigned char v;
1154
1155 if (!scanhex(&adrs))
1156 return;
1157 if (!scanhex(&ncsum))
1158 return;
1159 fcs = 0xffff;
1160 for (i = 0; i < ncsum; ++i) {
1161 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001162 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 break;
1164 }
1165 fcs = FCS(fcs, v);
1166 }
1167 printf("%x\n", fcs);
1168}
1169
1170/*
1171 * Check if this is a suitable place to put a breakpoint.
1172 */
1173static long check_bp_loc(unsigned long addr)
1174{
1175 unsigned int instr;
1176
1177 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001178 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 printf("Breakpoints may only be placed at kernel addresses\n");
1180 return 0;
1181 }
1182 if (!mread(addr, &instr, sizeof(instr))) {
1183 printf("Can't read instruction at address %lx\n", addr);
1184 return 0;
1185 }
1186 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1187 printf("Breakpoints may not be placed on mtmsrd or rfid "
1188 "instructions\n");
1189 return 0;
1190 }
1191 return 1;
1192}
1193
Michael Ellermane3bc8042012-08-23 22:09:13 +00001194static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 "Breakpoint command usage:\n"
1196 "b show breakpoints\n"
1197 "b <addr> [cnt] set breakpoint at given instr addr\n"
1198 "bc clear all breakpoints\n"
1199 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301200 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 "bd <addr> [cnt] set hardware data breakpoint\n"
1202 "";
1203
1204static void
1205bpt_cmds(void)
1206{
1207 int cmd;
1208 unsigned long a;
1209 int mode, i;
1210 struct bpt *bp;
1211 const char badaddr[] = "Only kernel addresses are permitted "
1212 "for breakpoints\n";
1213
1214 cmd = inchar();
1215 switch (cmd) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001216#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 case 'd': /* bd - hardware data breakpoint */
1218 mode = 7;
1219 cmd = inchar();
1220 if (cmd == 'r')
1221 mode = 5;
1222 else if (cmd == 'w')
1223 mode = 6;
1224 else
1225 termch = cmd;
1226 dabr.address = 0;
1227 dabr.enabled = 0;
1228 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001229 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 printf(badaddr);
1231 break;
1232 }
Michael Neuling9422de32012-12-20 14:06:44 +00001233 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 dabr.enabled = mode | BP_DABR;
1235 }
1236 break;
1237
1238 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301239 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 printf("Hardware instruction breakpoint "
1241 "not supported on this cpu\n");
1242 break;
1243 }
1244 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001245 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 iabr = NULL;
1247 }
1248 if (!scanhex(&a))
1249 break;
1250 if (!check_bp_loc(a))
1251 break;
1252 bp = new_breakpoint(a);
1253 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001254 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 iabr = bp;
1256 }
1257 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001258#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
1260 case 'c':
1261 if (!scanhex(&a)) {
1262 /* clear all breakpoints */
1263 for (i = 0; i < NBPTS; ++i)
1264 bpts[i].enabled = 0;
1265 iabr = NULL;
1266 dabr.enabled = 0;
1267 printf("All breakpoints cleared\n");
1268 break;
1269 }
1270
1271 if (a <= NBPTS && a >= 1) {
1272 /* assume a breakpoint number */
1273 bp = &bpts[a-1]; /* bp nums are 1 based */
1274 } else {
1275 /* assume a breakpoint address */
1276 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001277 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001278 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 break;
1280 }
1281 }
1282
Michael Ellerman736256e2014-05-26 21:02:14 +10001283 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 xmon_print_symbol(bp->address, " ", ")\n");
1285 bp->enabled = 0;
1286 break;
1287
1288 default:
1289 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001290 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 if (cmd == '?') {
1292 printf(breakpoint_help_string);
1293 break;
1294 }
1295 termch = cmd;
1296 if (!scanhex(&a)) {
1297 /* print all breakpoints */
1298 printf(" type address\n");
1299 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001300 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 if (dabr.enabled & 1)
1302 printf("r");
1303 if (dabr.enabled & 2)
1304 printf("w");
1305 printf("]\n");
1306 }
1307 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1308 if (!bp->enabled)
1309 continue;
1310 printf("%2x %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001311 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 xmon_print_symbol(bp->address, " ", "\n");
1313 }
1314 break;
1315 }
1316
1317 if (!check_bp_loc(a))
1318 break;
1319 bp = new_breakpoint(a);
1320 if (bp != NULL)
1321 bp->enabled |= BP_TRAP;
1322 break;
1323 }
1324}
1325
1326/* Very cheap human name for vector lookup. */
1327static
1328const char *getvecname(unsigned long vec)
1329{
1330 char *ret;
1331
1332 switch (vec) {
1333 case 0x100: ret = "(System Reset)"; break;
1334 case 0x200: ret = "(Machine Check)"; break;
1335 case 0x300: ret = "(Data Access)"; break;
1336 case 0x380: ret = "(Data SLB Access)"; break;
1337 case 0x400: ret = "(Instruction Access)"; break;
1338 case 0x480: ret = "(Instruction SLB Access)"; break;
1339 case 0x500: ret = "(Hardware Interrupt)"; break;
1340 case 0x600: ret = "(Alignment)"; break;
1341 case 0x700: ret = "(Program Check)"; break;
1342 case 0x800: ret = "(FPU Unavailable)"; break;
1343 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001344 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1345 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 case 0xc00: ret = "(System Call)"; break;
1347 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001348 case 0xe40: ret = "(Emulation Assist)"; break;
1349 case 0xe60: ret = "(HMI)"; break;
1350 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 case 0xf00: ret = "(Performance Monitor)"; break;
1352 case 0xf20: ret = "(Altivec Unavailable)"; break;
1353 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001354 case 0x1500: ret = "(Denormalisation)"; break;
1355 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 default: ret = "";
1357 }
1358 return ret;
1359}
1360
1361static void get_function_bounds(unsigned long pc, unsigned long *startp,
1362 unsigned long *endp)
1363{
1364 unsigned long size, offset;
1365 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
1367 *startp = *endp = 0;
1368 if (pc == 0)
1369 return;
1370 if (setjmp(bus_error_jmp) == 0) {
1371 catch_memory_errors = 1;
1372 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001373 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 if (name != NULL) {
1375 *startp = pc - offset;
1376 *endp = pc - offset + size;
1377 }
1378 sync();
1379 }
1380 catch_memory_errors = 0;
1381}
1382
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001383#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1384#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386static void xmon_show_stack(unsigned long sp, unsigned long lr,
1387 unsigned long pc)
1388{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001389 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 unsigned long ip;
1391 unsigned long newsp;
1392 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 struct pt_regs regs;
1394
Michael Ellerman0104cd62012-10-09 04:20:36 +00001395 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 if (sp < PAGE_OFFSET) {
1397 if (sp != 0)
1398 printf("SP (%lx) is in userspace\n", sp);
1399 break;
1400 }
1401
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001402 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 || !mread(sp, &newsp, sizeof(unsigned long))) {
1404 printf("Couldn't read stack frame at %lx\n", sp);
1405 break;
1406 }
1407
1408 /*
1409 * For the first stack frame, try to work out if
1410 * LR and/or the saved LR value in the bottommost
1411 * stack frame are valid.
1412 */
1413 if ((pc | lr) != 0) {
1414 unsigned long fnstart, fnend;
1415 unsigned long nextip;
1416 int printip = 1;
1417
1418 get_function_bounds(pc, &fnstart, &fnend);
1419 nextip = 0;
1420 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001421 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 sizeof(unsigned long));
1423 if (lr == ip) {
1424 if (lr < PAGE_OFFSET
1425 || (fnstart <= lr && lr < fnend))
1426 printip = 0;
1427 } else if (lr == nextip) {
1428 printip = 0;
1429 } else if (lr >= PAGE_OFFSET
1430 && !(fnstart <= lr && lr < fnend)) {
1431 printf("[link register ] ");
1432 xmon_print_symbol(lr, " ", "\n");
1433 }
1434 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001435 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 xmon_print_symbol(ip, " ", " (unreliable)\n");
1437 }
1438 pc = lr = 0;
1439
1440 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001441 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 xmon_print_symbol(ip, " ", "\n");
1443 }
1444
1445 /* Look for "regshere" marker to see if this is
1446 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001447 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001448 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001449 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 != sizeof(regs)) {
1451 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001452 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 break;
1454 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001455 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 getvecname(TRAP(&regs)));
1457 pc = regs.nip;
1458 lr = regs.link;
1459 xmon_print_symbol(pc, " ", "\n");
1460 }
1461
1462 if (newsp == 0)
1463 break;
1464
1465 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467}
1468
1469static void backtrace(struct pt_regs *excp)
1470{
1471 unsigned long sp;
1472
1473 if (scanhex(&sp))
1474 xmon_show_stack(sp, 0, 0);
1475 else
1476 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1477 scannl();
1478}
1479
1480static void print_bug_trap(struct pt_regs *regs)
1481{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001482#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001483 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 unsigned long addr;
1485
1486 if (regs->msr & MSR_PR)
1487 return; /* not in kernel */
1488 addr = regs->nip; /* address of trap instruction */
1489 if (addr < PAGE_OFFSET)
1490 return;
1491 bug = find_bug(regs->nip);
1492 if (bug == NULL)
1493 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001494 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 return;
1496
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001497#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001498 printf("kernel BUG at %s:%u!\n",
1499 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001500#else
1501 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1502#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001503#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504}
1505
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001506static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507{
1508 unsigned long trap;
1509
1510#ifdef CONFIG_SMP
1511 printf("cpu 0x%x: ", smp_processor_id());
1512#endif /* CONFIG_SMP */
1513
1514 trap = TRAP(fp);
1515 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1516 printf(" pc: ");
1517 xmon_print_symbol(fp->nip, ": ", "\n");
1518
1519 printf(" lr: ", fp->link);
1520 xmon_print_symbol(fp->link, ": ", "\n");
1521
1522 printf(" sp: %lx\n", fp->gpr[1]);
1523 printf(" msr: %lx\n", fp->msr);
1524
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001525 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 printf(" dar: %lx\n", fp->dar);
1527 if (trap != 0x380)
1528 printf(" dsisr: %lx\n", fp->dsisr);
1529 }
1530
1531 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001532#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001533 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1534 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001535#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 if (current) {
1537 printf(" pid = %ld, comm = %s\n",
1538 current->pid, current->comm);
1539 }
1540
1541 if (trap == 0x700)
1542 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001543
1544 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545}
1546
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001547static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001549 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 unsigned long base;
1551 struct pt_regs regs;
1552
1553 if (scanhex(&base)) {
1554 if (setjmp(bus_error_jmp) == 0) {
1555 catch_memory_errors = 1;
1556 sync();
1557 regs = *(struct pt_regs *)base;
1558 sync();
1559 __delay(200);
1560 } else {
1561 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001562 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 base);
1564 return;
1565 }
1566 catch_memory_errors = 0;
1567 fp = &regs;
1568 }
1569
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001570#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 if (FULL_REGS(fp)) {
1572 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001573 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1575 } else {
1576 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001577 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1579 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001580#else
1581 for (n = 0; n < 32; ++n) {
1582 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1583 (n & 3) == 3? "\n": " ");
1584 if (n == 12 && !FULL_REGS(fp)) {
1585 printf("\n");
1586 break;
1587 }
1588 }
1589#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 printf("pc = ");
1591 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001592 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1593 printf("cfar= ");
1594 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 printf("lr = ");
1597 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001598 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1599 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001601 trap = TRAP(fp);
1602 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1603 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604}
1605
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001606static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607{
1608 int cmd;
1609 unsigned long nflush;
1610
1611 cmd = inchar();
1612 if (cmd != 'i')
1613 termch = cmd;
1614 scanhex((void *)&adrs);
1615 if (termch != '\n')
1616 termch = 0;
1617 nflush = 1;
1618 scanhex(&nflush);
1619 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1620 if (setjmp(bus_error_jmp) == 0) {
1621 catch_memory_errors = 1;
1622 sync();
1623
1624 if (cmd != 'i') {
1625 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1626 cflush((void *) adrs);
1627 } else {
1628 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1629 cinval((void *) adrs);
1630 }
1631 sync();
1632 /* wait a little while to see if we get a machine check */
1633 __delay(200);
1634 }
1635 catch_memory_errors = 0;
1636}
1637
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001638static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639read_spr(int n)
1640{
1641 unsigned int instrs[2];
1642 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001644#ifdef CONFIG_PPC64
1645 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 opd[0] = (unsigned long)instrs;
1648 opd[1] = 0;
1649 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001650 code = (unsigned long (*)(void)) opd;
1651#else
1652 code = (unsigned long (*)(void)) instrs;
1653#endif
1654
1655 /* mfspr r3,n; blr */
1656 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1657 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 store_inst(instrs);
1659 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
1661 if (setjmp(bus_error_jmp) == 0) {
1662 catch_memory_errors = 1;
1663 sync();
1664
1665 ret = code();
1666
1667 sync();
1668 /* wait a little while to see if we get a machine check */
1669 __delay(200);
1670 n = size;
1671 }
1672
1673 return ret;
1674}
1675
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001676static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677write_spr(int n, unsigned long val)
1678{
1679 unsigned int instrs[2];
1680 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001681#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 unsigned long opd[3];
1683
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 opd[0] = (unsigned long)instrs;
1685 opd[1] = 0;
1686 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001687 code = (unsigned long (*)(unsigned long)) opd;
1688#else
1689 code = (unsigned long (*)(unsigned long)) instrs;
1690#endif
1691
1692 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1693 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 store_inst(instrs);
1695 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 if (setjmp(bus_error_jmp) == 0) {
1698 catch_memory_errors = 1;
1699 sync();
1700
1701 code(val);
1702
1703 sync();
1704 /* wait a little while to see if we get a machine check */
1705 __delay(200);
1706 n = size;
1707 }
1708}
1709
1710static unsigned long regno;
1711extern char exc_prolog;
1712extern char dec_exc;
1713
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001714static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715{
1716 int cmd;
1717 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718
1719 cmd = skipbl();
1720 if (cmd == '\n') {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001721 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 asm("mr %0,1" : "=r" (sp) :);
1723 asm("mr %0,2" : "=r" (toc) :);
1724
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001725 printf("msr = "REG" sprg0= "REG"\n",
1726 mfmsr(), mfspr(SPRN_SPRG0));
1727 printf("pvr = "REG" sprg1= "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001728 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001729 printf("dec = "REG" sprg2= "REG"\n",
1730 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1731 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1732 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
1734 return;
1735 }
1736
1737 scanhex(&regno);
1738 switch (cmd) {
1739 case 'w':
1740 val = read_spr(regno);
1741 scanhex(&val);
1742 write_spr(regno, val);
1743 /* fall through */
1744 case 'r':
1745 printf("spr %lx = %lx\n", regno, read_spr(regno));
1746 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 }
1748 scannl();
1749}
1750
1751/*
1752 * Stuff for reading and writing memory safely
1753 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001754static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755mread(unsigned long adrs, void *buf, int size)
1756{
1757 volatile int n;
1758 char *p, *q;
1759
1760 n = 0;
1761 if (setjmp(bus_error_jmp) == 0) {
1762 catch_memory_errors = 1;
1763 sync();
1764 p = (char *)adrs;
1765 q = (char *)buf;
1766 switch (size) {
1767 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001768 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 break;
1770 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001771 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 break;
1773 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001774 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 break;
1776 default:
1777 for( ; n < size; ++n) {
1778 *q++ = *p++;
1779 sync();
1780 }
1781 }
1782 sync();
1783 /* wait a little while to see if we get a machine check */
1784 __delay(200);
1785 n = size;
1786 }
1787 catch_memory_errors = 0;
1788 return n;
1789}
1790
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001791static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792mwrite(unsigned long adrs, void *buf, int size)
1793{
1794 volatile int n;
1795 char *p, *q;
1796
1797 n = 0;
1798 if (setjmp(bus_error_jmp) == 0) {
1799 catch_memory_errors = 1;
1800 sync();
1801 p = (char *) adrs;
1802 q = (char *) buf;
1803 switch (size) {
1804 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001805 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 break;
1807 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001808 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 break;
1810 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001811 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 break;
1813 default:
1814 for ( ; n < size; ++n) {
1815 *p++ = *q++;
1816 sync();
1817 }
1818 }
1819 sync();
1820 /* wait a little while to see if we get a machine check */
1821 __delay(200);
1822 n = size;
1823 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10001824 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 }
1826 catch_memory_errors = 0;
1827 return n;
1828}
1829
1830static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001831static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832static char *fault_chars[] = { "--", "**", "##" };
1833
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001834static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001836 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 switch (TRAP(regs)) {
1838 case 0x200:
1839 fault_type = 0;
1840 break;
1841 case 0x300:
1842 case 0x380:
1843 fault_type = 1;
1844 break;
1845 default:
1846 fault_type = 2;
1847 }
1848
1849 longjmp(bus_error_jmp, 1);
1850
1851 return 0;
1852}
1853
1854#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1855
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001856static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857byterev(unsigned char *val, int size)
1858{
1859 int t;
1860
1861 switch (size) {
1862 case 2:
1863 SWAP(val[0], val[1], t);
1864 break;
1865 case 4:
1866 SWAP(val[0], val[3], t);
1867 SWAP(val[1], val[2], t);
1868 break;
1869 case 8: /* is there really any use for this? */
1870 SWAP(val[0], val[7], t);
1871 SWAP(val[1], val[6], t);
1872 SWAP(val[2], val[5], t);
1873 SWAP(val[3], val[4], t);
1874 break;
1875 }
1876}
1877
1878static int brev;
1879static int mnoread;
1880
Michael Ellermane3bc8042012-08-23 22:09:13 +00001881static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 "Memory examine command usage:\n"
1883 "m [addr] [flags] examine/change memory\n"
1884 " addr is optional. will start where left off.\n"
1885 " flags may include chars from this set:\n"
1886 " b modify by bytes (default)\n"
1887 " w modify by words (2 byte)\n"
1888 " l modify by longs (4 byte)\n"
1889 " d modify by doubleword (8 byte)\n"
1890 " r toggle reverse byte order mode\n"
1891 " n do not read memory (for i/o spaces)\n"
1892 " . ok to read (default)\n"
1893 "NOTE: flags are saved as defaults\n"
1894 "";
1895
Michael Ellermane3bc8042012-08-23 22:09:13 +00001896static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 "Memory examine subcommands:\n"
1898 " hexval write this val to current location\n"
1899 " 'string' write chars from string to this location\n"
1900 " ' increment address\n"
1901 " ^ decrement address\n"
1902 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1903 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1904 " ` clear no-read flag\n"
1905 " ; stay at this addr\n"
1906 " v change to byte mode\n"
1907 " w change to word (2 byte) mode\n"
1908 " l change to long (4 byte) mode\n"
1909 " u change to doubleword (8 byte) mode\n"
1910 " m addr change current addr\n"
1911 " n toggle no-read flag\n"
1912 " r toggle byte reverse flag\n"
1913 " < count back up count bytes\n"
1914 " > count skip forward count bytes\n"
1915 " x exit this mode\n"
1916 "";
1917
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001918static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919memex(void)
1920{
1921 int cmd, inc, i, nslash;
1922 unsigned long n;
1923 unsigned char val[16];
1924
1925 scanhex((void *)&adrs);
1926 cmd = skipbl();
1927 if (cmd == '?') {
1928 printf(memex_help_string);
1929 return;
1930 } else {
1931 termch = cmd;
1932 }
1933 last_cmd = "m\n";
1934 while ((cmd = skipbl()) != '\n') {
1935 switch( cmd ){
1936 case 'b': size = 1; break;
1937 case 'w': size = 2; break;
1938 case 'l': size = 4; break;
1939 case 'd': size = 8; break;
1940 case 'r': brev = !brev; break;
1941 case 'n': mnoread = 1; break;
1942 case '.': mnoread = 0; break;
1943 }
1944 }
1945 if( size <= 0 )
1946 size = 1;
1947 else if( size > 8 )
1948 size = 8;
1949 for(;;){
1950 if (!mnoread)
1951 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001952 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 if (!mnoread) {
1954 if (brev)
1955 byterev(val, size);
1956 putchar(' ');
1957 for (i = 0; i < n; ++i)
1958 printf("%.2x", val[i]);
1959 for (; i < size; ++i)
1960 printf("%s", fault_chars[fault_type]);
1961 }
1962 putchar(' ');
1963 inc = size;
1964 nslash = 0;
1965 for(;;){
1966 if( scanhex(&n) ){
1967 for (i = 0; i < size; ++i)
1968 val[i] = n >> (i * 8);
1969 if (!brev)
1970 byterev(val, size);
1971 mwrite(adrs, val, size);
1972 inc = size;
1973 }
1974 cmd = skipbl();
1975 if (cmd == '\n')
1976 break;
1977 inc = 0;
1978 switch (cmd) {
1979 case '\'':
1980 for(;;){
1981 n = inchar();
1982 if( n == '\\' )
1983 n = bsesc();
1984 else if( n == '\'' )
1985 break;
1986 for (i = 0; i < size; ++i)
1987 val[i] = n >> (i * 8);
1988 if (!brev)
1989 byterev(val, size);
1990 mwrite(adrs, val, size);
1991 adrs += size;
1992 }
1993 adrs -= size;
1994 inc = size;
1995 break;
1996 case ',':
1997 adrs += size;
1998 break;
1999 case '.':
2000 mnoread = 0;
2001 break;
2002 case ';':
2003 break;
2004 case 'x':
2005 case EOF:
2006 scannl();
2007 return;
2008 case 'b':
2009 case 'v':
2010 size = 1;
2011 break;
2012 case 'w':
2013 size = 2;
2014 break;
2015 case 'l':
2016 size = 4;
2017 break;
2018 case 'u':
2019 size = 8;
2020 break;
2021 case '^':
2022 adrs -= size;
2023 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 case '/':
2025 if (nslash > 0)
2026 adrs -= 1 << nslash;
2027 else
2028 nslash = 0;
2029 nslash += 4;
2030 adrs += 1 << nslash;
2031 break;
2032 case '\\':
2033 if (nslash < 0)
2034 adrs += 1 << -nslash;
2035 else
2036 nslash = 0;
2037 nslash -= 4;
2038 adrs -= 1 << -nslash;
2039 break;
2040 case 'm':
2041 scanhex((void *)&adrs);
2042 break;
2043 case 'n':
2044 mnoread = 1;
2045 break;
2046 case 'r':
2047 brev = !brev;
2048 break;
2049 case '<':
2050 n = size;
2051 scanhex(&n);
2052 adrs -= n;
2053 break;
2054 case '>':
2055 n = size;
2056 scanhex(&n);
2057 adrs += n;
2058 break;
2059 case '?':
2060 printf(memex_subcmd_help_string);
2061 break;
2062 }
2063 }
2064 adrs += inc;
2065 }
2066}
2067
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002068static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069bsesc(void)
2070{
2071 int c;
2072
2073 c = inchar();
2074 switch( c ){
2075 case 'n': c = '\n'; break;
2076 case 'r': c = '\r'; break;
2077 case 'b': c = '\b'; break;
2078 case 't': c = '\t'; break;
2079 }
2080 return c;
2081}
2082
Olaf Hering7e5b5932006-03-08 20:40:28 +01002083static void xmon_rawdump (unsigned long adrs, long ndump)
2084{
2085 long n, m, r, nr;
2086 unsigned char temp[16];
2087
2088 for (n = ndump; n > 0;) {
2089 r = n < 16? n: 16;
2090 nr = mread(adrs, temp, r);
2091 adrs += nr;
2092 for (m = 0; m < r; ++m) {
2093 if (m < nr)
2094 printf("%.2x", temp[m]);
2095 else
2096 printf("%s", fault_chars[fault_type]);
2097 }
2098 n -= r;
2099 if (nr < r)
2100 break;
2101 }
2102 printf("\n");
2103}
2104
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002105#ifdef CONFIG_PPC64
2106static void dump_one_paca(int cpu)
2107{
2108 struct paca_struct *p;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002109#ifdef CONFIG_PPC_STD_MMU_64
2110 int i = 0;
2111#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002112
2113 if (setjmp(bus_error_jmp) != 0) {
2114 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2115 return;
2116 }
2117
2118 catch_memory_errors = 1;
2119 sync();
2120
2121 p = &paca[cpu];
2122
2123 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2124
Michael Ellermanad987fc2015-10-14 16:58:36 +11002125 printf(" %-*s = %s\n", 20, "possible", cpu_possible(cpu) ? "yes" : "no");
2126 printf(" %-*s = %s\n", 20, "present", cpu_present(cpu) ? "yes" : "no");
2127 printf(" %-*s = %s\n", 20, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002128
2129#define DUMP(paca, name, format) \
Michael Ellermanad987fc2015-10-14 16:58:36 +11002130 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 20, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002131 offsetof(struct paca_struct, name));
2132
2133 DUMP(p, lock_token, "x");
2134 DUMP(p, paca_index, "x");
2135 DUMP(p, kernel_toc, "lx");
2136 DUMP(p, kernelbase, "lx");
2137 DUMP(p, kernel_msr, "lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002138 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302139#ifdef CONFIG_PPC_BOOK3S_64
2140 DUMP(p, mc_emergency_sp, "p");
2141 DUMP(p, in_mce, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002142 DUMP(p, hmi_event_available, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302143#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002144 DUMP(p, data_offset, "lx");
2145 DUMP(p, hw_cpu_id, "x");
2146 DUMP(p, cpu_start, "x");
2147 DUMP(p, kexec_state, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002148#ifdef CONFIG_PPC_STD_MMU_64
2149 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2150 u64 esid, vsid;
2151
2152 if (!p->slb_shadow_ptr)
2153 continue;
2154
2155 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2156 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
2157
2158 if (esid || vsid) {
2159 printf(" slb_shadow[%d]: = 0x%016lx 0x%016lx\n",
2160 i, esid, vsid);
2161 }
2162 }
2163 DUMP(p, vmalloc_sllp, "x");
2164 DUMP(p, slb_cache_ptr, "x");
2165 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2166 printf(" slb_cache[%d]: = 0x%016lx\n", i, p->slb_cache[i]);
2167#endif
2168 DUMP(p, dscr_default, "llx");
2169#ifdef CONFIG_PPC_BOOK3E
2170 DUMP(p, pgd, "p");
2171 DUMP(p, kernel_pgd, "p");
2172 DUMP(p, tcd_ptr, "p");
2173 DUMP(p, mc_kstack, "p");
2174 DUMP(p, crit_kstack, "p");
2175 DUMP(p, dbg_kstack, "p");
2176#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002177 DUMP(p, __current, "p");
2178 DUMP(p, kstack, "lx");
2179 DUMP(p, stab_rr, "lx");
2180 DUMP(p, saved_r1, "lx");
2181 DUMP(p, trap_save, "x");
2182 DUMP(p, soft_enabled, "x");
2183 DUMP(p, irq_happened, "x");
2184 DUMP(p, io_sync, "x");
2185 DUMP(p, irq_work_pending, "x");
2186 DUMP(p, nap_state_lost, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002187 DUMP(p, sprg_vdso, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002188
Michael Ellermanad987fc2015-10-14 16:58:36 +11002189#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
2190 DUMP(p, tm_scratch, "llx");
2191#endif
2192
2193#ifdef CONFIG_PPC_POWERNV
2194 DUMP(p, core_idle_state_ptr, "p");
2195 DUMP(p, thread_idle_state, "x");
2196 DUMP(p, thread_mask, "x");
2197 DUMP(p, subcore_sibling_mask, "x");
2198#endif
2199
2200 DUMP(p, user_time, "llx");
2201 DUMP(p, system_time, "llx");
2202 DUMP(p, user_time_scaled, "llx");
2203 DUMP(p, starttime, "llx");
2204 DUMP(p, starttime_user, "llx");
2205 DUMP(p, startspurr, "llx");
2206 DUMP(p, utime_sspurr, "llx");
2207 DUMP(p, stolen_time, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002208#undef DUMP
2209
2210 catch_memory_errors = 0;
2211 sync();
2212}
2213
2214static void dump_all_pacas(void)
2215{
2216 int cpu;
2217
2218 if (num_possible_cpus() == 0) {
2219 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2220 return;
2221 }
2222
2223 for_each_possible_cpu(cpu)
2224 dump_one_paca(cpu);
2225}
2226
2227static void dump_pacas(void)
2228{
2229 unsigned long num;
2230 int c;
2231
2232 c = inchar();
2233 if (c == 'a') {
2234 dump_all_pacas();
2235 return;
2236 }
2237
2238 termch = c; /* Put c back, it wasn't 'a' */
2239
2240 if (scanhex(&num))
2241 dump_one_paca(num);
2242 else
2243 dump_one_paca(xmon_owner);
2244}
2245#endif
2246
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002247static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248dump(void)
2249{
2250 int c;
2251
2252 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002253
2254#ifdef CONFIG_PPC64
2255 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002256 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002257 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002258 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002259 return;
2260 }
2261#endif
2262
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2264 termch = c;
2265 scanhex((void *)&adrs);
2266 if (termch != '\n')
2267 termch = 0;
2268 if (c == 'i') {
2269 scanhex(&nidump);
2270 if (nidump == 0)
2271 nidump = 16;
2272 else if (nidump > MAX_DUMP)
2273 nidump = MAX_DUMP;
2274 adrs += ppc_inst_dump(adrs, nidump, 1);
2275 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002276 } else if (c == 'l') {
2277 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002278 } else if (c == 'o') {
2279 dump_opal_msglog();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002280 } else if (c == 'r') {
2281 scanhex(&ndump);
2282 if (ndump == 0)
2283 ndump = 64;
2284 xmon_rawdump(adrs, ndump);
2285 adrs += ndump;
2286 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 } else {
2288 scanhex(&ndump);
2289 if (ndump == 0)
2290 ndump = 64;
2291 else if (ndump > MAX_DUMP)
2292 ndump = MAX_DUMP;
2293 prdump(adrs, ndump);
2294 adrs += ndump;
2295 last_cmd = "d\n";
2296 }
2297}
2298
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002299static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300prdump(unsigned long adrs, long ndump)
2301{
2302 long n, m, c, r, nr;
2303 unsigned char temp[16];
2304
2305 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002306 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 putchar(' ');
2308 r = n < 16? n: 16;
2309 nr = mread(adrs, temp, r);
2310 adrs += nr;
2311 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002312 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002313 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 if (m < nr)
2315 printf("%.2x", temp[m]);
2316 else
2317 printf("%s", fault_chars[fault_type]);
2318 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002319 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002320 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002321 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 printf(" |");
2325 for (m = 0; m < r; ++m) {
2326 if (m < nr) {
2327 c = temp[m];
2328 putchar(' ' <= c && c <= '~'? c: '.');
2329 } else
2330 putchar(' ');
2331 }
2332 n -= r;
2333 for (; m < 16; ++m)
2334 putchar(' ');
2335 printf("|\n");
2336 if (nr < r)
2337 break;
2338 }
2339}
2340
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002341typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2342
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002343static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002344generic_inst_dump(unsigned long adr, long count, int praddr,
2345 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346{
2347 int nr, dotted;
2348 unsigned long first_adr;
2349 unsigned long inst, last_inst = 0;
2350 unsigned char val[4];
2351
2352 dotted = 0;
2353 for (first_adr = adr; count > 0; --count, adr += 4) {
2354 nr = mread(adr, val, 4);
2355 if (nr == 0) {
2356 if (praddr) {
2357 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002358 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 }
2360 break;
2361 }
2362 inst = GETWORD(val);
2363 if (adr > first_adr && inst == last_inst) {
2364 if (!dotted) {
2365 printf(" ...\n");
2366 dotted = 1;
2367 }
2368 continue;
2369 }
2370 dotted = 0;
2371 last_inst = inst;
2372 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002373 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002375 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 printf("\n");
2377 }
2378 return adr - first_adr;
2379}
2380
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002381static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002382ppc_inst_dump(unsigned long adr, long count, int praddr)
2383{
2384 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2385}
2386
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387void
2388print_address(unsigned long addr)
2389{
2390 xmon_print_symbol(addr, "\t# ", "");
2391}
2392
Vinay Sridharf312deb2009-05-14 23:13:07 +00002393void
2394dump_log_buf(void)
2395{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002396 struct kmsg_dumper dumper = { .active = 1 };
2397 unsigned char buf[128];
2398 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002399
Michael Ellermane3bc8042012-08-23 22:09:13 +00002400 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002401 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002402 return;
2403 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002404
Michael Ellermane3bc8042012-08-23 22:09:13 +00002405 catch_memory_errors = 1;
2406 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002407
Michael Ellermanca5dd392012-08-23 22:09:12 +00002408 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002409 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002410 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2411 buf[len] = '\0';
2412 printf("%s", buf);
2413 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002414 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002415
Michael Ellermane3bc8042012-08-23 22:09:13 +00002416 sync();
2417 /* wait a little while to see if we get a machine check */
2418 __delay(200);
2419 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002420}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002422#ifdef CONFIG_PPC_POWERNV
2423static void dump_opal_msglog(void)
2424{
2425 unsigned char buf[128];
2426 ssize_t res;
2427 loff_t pos = 0;
2428
2429 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2430 printf("Machine is not running OPAL firmware.\n");
2431 return;
2432 }
2433
2434 if (setjmp(bus_error_jmp) != 0) {
2435 printf("Error dumping OPAL msglog!\n");
2436 return;
2437 }
2438
2439 catch_memory_errors = 1;
2440 sync();
2441
2442 xmon_start_pagination();
2443 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2444 if (res < 0) {
2445 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2446 break;
2447 }
2448 buf[res] = '\0';
2449 printf("%s", buf);
2450 pos += res;
2451 }
2452 xmon_end_pagination();
2453
2454 sync();
2455 /* wait a little while to see if we get a machine check */
2456 __delay(200);
2457 catch_memory_errors = 0;
2458}
2459#endif
2460
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461/*
2462 * Memory operations - move, set, print differences
2463 */
2464static unsigned long mdest; /* destination address */
2465static unsigned long msrc; /* source address */
2466static unsigned long mval; /* byte value to set memory to */
2467static unsigned long mcount; /* # bytes to affect */
2468static unsigned long mdiffs; /* max # differences to print */
2469
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002470static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471memops(int cmd)
2472{
2473 scanhex((void *)&mdest);
2474 if( termch != '\n' )
2475 termch = 0;
2476 scanhex((void *)(cmd == 's'? &mval: &msrc));
2477 if( termch != '\n' )
2478 termch = 0;
2479 scanhex((void *)&mcount);
2480 switch( cmd ){
2481 case 'm':
2482 memmove((void *)mdest, (void *)msrc, mcount);
2483 break;
2484 case 's':
2485 memset((void *)mdest, mval, mcount);
2486 break;
2487 case 'd':
2488 if( termch != '\n' )
2489 termch = 0;
2490 scanhex((void *)&mdiffs);
2491 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2492 break;
2493 }
2494}
2495
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002496static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2498{
2499 unsigned n, prt;
2500
2501 prt = 0;
2502 for( n = nb; n > 0; --n )
2503 if( *p1++ != *p2++ )
2504 if( ++prt <= maxpr )
2505 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2506 p1[-1], p2 - 1, p2[-1]);
2507 if( prt > maxpr )
2508 printf("Total of %d differences\n", prt);
2509}
2510
2511static unsigned mend;
2512static unsigned mask;
2513
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002514static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515memlocate(void)
2516{
2517 unsigned a, n;
2518 unsigned char val[4];
2519
2520 last_cmd = "ml";
2521 scanhex((void *)&mdest);
2522 if (termch != '\n') {
2523 termch = 0;
2524 scanhex((void *)&mend);
2525 if (termch != '\n') {
2526 termch = 0;
2527 scanhex((void *)&mval);
2528 mask = ~0;
2529 if (termch != '\n') termch = 0;
2530 scanhex((void *)&mask);
2531 }
2532 }
2533 n = 0;
2534 for (a = mdest; a < mend; a += 4) {
2535 if (mread(a, val, 4) == 4
2536 && ((GETWORD(val) ^ mval) & mask) == 0) {
2537 printf("%.16x: %.16x\n", a, GETWORD(val));
2538 if (++n >= 10)
2539 break;
2540 }
2541 }
2542}
2543
2544static unsigned long mskip = 0x1000;
2545static unsigned long mlim = 0xffffffff;
2546
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002547static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548memzcan(void)
2549{
2550 unsigned char v;
2551 unsigned a;
2552 int ok, ook;
2553
2554 scanhex(&mdest);
2555 if (termch != '\n') termch = 0;
2556 scanhex(&mskip);
2557 if (termch != '\n') termch = 0;
2558 scanhex(&mlim);
2559 ook = 0;
2560 for (a = mdest; a < mlim; a += mskip) {
2561 ok = mread(a, &v, 1);
2562 if (ok && !ook) {
2563 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 } else if (!ok && ook)
2565 printf("%.8x\n", a - mskip);
2566 ook = ok;
2567 if (a + mskip < a)
2568 break;
2569 }
2570 if (ook)
2571 printf("%.8x\n", a - mskip);
2572}
2573
Douglas Miller6dfb5402015-11-23 09:01:15 -06002574static void show_task(struct task_struct *tsk)
2575{
2576 char state;
2577
2578 /*
2579 * Cloned from kdb_task_state_char(), which is not entirely
2580 * appropriate for calling from xmon. This could be moved
2581 * to a common, generic, routine used by both.
2582 */
2583 state = (tsk->state == 0) ? 'R' :
2584 (tsk->state < 0) ? 'U' :
2585 (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
2586 (tsk->state & TASK_STOPPED) ? 'T' :
2587 (tsk->state & TASK_TRACED) ? 'C' :
2588 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
2589 (tsk->exit_state & EXIT_DEAD) ? 'E' :
2590 (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
2591
2592 printf("%p %016lx %6d %6d %c %2d %s\n", tsk,
2593 tsk->thread.ksp,
2594 tsk->pid, tsk->parent->pid,
2595 state, task_thread_info(tsk)->cpu,
2596 tsk->comm);
2597}
2598
2599static void show_tasks(void)
2600{
2601 unsigned long tskv;
2602 struct task_struct *tsk = NULL;
2603
2604 printf(" task_struct ->thread.ksp PID PPID S P CMD\n");
2605
2606 if (scanhex(&tskv))
2607 tsk = (struct task_struct *)tskv;
2608
2609 if (setjmp(bus_error_jmp) != 0) {
2610 catch_memory_errors = 0;
2611 printf("*** Error dumping task %p\n", tsk);
2612 return;
2613 }
2614
2615 catch_memory_errors = 1;
2616 sync();
2617
2618 if (tsk)
2619 show_task(tsk);
2620 else
2621 for_each_process(tsk)
2622 show_task(tsk);
2623
2624 sync();
2625 __delay(200);
2626 catch_memory_errors = 0;
2627}
2628
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002629static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002630{
2631 unsigned long args[8];
2632 unsigned long ret;
2633 int i;
2634 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2635 unsigned long, unsigned long, unsigned long,
2636 unsigned long, unsigned long, unsigned long);
2637 callfunc_t func;
2638
2639 if (!scanhex(&adrs))
2640 return;
2641 if (termch != '\n')
2642 termch = 0;
2643 for (i = 0; i < 8; ++i)
2644 args[i] = 0;
2645 for (i = 0; i < 8; ++i) {
2646 if (!scanhex(&args[i]) || termch == '\n')
2647 break;
2648 termch = 0;
2649 }
2650 func = (callfunc_t) adrs;
2651 ret = 0;
2652 if (setjmp(bus_error_jmp) == 0) {
2653 catch_memory_errors = 1;
2654 sync();
2655 ret = func(args[0], args[1], args[2], args[3],
2656 args[4], args[5], args[6], args[7]);
2657 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10002658 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002659 } else {
2660 printf("*** %x exception occurred\n", fault_except);
2661 }
2662 catch_memory_errors = 0;
2663}
2664
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665/* Input scanning routines */
2666int
2667skipbl(void)
2668{
2669 int c;
2670
2671 if( termch != 0 ){
2672 c = termch;
2673 termch = 0;
2674 } else
2675 c = inchar();
2676 while( c == ' ' || c == '\t' )
2677 c = inchar();
2678 return c;
2679}
2680
2681#define N_PTREGS 44
2682static char *regnames[N_PTREGS] = {
2683 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2684 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2685 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2686 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002687 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2688#ifdef CONFIG_PPC64
2689 "softe",
2690#else
2691 "mq",
2692#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 "trap", "dar", "dsisr", "res"
2694};
2695
2696int
2697scanhex(unsigned long *vp)
2698{
2699 int c, d;
2700 unsigned long v;
2701
2702 c = skipbl();
2703 if (c == '%') {
2704 /* parse register name */
2705 char regname[8];
2706 int i;
2707
2708 for (i = 0; i < sizeof(regname) - 1; ++i) {
2709 c = inchar();
2710 if (!isalnum(c)) {
2711 termch = c;
2712 break;
2713 }
2714 regname[i] = c;
2715 }
2716 regname[i] = 0;
2717 for (i = 0; i < N_PTREGS; ++i) {
2718 if (strcmp(regnames[i], regname) == 0) {
2719 if (xmon_regs == NULL) {
2720 printf("regs not available\n");
2721 return 0;
2722 }
2723 *vp = ((unsigned long *)xmon_regs)[i];
2724 return 1;
2725 }
2726 }
2727 printf("invalid register name '%%%s'\n", regname);
2728 return 0;
2729 }
2730
2731 /* skip leading "0x" if any */
2732
2733 if (c == '0') {
2734 c = inchar();
2735 if (c == 'x') {
2736 c = inchar();
2737 } else {
2738 d = hexdigit(c);
2739 if (d == EOF) {
2740 termch = c;
2741 *vp = 0;
2742 return 1;
2743 }
2744 }
2745 } else if (c == '$') {
2746 int i;
2747 for (i=0; i<63; i++) {
2748 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02002749 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 termch = c;
2751 break;
2752 }
2753 tmpstr[i] = c;
2754 }
2755 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002756 *vp = 0;
2757 if (setjmp(bus_error_jmp) == 0) {
2758 catch_memory_errors = 1;
2759 sync();
2760 *vp = kallsyms_lookup_name(tmpstr);
2761 sync();
2762 }
2763 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 if (!(*vp)) {
2765 printf("unknown symbol '%s'\n", tmpstr);
2766 return 0;
2767 }
2768 return 1;
2769 }
2770
2771 d = hexdigit(c);
2772 if (d == EOF) {
2773 termch = c;
2774 return 0;
2775 }
2776 v = 0;
2777 do {
2778 v = (v << 4) + d;
2779 c = inchar();
2780 d = hexdigit(c);
2781 } while (d != EOF);
2782 termch = c;
2783 *vp = v;
2784 return 1;
2785}
2786
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002787static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788scannl(void)
2789{
2790 int c;
2791
2792 c = termch;
2793 termch = 0;
2794 while( c != '\n' )
2795 c = inchar();
2796}
2797
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002798static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799{
2800 if( '0' <= c && c <= '9' )
2801 return c - '0';
2802 if( 'A' <= c && c <= 'F' )
2803 return c - ('A' - 10);
2804 if( 'a' <= c && c <= 'f' )
2805 return c - ('a' - 10);
2806 return EOF;
2807}
2808
2809void
2810getstring(char *s, int size)
2811{
2812 int c;
2813
2814 c = skipbl();
2815 do {
2816 if( size > 1 ){
2817 *s++ = c;
2818 --size;
2819 }
2820 c = inchar();
2821 } while( c != ' ' && c != '\t' && c != '\n' );
2822 termch = c;
2823 *s = 0;
2824}
2825
2826static char line[256];
2827static char *lineptr;
2828
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002829static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830flush_input(void)
2831{
2832 lineptr = NULL;
2833}
2834
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002835static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836inchar(void)
2837{
2838 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002839 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 lineptr = NULL;
2841 return EOF;
2842 }
2843 lineptr = line;
2844 }
2845 return *lineptr++;
2846}
2847
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002848static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849take_input(char *str)
2850{
2851 lineptr = str;
2852}
2853
2854
2855static void
2856symbol_lookup(void)
2857{
2858 int type = inchar();
2859 unsigned long addr;
2860 static char tmp[64];
2861
2862 switch (type) {
2863 case 'a':
2864 if (scanhex(&addr))
2865 xmon_print_symbol(addr, ": ", "\n");
2866 termch = 0;
2867 break;
2868 case 's':
2869 getstring(tmp, 64);
2870 if (setjmp(bus_error_jmp) == 0) {
2871 catch_memory_errors = 1;
2872 sync();
2873 addr = kallsyms_lookup_name(tmp);
2874 if (addr)
2875 printf("%s: %lx\n", tmp, addr);
2876 else
2877 printf("Symbol '%s' not found.\n", tmp);
2878 sync();
2879 }
2880 catch_memory_errors = 0;
2881 termch = 0;
2882 break;
2883 }
2884}
2885
2886
2887/* Print an address in numeric and symbolic form (if possible) */
2888static void xmon_print_symbol(unsigned long address, const char *mid,
2889 const char *after)
2890{
2891 char *modname;
2892 const char *name = NULL;
2893 unsigned long offset, size;
2894
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002895 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 if (setjmp(bus_error_jmp) == 0) {
2897 catch_memory_errors = 1;
2898 sync();
2899 name = kallsyms_lookup(address, &size, &offset, &modname,
2900 tmpstr);
2901 sync();
2902 /* wait a little while to see if we get a machine check */
2903 __delay(200);
2904 }
2905
2906 catch_memory_errors = 0;
2907
2908 if (name) {
2909 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2910 if (modname)
2911 printf(" [%s]", modname);
2912 }
2913 printf("%s", after);
2914}
2915
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002916#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10002917void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918{
2919 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05302920 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11002921 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922
Michael Ellerman736256e2014-05-26 21:02:14 +10002923 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924
Michael Neuling584f8b72007-12-06 17:24:48 +11002925 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002926 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2927 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Anshuman Khandual8218a302015-07-29 12:40:04 +05302928 if (esid || vsid) {
will schmidtb3b95952007-12-07 08:22:23 +11002929 printf("%02d %016lx %016lx", i, esid, vsid);
Anshuman Khandual8218a302015-07-29 12:40:04 +05302930 if (esid & SLB_ESID_V) {
will schmidtb3b95952007-12-07 08:22:23 +11002931 llp = vsid & SLB_VSID_LLP;
2932 if (vsid & SLB_VSID_B_1T) {
2933 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2934 GET_ESID_1T(esid),
2935 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2936 llp);
2937 } else {
2938 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2939 GET_ESID(esid),
2940 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2941 llp);
2942 }
2943 } else
2944 printf("\n");
2945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 }
2947}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002948#endif
2949
2950#ifdef CONFIG_PPC_STD_MMU_32
2951void dump_segments(void)
2952{
2953 int i;
2954
2955 printf("sr0-15 =");
2956 for (i = 0; i < 16; ++i)
2957 printf(" %x", mfsrin(i));
2958 printf("\n");
2959}
2960#endif
2961
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002962#ifdef CONFIG_44x
2963static void dump_tlb_44x(void)
2964{
2965 int i;
2966
2967 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2968 unsigned long w0,w1,w2;
2969 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2970 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2971 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2972 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2973 if (w0 & PPC44x_TLB_VALID) {
2974 printf("V %08x -> %01x%08x %c%c%c%c%c",
2975 w0 & PPC44x_TLB_EPN_MASK,
2976 w1 & PPC44x_TLB_ERPN_MASK,
2977 w1 & PPC44x_TLB_RPN_MASK,
2978 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2979 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2980 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2981 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2982 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2983 }
2984 printf("\n");
2985 }
2986}
2987#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002988
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002989#ifdef CONFIG_PPC_BOOK3E
2990static void dump_tlb_book3e(void)
2991{
2992 u32 mmucfg, pidmask, lpidmask;
2993 u64 ramask;
2994 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2995 int mmu_version;
2996 static const char *pgsz_names[] = {
2997 " 1K",
2998 " 2K",
2999 " 4K",
3000 " 8K",
3001 " 16K",
3002 " 32K",
3003 " 64K",
3004 "128K",
3005 "256K",
3006 "512K",
3007 " 1M",
3008 " 2M",
3009 " 4M",
3010 " 8M",
3011 " 16M",
3012 " 32M",
3013 " 64M",
3014 "128M",
3015 "256M",
3016 "512M",
3017 " 1G",
3018 " 2G",
3019 " 4G",
3020 " 8G",
3021 " 16G",
3022 " 32G",
3023 " 64G",
3024 "128G",
3025 "256G",
3026 "512G",
3027 " 1T",
3028 " 2T",
3029 };
3030
3031 /* Gather some infos about the MMU */
3032 mmucfg = mfspr(SPRN_MMUCFG);
3033 mmu_version = (mmucfg & 3) + 1;
3034 ntlbs = ((mmucfg >> 2) & 3) + 1;
3035 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3036 lpidsz = (mmucfg >> 24) & 0xf;
3037 rasz = (mmucfg >> 16) & 0x7f;
3038 if ((mmu_version > 1) && (mmucfg & 0x10000))
3039 lrat = 1;
3040 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3041 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3042 pidmask = (1ul << pidsz) - 1;
3043 lpidmask = (1ul << lpidsz) - 1;
3044 ramask = (1ull << rasz) - 1;
3045
3046 for (tlb = 0; tlb < ntlbs; tlb++) {
3047 u32 tlbcfg;
3048 int nent, assoc, new_cc = 1;
3049 printf("TLB %d:\n------\n", tlb);
3050 switch(tlb) {
3051 case 0:
3052 tlbcfg = mfspr(SPRN_TLB0CFG);
3053 break;
3054 case 1:
3055 tlbcfg = mfspr(SPRN_TLB1CFG);
3056 break;
3057 case 2:
3058 tlbcfg = mfspr(SPRN_TLB2CFG);
3059 break;
3060 case 3:
3061 tlbcfg = mfspr(SPRN_TLB3CFG);
3062 break;
3063 default:
3064 printf("Unsupported TLB number !\n");
3065 continue;
3066 }
3067 nent = tlbcfg & 0xfff;
3068 assoc = (tlbcfg >> 24) & 0xff;
3069 for (i = 0; i < nent; i++) {
3070 u32 mas0 = MAS0_TLBSEL(tlb);
3071 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3072 u64 mas2 = 0;
3073 u64 mas7_mas3;
3074 int esel = i, cc = i;
3075
3076 if (assoc != 0) {
3077 cc = i / assoc;
3078 esel = i % assoc;
3079 mas2 = cc * 0x1000;
3080 }
3081
3082 mas0 |= MAS0_ESEL(esel);
3083 mtspr(SPRN_MAS0, mas0);
3084 mtspr(SPRN_MAS1, mas1);
3085 mtspr(SPRN_MAS2, mas2);
3086 asm volatile("tlbre 0,0,0" : : : "memory");
3087 mas1 = mfspr(SPRN_MAS1);
3088 mas2 = mfspr(SPRN_MAS2);
3089 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3090 if (assoc && (i % assoc) == 0)
3091 new_cc = 1;
3092 if (!(mas1 & MAS1_VALID))
3093 continue;
3094 if (assoc == 0)
3095 printf("%04x- ", i);
3096 else if (new_cc)
3097 printf("%04x-%c", cc, 'A' + esel);
3098 else
3099 printf(" |%c", 'A' + esel);
3100 new_cc = 0;
3101 printf(" %016llx %04x %s %c%c AS%c",
3102 mas2 & ~0x3ffull,
3103 (mas1 >> 16) & 0x3fff,
3104 pgsz_names[(mas1 >> 7) & 0x1f],
3105 mas1 & MAS1_IND ? 'I' : ' ',
3106 mas1 & MAS1_IPROT ? 'P' : ' ',
3107 mas1 & MAS1_TS ? '1' : '0');
3108 printf(" %c%c%c%c%c%c%c",
3109 mas2 & MAS2_X0 ? 'a' : ' ',
3110 mas2 & MAS2_X1 ? 'v' : ' ',
3111 mas2 & MAS2_W ? 'w' : ' ',
3112 mas2 & MAS2_I ? 'i' : ' ',
3113 mas2 & MAS2_M ? 'm' : ' ',
3114 mas2 & MAS2_G ? 'g' : ' ',
3115 mas2 & MAS2_E ? 'e' : ' ');
3116 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3117 if (mas1 & MAS1_IND)
3118 printf(" %s\n",
3119 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3120 else
3121 printf(" U%c%c%c S%c%c%c\n",
3122 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3123 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3124 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3125 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3126 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3127 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3128 }
3129 }
3130}
3131#endif /* CONFIG_PPC_BOOK3E */
3132
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003133static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003135 if (enable) {
3136 __debugger = xmon;
3137 __debugger_ipi = xmon_ipi;
3138 __debugger_bpt = xmon_bpt;
3139 __debugger_sstep = xmon_sstep;
3140 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003141 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003142 __debugger_fault_handler = xmon_fault_handler;
3143 } else {
3144 __debugger = NULL;
3145 __debugger_ipi = NULL;
3146 __debugger_bpt = NULL;
3147 __debugger_sstep = NULL;
3148 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003149 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003150 __debugger_fault_handler = NULL;
3151 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003153
3154#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003155static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003156{
3157 /* ensure xmon is enabled */
3158 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003159 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003160}
3161
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003162static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003163 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003164 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003165 .action_msg = "Entering xmon",
3166};
3167
3168static int __init setup_xmon_sysrq(void)
3169{
3170 register_sysrq_key('x', &sysrq_xmon_op);
3171 return 0;
3172}
3173__initcall(setup_xmon_sysrq);
3174#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003175
Olaf Heringf5e6a282007-06-24 16:57:08 +10003176static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10003177
3178static int __init early_parse_xmon(char *p)
3179{
3180 if (!p || strncmp(p, "early", 5) == 0) {
3181 /* just "xmon" is equivalent to "xmon=early" */
3182 xmon_init(1);
3183 xmon_early = 1;
3184 } else if (strncmp(p, "on", 2) == 0)
3185 xmon_init(1);
3186 else if (strncmp(p, "off", 3) == 0)
3187 xmon_off = 1;
3188 else if (strncmp(p, "nobt", 4) == 0)
3189 xmon_no_auto_backtrace = 1;
3190 else
3191 return 1;
3192
3193 return 0;
3194}
3195early_param("xmon", early_parse_xmon);
3196
3197void __init xmon_setup(void)
3198{
3199#ifdef CONFIG_XMON_DEFAULT
3200 if (!xmon_off)
3201 xmon_init(1);
3202#endif
3203 if (xmon_early)
3204 debugger(NULL);
3205}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003206
Arnd Bergmanne0555952006-11-27 19:18:55 +01003207#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003208
3209struct spu_info {
3210 struct spu *spu;
3211 u64 saved_mfc_sr1_RW;
3212 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003213 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003214 u8 stopped_ok;
3215};
3216
3217#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3218
3219static struct spu_info spu_info[XMON_NUM_SPUS];
3220
3221void xmon_register_spus(struct list_head *list)
3222{
3223 struct spu *spu;
3224
3225 list_for_each_entry(spu, list, full_list) {
3226 if (spu->number >= XMON_NUM_SPUS) {
3227 WARN_ON(1);
3228 continue;
3229 }
3230
3231 spu_info[spu->number].spu = spu;
3232 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003233 spu_info[spu->number].dump_addr = (unsigned long)
3234 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003235 }
3236}
3237
3238static void stop_spus(void)
3239{
3240 struct spu *spu;
3241 int i;
3242 u64 tmp;
3243
3244 for (i = 0; i < XMON_NUM_SPUS; i++) {
3245 if (!spu_info[i].spu)
3246 continue;
3247
3248 if (setjmp(bus_error_jmp) == 0) {
3249 catch_memory_errors = 1;
3250 sync();
3251
3252 spu = spu_info[i].spu;
3253
3254 spu_info[i].saved_spu_runcntl_RW =
3255 in_be32(&spu->problem->spu_runcntl_RW);
3256
3257 tmp = spu_mfc_sr1_get(spu);
3258 spu_info[i].saved_mfc_sr1_RW = tmp;
3259
3260 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3261 spu_mfc_sr1_set(spu, tmp);
3262
3263 sync();
3264 __delay(200);
3265
3266 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003267
3268 printf("Stopped spu %.2d (was %s)\n", i,
3269 spu_info[i].saved_spu_runcntl_RW ?
3270 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003271 } else {
3272 catch_memory_errors = 0;
3273 printf("*** Error stopping spu %.2d\n", i);
3274 }
3275 catch_memory_errors = 0;
3276 }
3277}
3278
3279static void restart_spus(void)
3280{
3281 struct spu *spu;
3282 int i;
3283
3284 for (i = 0; i < XMON_NUM_SPUS; i++) {
3285 if (!spu_info[i].spu)
3286 continue;
3287
3288 if (!spu_info[i].stopped_ok) {
3289 printf("*** Error, spu %d was not successfully stopped"
3290 ", not restarting\n", i);
3291 continue;
3292 }
3293
3294 if (setjmp(bus_error_jmp) == 0) {
3295 catch_memory_errors = 1;
3296 sync();
3297
3298 spu = spu_info[i].spu;
3299 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3300 out_be32(&spu->problem->spu_runcntl_RW,
3301 spu_info[i].saved_spu_runcntl_RW);
3302
3303 sync();
3304 __delay(200);
3305
3306 printf("Restarted spu %.2d\n", i);
3307 } else {
3308 catch_memory_errors = 0;
3309 printf("*** Error restarting spu %.2d\n", i);
3310 }
3311 catch_memory_errors = 0;
3312 }
3313}
3314
Michael Ellermana8984972006-10-24 18:31:28 +02003315#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003316#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003317do { \
3318 if (setjmp(bus_error_jmp) == 0) { \
3319 catch_memory_errors = 1; \
3320 sync(); \
3321 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003322 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003323 sync(); \
3324 __delay(200); \
3325 } else { \
3326 catch_memory_errors = 0; \
3327 printf(" %-*s = *** Error reading field.\n", \
3328 DUMP_WIDTH, #field); \
3329 } \
3330 catch_memory_errors = 0; \
3331} while (0)
3332
Michael Ellerman437a0702006-11-23 00:46:39 +01003333#define DUMP_FIELD(obj, format, field) \
3334 DUMP_VALUE(format, field, obj->field)
3335
Michael Ellermana8984972006-10-24 18:31:28 +02003336static void dump_spu_fields(struct spu *spu)
3337{
3338 printf("Dumping spu fields at address %p:\n", spu);
3339
3340 DUMP_FIELD(spu, "0x%x", number);
3341 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003342 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3343 DUMP_FIELD(spu, "0x%p", local_store);
3344 DUMP_FIELD(spu, "0x%lx", ls_size);
3345 DUMP_FIELD(spu, "0x%x", node);
3346 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003347 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003348 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003349 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3350 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003351 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3352 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3353 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3354 DUMP_FIELD(spu, "0x%x", slb_replace);
3355 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003356 DUMP_FIELD(spu, "0x%p", mm);
3357 DUMP_FIELD(spu, "0x%p", ctx);
3358 DUMP_FIELD(spu, "0x%p", rq);
3359 DUMP_FIELD(spu, "0x%p", timestamp);
3360 DUMP_FIELD(spu, "0x%lx", problem_phys);
3361 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003362 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3363 in_be32(&spu->problem->spu_runcntl_RW));
3364 DUMP_VALUE("0x%x", problem->spu_status_R,
3365 in_be32(&spu->problem->spu_status_R));
3366 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3367 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003368 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003369 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003370}
3371
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003372int
3373spu_inst_dump(unsigned long adr, long count, int praddr)
3374{
3375 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3376}
3377
3378static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003379{
3380 unsigned long offset, addr, ls_addr;
3381
3382 if (setjmp(bus_error_jmp) == 0) {
3383 catch_memory_errors = 1;
3384 sync();
3385 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3386 sync();
3387 __delay(200);
3388 } else {
3389 catch_memory_errors = 0;
3390 printf("*** Error: accessing spu info for spu %d\n", num);
3391 return;
3392 }
3393 catch_memory_errors = 0;
3394
3395 if (scanhex(&offset))
3396 addr = ls_addr + offset;
3397 else
3398 addr = spu_info[num].dump_addr;
3399
3400 if (addr >= ls_addr + LS_SIZE) {
3401 printf("*** Error: address outside of local store\n");
3402 return;
3403 }
3404
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003405 switch (subcmd) {
3406 case 'i':
3407 addr += spu_inst_dump(addr, 16, 1);
3408 last_cmd = "sdi\n";
3409 break;
3410 default:
3411 prdump(addr, 64);
3412 addr += 64;
3413 last_cmd = "sd\n";
3414 break;
3415 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003416
3417 spu_info[num].dump_addr = addr;
3418}
3419
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003420static int do_spu_cmd(void)
3421{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003422 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003423 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003424
3425 cmd = inchar();
3426 switch (cmd) {
3427 case 's':
3428 stop_spus();
3429 break;
3430 case 'r':
3431 restart_spus();
3432 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003433 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003434 subcmd = inchar();
3435 if (isxdigit(subcmd) || subcmd == '\n')
3436 termch = subcmd;
3437 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003438 scanhex(&num);
3439 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003440 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003441 return 0;
3442 }
3443
3444 switch (cmd) {
3445 case 'f':
3446 dump_spu_fields(spu_info[num].spu);
3447 break;
3448 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003449 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003450 break;
3451 }
3452
Michael Ellermana8984972006-10-24 18:31:28 +02003453 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003454 default:
3455 return -1;
3456 }
3457
3458 return 0;
3459}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003460#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003461static int do_spu_cmd(void)
3462{
3463 return -1;
3464}
3465#endif