blob: 899288b71145ec228cf030966e7028d159325dc3 [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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-10-28 22:53:37 +100053#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-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
Breno Leitao81175082018-11-08 15:12:42 -020076#ifdef CONFIG_PPC_PSERIES
77static int set_indicator_token = RTAS_UNKNOWN_SERVICE;
78#endif
Anton Blanchard5be34922010-01-12 00:50:14 +000079static unsigned long in_xmon __read_mostly = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
81static unsigned long adrs;
82static int size = 1;
83#define MAX_DUMP (128 * 1024)
84static unsigned long ndump = 64;
85static unsigned long nidump = 16;
86static unsigned long ncsum = 4096;
87static int termch;
88static char tmpstr[128];
89
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static long bus_error_jmp[JMP_BUF_LEN];
91static int catch_memory_errors;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +100092static int catch_spr_faults;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95/* Breakpoint stuff */
96struct bpt {
97 unsigned long address;
98 unsigned int instr[2];
99 atomic_t ref_count;
100 int enabled;
101 unsigned long pad;
102};
103
104/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100105#define BP_CIABR 1
106#define BP_TRAP 2
107#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
109#define NBPTS 256
110static struct bpt bpts[NBPTS];
111static struct bpt dabr;
112static struct bpt *iabr;
113static unsigned bpinstr = 0x7fe00008; /* trap */
114
115#define BP_NUM(bp) ((bp) - bpts + 1)
116
117/* Prototypes */
118static int cmds(struct pt_regs *);
119static int mread(unsigned long, void *, int);
120static int mwrite(unsigned long, void *, int);
121static int handle_fault(struct pt_regs *);
122static void byterev(unsigned char *, int);
123static void memex(void);
124static int bsesc(void);
125static void dump(void);
126static void prdump(unsigned long, long);
127static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000128static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100129
130#ifdef CONFIG_PPC_POWERNV
131static void dump_opal_msglog(void);
132#else
133static inline void dump_opal_msglog(void)
134{
135 printf("Machine is not running OPAL firmware.\n");
136}
137#endif
138
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139static void backtrace(struct pt_regs *);
140static void excprint(struct pt_regs *);
141static void prregs(struct pt_regs *);
142static void memops(int);
143static void memlocate(void);
144static void memzcan(void);
145static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
146int skipbl(void);
147int scanhex(unsigned long *valp);
148static void scannl(void);
149static int hexdigit(int);
150void getstring(char *, int);
151static void flush_input(void);
152static int inchar(void);
153static void take_input(char *);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000154static int read_spr(int, unsigned long *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155static void write_spr(int, unsigned long);
156static void super_regs(void);
157static void remove_bpts(void);
158static void insert_bpts(void);
159static void remove_cpu_bpts(void);
160static void insert_cpu_bpts(void);
161static struct bpt *at_breakpoint(unsigned long pc);
162static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
163static int do_step(struct pt_regs *);
164static void bpt_cmds(void);
165static void cacheflush(void);
166static int cpu_cmd(void);
167static void csum(void);
168static void bootcmds(void);
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000169static void proccall(void);
Douglas Miller6dfb5402015-11-23 09:01:15 -0600170static void show_tasks(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171void dump_segments(void);
172static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200173static void xmon_show_stack(unsigned long sp, unsigned long lr,
174 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175static void xmon_print_symbol(unsigned long address, const char *mid,
176 const char *after);
177static const char *getvecname(unsigned long vec);
178
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200179static int do_spu_cmd(void);
180
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100181#ifdef CONFIG_44x
182static void dump_tlb_44x(void);
183#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000184#ifdef CONFIG_PPC_BOOK3E
185static void dump_tlb_book3e(void);
186#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100187
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000188static int xmon_no_auto_backtrace;
Olaf Hering26c8af52006-09-08 16:29:21 +0200189
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000190#ifdef CONFIG_PPC64
191#define REG "%.16lx"
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000192#else
193#define REG "%.8lx"
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000194#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100196#ifdef __LITTLE_ENDIAN__
197#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
198#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100200#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202static char *help_string = "\
203Commands:\n\
204 b show breakpoints\n\
205 bd set data breakpoint\n\
206 bi set instruction breakpoint\n\
207 bc clear breakpoint\n"
208#ifdef CONFIG_SMP
209 "\
210 c print cpus stopped in xmon\n\
211 c# try to switch to cpu number h (in hex)\n"
212#endif
213 "\
214 C checksum\n\
215 d dump bytes\n\
216 di dump instructions\n\
217 df dump float values\n\
218 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000219 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100220#ifdef CONFIG_PPC_POWERNV
221 "\
222 do dump the OPAL message log\n"
223#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000224#ifdef CONFIG_PPC64
225 "\
226 dp[#] dump paca for current cpu, or cpu #\n\
227 dpa dump paca for all possible cpus\n"
228#endif
229 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100230 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 e print exception information\n\
232 f flush cache\n\
233 la lookup symbol+offset of specified address\n\
234 ls lookup address of specified symbol\n\
235 m examine/change memory\n\
236 mm move a block of memory\n\
237 ms set a block of memory\n\
238 md compare two blocks of memory\n\
239 ml locate a block of memory\n\
240 mz zero a block of memory\n\
241 mi show information about memory allocation\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000242 p call a procedure\n\
Douglas Miller6dfb5402015-11-23 09:01:15 -0600243 P list processes/tasks\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200245 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100246#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200247" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200248 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100249 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900250 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100251 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200252#endif
253" S print special registers\n\
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000254 Sa print all SPRs\n\
255 Sr # read SPR #\n\
256 Sw #v write v to SPR #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100259 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000260#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000261" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000262#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000263" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000264#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100265" u dump TLB\n"
266#endif
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000267" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100268" # n limit output to n lines per page (for dp, dpa, dl)\n"
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000269" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 zh halt\n"
271;
272
273static struct pt_regs *xmon_regs;
274
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000275static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
277 asm volatile("sync; isync");
278}
279
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000280static inline void store_inst(void *p)
281{
282 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
283}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000285static inline void cflush(void *p)
286{
287 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
288}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000290static inline void cinval(void *p)
291{
292 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
293}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530295/**
296 * write_ciabr() - write the CIABR SPR
297 * @ciabr: The value to write.
298 *
299 * This function writes a value to the CIARB register either directly
300 * through mtspr instruction if the kernel is in HV privilege mode or
301 * call a hypervisor function to achieve the same in case the kernel
302 * is in supervisor privilege mode.
303 */
304static void write_ciabr(unsigned long ciabr)
305{
306 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
307 return;
308
309 if (cpu_has_feature(CPU_FTR_HVMODE)) {
310 mtspr(SPRN_CIABR, ciabr);
311 return;
312 }
313 plapr_set_ciabr(ciabr);
314}
315
316/**
317 * set_ciabr() - set the CIABR
318 * @addr: The value to set.
319 *
320 * This function sets the correct privilege value into the the HW
321 * breakpoint address before writing it up in the CIABR register.
322 */
323static void set_ciabr(unsigned long addr)
324{
325 addr &= ~CIABR_PRIV;
326
327 if (cpu_has_feature(CPU_FTR_HVMODE))
328 addr |= CIABR_PRIV_HYPER;
329 else
330 addr |= CIABR_PRIV_SUPER;
331 write_ciabr(addr);
332}
333
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334/*
335 * Disable surveillance (the service processor watchdog function)
336 * while we are in xmon.
337 * XXX we should re-enable it when we leave. :)
338 */
339#define SURVEILLANCE_TOKEN 9000
340
341static inline void disable_surveillance(void)
342{
343#ifdef CONFIG_PPC_PSERIES
344 /* Since this can't be a module, args should end up below 4GB. */
345 static struct rtas_args args;
346
347 /*
348 * At this point we have got all the cpus we can into
349 * xmon, so there is hopefully no other cpu calling RTAS
350 * at the moment, even though we don't take rtas.lock.
351 * If we did try to take rtas.lock there would be a
352 * real possibility of deadlock.
353 */
Breno Leitao81175082018-11-08 15:12:42 -0200354 if (set_indicator_token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100356
Breno Leitao81175082018-11-08 15:12:42 -0200357 rtas_call_unlocked(&args, set_indicator_token, 3, 1, NULL,
358 SURVEILLANCE_TOKEN, 0, 0);
Michael Ellerman08eb1052015-11-24 22:26:09 +1100359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360#endif /* CONFIG_PPC_PSERIES */
361}
362
363#ifdef CONFIG_SMP
364static int xmon_speaker;
365
366static void get_output_lock(void)
367{
368 int me = smp_processor_id() + 0x100;
369 int last_speaker = 0, prev;
370 long timeout;
371
372 if (xmon_speaker == me)
373 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100376 last_speaker = cmpxchg(&xmon_speaker, 0, me);
377 if (last_speaker == 0)
378 return;
379
Michael Ellerman15075892013-12-23 23:46:05 +1100380 /*
381 * Wait a full second for the lock, we might be on a slow
382 * console, but check every 100us.
383 */
384 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100386 if (--timeout > 0) {
387 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100389 }
390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 /* hostile takeover */
392 prev = cmpxchg(&xmon_speaker, last_speaker, me);
393 if (prev == last_speaker)
394 return;
395 break;
396 }
397 }
398}
399
400static void release_output_lock(void)
401{
402 xmon_speaker = 0;
403}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000404
405int cpus_are_in_xmon(void)
406{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000407 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000408}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409#endif
410
Josh Boyerdaf8f402009-09-23 03:51:04 +0000411static inline int unrecoverable_excp(struct pt_regs *regs)
412{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000413#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000414 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000415 return 0;
416#else
417 return ((regs->msr & MSR_RI) == 0);
418#endif
419}
420
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000421static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422{
423 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 struct bpt *bp;
425 long recurse_jmp[JMP_BUF_LEN];
426 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100427 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428#ifdef CONFIG_SMP
429 int cpu;
430 int secondary;
431 unsigned long timeout;
432#endif
433
Anton Blanchardf13659e2007-03-21 01:48:34 +1100434 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000435 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437 bp = in_breakpoint_table(regs->nip, &offset);
438 if (bp != NULL) {
439 regs->nip = bp->address + offset;
440 atomic_dec(&bp->ref_count);
441 }
442
443 remove_cpu_bpts();
444
445#ifdef CONFIG_SMP
446 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000447 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000448 /*
449 * We catch SPR read/write faults here because the 0x700, 0xf60
450 * etc. handlers don't call debugger_fault_handler().
451 */
452 if (catch_spr_faults)
453 longjmp(bus_error_jmp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 get_output_lock();
455 excprint(regs);
456 printf("cpu 0x%x: Exception %lx %s in xmon, "
457 "returning to main loop\n",
458 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000459 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 longjmp(xmon_fault_jmp[cpu], 1);
461 }
462
463 if (setjmp(recurse_jmp) != 0) {
464 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000465 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 printf("xmon: WARNING: bad recursive fault "
467 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000468 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 goto waiting;
470 }
471 secondary = !(xmon_taken && cpu == xmon_owner);
472 goto cmdloop;
473 }
474
475 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
477 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000478 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000480 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 fromipi = 0;
482
483 if (!fromipi) {
484 get_output_lock();
485 excprint(regs);
486 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000487 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 cpu, BP_NUM(bp));
489 xmon_print_symbol(regs->nip, " ", ")\n");
490 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000491 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 printf("WARNING: exception is not recoverable, "
493 "can't continue\n");
494 release_output_lock();
495 }
496
Michael Ellermand2b496e2013-12-23 23:46:06 +1100497 cpumask_set_cpu(cpu, &cpus_in_xmon);
498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 waiting:
500 secondary = 1;
501 while (secondary && !xmon_gate) {
502 if (in_xmon == 0) {
503 if (fromipi)
504 goto leave;
505 secondary = test_and_set_bit(0, &in_xmon);
506 }
507 barrier();
508 }
509
510 if (!secondary && !xmon_gate) {
511 /* we are the first cpu to come in */
512 /* interrupt other cpu(s) */
513 int ncpus = num_online_cpus();
514
515 xmon_owner = cpu;
516 mb();
517 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000518 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 /* wait for other cpus to come in */
520 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000521 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 break;
523 barrier();
524 }
525 }
526 remove_bpts();
527 disable_surveillance();
528 /* for breakpoint or single step, print the current instr. */
529 if (bp || TRAP(regs) == 0xd00)
530 ppc_inst_dump(regs->nip, 1, 0);
531 printf("enter ? for help\n");
532 mb();
533 xmon_gate = 1;
534 barrier();
535 }
536
537 cmdloop:
538 while (in_xmon) {
539 if (secondary) {
540 if (cpu == xmon_owner) {
541 if (!test_and_set_bit(0, &xmon_taken)) {
542 secondary = 0;
543 continue;
544 }
545 /* missed it */
546 while (cpu == xmon_owner)
547 barrier();
548 }
549 barrier();
550 } else {
551 cmd = cmds(regs);
552 if (cmd != 0) {
553 /* exiting xmon */
554 insert_bpts();
555 xmon_gate = 0;
556 wmb();
557 in_xmon = 0;
558 break;
559 }
560 /* have switched to some other cpu */
561 secondary = 1;
562 }
563 }
564 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000565 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567#else
568 /* UP is simple... */
569 if (in_xmon) {
570 printf("Exception %lx %s in xmon, returning to main loop\n",
571 regs->trap, getvecname(TRAP(regs)));
572 longjmp(xmon_fault_jmp[0], 1);
573 }
574 if (setjmp(recurse_jmp) == 0) {
575 xmon_fault_jmp[0] = recurse_jmp;
576 in_xmon = 1;
577
578 excprint(regs);
579 bp = at_breakpoint(regs->nip);
580 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000581 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 xmon_print_symbol(regs->nip, " ", ")\n");
583 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000584 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 printf("WARNING: exception is not recoverable, "
586 "can't continue\n");
587 remove_bpts();
588 disable_surveillance();
589 /* for breakpoint or single step, print the current instr. */
590 if (bp || TRAP(regs) == 0xd00)
591 ppc_inst_dump(regs->nip, 1, 0);
592 printf("enter ? for help\n");
593 }
594
595 cmd = cmds(regs);
596
597 insert_bpts();
598 in_xmon = 0;
599#endif
600
Josh Boyercdd39042009-10-05 04:46:05 +0000601#ifdef CONFIG_BOOKE
602 if (regs->msr & MSR_DE) {
603 bp = at_breakpoint(regs->nip);
604 if (bp != NULL) {
605 regs->nip = (unsigned long) &bp->instr[0];
606 atomic_inc(&bp->ref_count);
607 }
608 }
609#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000610 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 bp = at_breakpoint(regs->nip);
612 if (bp != NULL) {
613 int stepped = emulate_step(regs, bp->instr[0]);
614 if (stepped == 0) {
615 regs->nip = (unsigned long) &bp->instr[0];
616 atomic_inc(&bp->ref_count);
617 } else if (stepped < 0) {
618 printf("Couldn't single-step %s instruction\n",
619 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
620 }
621 }
622 }
Josh Boyercdd39042009-10-05 04:46:05 +0000623#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 insert_cpu_bpts();
625
Anton Blancharda71d64b2014-08-05 14:55:00 +1000626 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100627 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000629 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630}
631
632int xmon(struct pt_regs *excp)
633{
634 struct pt_regs regs;
635
636 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000637 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 excp = &regs;
639 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200640
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 return xmon_core(excp, 0);
642}
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000643EXPORT_SYMBOL(xmon);
644
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000645irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000646{
647 unsigned long flags;
648 local_irq_save(flags);
649 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000650 xmon(get_irq_regs());
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000651 local_irq_restore(flags);
652 return IRQ_HANDLED;
653}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000655static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
657 struct bpt *bp;
658 unsigned long offset;
659
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000660 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 return 0;
662
663 /* Are we at the trap at bp->instr[1] for some bp? */
664 bp = in_breakpoint_table(regs->nip, &offset);
665 if (bp != NULL && offset == 4) {
666 regs->nip = bp->address + 4;
667 atomic_dec(&bp->ref_count);
668 return 1;
669 }
670
671 /* Are we at a breakpoint? */
672 bp = at_breakpoint(regs->nip);
673 if (!bp)
674 return 0;
675
676 xmon_core(regs, 0);
677
678 return 1;
679}
680
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000681static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
683 if (user_mode(regs))
684 return 0;
685 xmon_core(regs, 0);
686 return 1;
687}
688
Michael Neuling9422de32012-12-20 14:06:44 +0000689static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000691 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000693 if (dabr.enabled == 0)
694 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 xmon_core(regs, 0);
696 return 1;
697}
698
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000699static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000701 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000703 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return 0;
705 xmon_core(regs, 0);
706 return 1;
707}
708
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000709static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{
711#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000712 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 xmon_core(regs, 1);
714#endif
715 return 0;
716}
717
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000718static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719{
720 struct bpt *bp;
721 unsigned long offset;
722
723 if (in_xmon && catch_memory_errors)
724 handle_fault(regs); /* doesn't return */
725
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000726 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 bp = in_breakpoint_table(regs->nip, &offset);
728 if (bp != NULL) {
729 regs->nip = bp->address + offset;
730 atomic_dec(&bp->ref_count);
731 }
732 }
733
734 return 0;
735}
736
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737static struct bpt *at_breakpoint(unsigned long pc)
738{
739 int i;
740 struct bpt *bp;
741
742 bp = bpts;
743 for (i = 0; i < NBPTS; ++i, ++bp)
744 if (bp->enabled && pc == bp->address)
745 return bp;
746 return NULL;
747}
748
749static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
750{
751 unsigned long off;
752
753 off = nip - (unsigned long) bpts;
754 if (off >= sizeof(bpts))
755 return NULL;
756 off %= sizeof(struct bpt);
757 if (off != offsetof(struct bpt, instr[0])
758 && off != offsetof(struct bpt, instr[1]))
759 return NULL;
760 *offp = off - offsetof(struct bpt, instr[0]);
761 return (struct bpt *) (nip - off);
762}
763
764static struct bpt *new_breakpoint(unsigned long a)
765{
766 struct bpt *bp;
767
768 a &= ~3UL;
769 bp = at_breakpoint(a);
770 if (bp)
771 return bp;
772
773 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
774 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
775 bp->address = a;
776 bp->instr[1] = bpinstr;
777 store_inst(&bp->instr[1]);
778 return bp;
779 }
780 }
781
782 printf("Sorry, no free breakpoints. Please clear one first.\n");
783 return NULL;
784}
785
786static void insert_bpts(void)
787{
788 int i;
789 struct bpt *bp;
790
791 bp = bpts;
792 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100793 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 continue;
795 if (mread(bp->address, &bp->instr[0], 4) != 4) {
796 printf("Couldn't read instruction at %lx, "
797 "disabling breakpoint there\n", bp->address);
798 bp->enabled = 0;
799 continue;
800 }
801 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
802 printf("Breakpoint at %lx is on an mtmsrd or rfid "
803 "instruction, disabling it\n", bp->address);
804 bp->enabled = 0;
805 continue;
806 }
807 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100808 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 continue;
810 if (mwrite(bp->address, &bpinstr, 4) != 4) {
811 printf("Couldn't write instruction at %lx, "
812 "disabling breakpoint there\n", bp->address);
813 bp->enabled &= ~BP_TRAP;
814 continue;
815 }
816 store_inst((void *)bp->address);
817 }
818}
819
820static void insert_cpu_bpts(void)
821{
Michael Neuling9422de32012-12-20 14:06:44 +0000822 struct arch_hw_breakpoint brk;
823
824 if (dabr.enabled) {
825 brk.address = dabr.address;
826 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
827 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400828 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000829 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530830
831 if (iabr)
832 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833}
834
835static void remove_bpts(void)
836{
837 int i;
838 struct bpt *bp;
839 unsigned instr;
840
841 bp = bpts;
842 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100843 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 continue;
845 if (mread(bp->address, &instr, 4) == 4
846 && instr == bpinstr
847 && mwrite(bp->address, &bp->instr, 4) != 4)
848 printf("Couldn't remove breakpoint at %lx\n",
849 bp->address);
850 else
851 store_inst((void *)bp->address);
852 }
853}
854
855static void remove_cpu_bpts(void)
856{
Michael Neuling9422de32012-12-20 14:06:44 +0000857 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530858 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859}
860
Sam bobroff958b7c82015-10-08 11:50:23 +1100861static void set_lpp_cmd(void)
862{
863 unsigned long lpp;
864
865 if (!scanhex(&lpp)) {
866 printf("Invalid number.\n");
867 lpp = 0;
868 }
869 xmon_set_pagination_lpp(lpp);
870}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871/* Command interpreting routine */
872static char *last_cmd;
873
874static int
875cmds(struct pt_regs *excp)
876{
877 int cmd = 0;
878
879 last_cmd = NULL;
880 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200881
882 if (!xmon_no_auto_backtrace) {
883 xmon_no_auto_backtrace = 1;
884 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
885 }
886
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 for(;;) {
888#ifdef CONFIG_SMP
889 printf("%x:", smp_processor_id());
890#endif /* CONFIG_SMP */
891 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 flush_input();
893 termch = 0;
894 cmd = skipbl();
895 if( cmd == '\n' ) {
896 if (last_cmd == NULL)
897 continue;
898 take_input(last_cmd);
899 last_cmd = NULL;
900 cmd = inchar();
901 }
902 switch (cmd) {
903 case 'm':
904 cmd = inchar();
905 switch (cmd) {
906 case 'm':
907 case 's':
908 case 'd':
909 memops(cmd);
910 break;
911 case 'l':
912 memlocate();
913 break;
914 case 'z':
915 memzcan();
916 break;
917 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700918 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 break;
920 default:
921 termch = cmd;
922 memex();
923 }
924 break;
925 case 'd':
926 dump();
927 break;
928 case 'l':
929 symbol_lookup();
930 break;
931 case 'r':
932 prregs(excp); /* print regs */
933 break;
934 case 'e':
935 excprint(excp);
936 break;
937 case 'S':
938 super_regs();
939 break;
940 case 't':
941 backtrace(excp);
942 break;
943 case 'f':
944 cacheflush();
945 break;
946 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200947 if (do_spu_cmd() == 0)
948 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 if (do_step(excp))
950 return cmd;
951 break;
952 case 'x':
953 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100954 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100956 printf(" <no input ...>\n");
957 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 return cmd;
959 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000960 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 break;
Sam bobroff958b7c82015-10-08 11:50:23 +1100962 case '#':
963 set_lpp_cmd();
964 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 case 'b':
966 bpt_cmds();
967 break;
968 case 'C':
969 csum();
970 break;
971 case 'c':
972 if (cpu_cmd())
973 return 0;
974 break;
975 case 'z':
976 bootcmds();
977 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000978 case 'p':
979 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -0600981 case 'P':
982 show_tasks();
983 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000984#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 case 'u':
986 dump_segments();
987 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +1100988#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100989 case 'u':
990 dump_tlb_44x();
991 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000992#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000993 case 'u':
994 dump_tlb_book3e();
995 break;
996#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 default:
998 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000999 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 if (' ' < cmd && cmd <= '~')
1001 putchar(cmd);
1002 else
1003 printf("\\x%x", cmd);
1004 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +00001005 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 printf(" (type ? for help)\n");
1007 break;
1008 }
1009 }
1010}
1011
Josh Boyercdd39042009-10-05 04:46:05 +00001012#ifdef CONFIG_BOOKE
1013static int do_step(struct pt_regs *regs)
1014{
1015 regs->msr |= MSR_DE;
1016 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1017 return 1;
1018}
1019#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020/*
1021 * Step a single instruction.
1022 * Some instructions we emulate, others we execute with MSR_SE set.
1023 */
1024static int do_step(struct pt_regs *regs)
1025{
1026 unsigned int instr;
1027 int stepped;
1028
1029 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001030 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 if (mread(regs->nip, &instr, 4) == 4) {
1032 stepped = emulate_step(regs, instr);
1033 if (stepped < 0) {
1034 printf("Couldn't single-step %s instruction\n",
1035 (IS_RFID(instr)? "rfid": "mtmsrd"));
1036 return 0;
1037 }
1038 if (stepped > 0) {
1039 regs->trap = 0xd00 | (regs->trap & 1);
1040 printf("stepped to ");
1041 xmon_print_symbol(regs->nip, " ", "\n");
1042 ppc_inst_dump(regs->nip, 1, 0);
1043 return 0;
1044 }
1045 }
1046 }
1047 regs->msr |= MSR_SE;
1048 return 1;
1049}
Josh Boyercdd39042009-10-05 04:46:05 +00001050#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
1052static void bootcmds(void)
1053{
1054 int cmd;
1055
1056 cmd = inchar();
1057 if (cmd == 'r')
1058 ppc_md.restart(NULL);
1059 else if (cmd == 'h')
1060 ppc_md.halt();
1061 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001062 if (pm_power_off)
1063 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064}
1065
1066static int cpu_cmd(void)
1067{
1068#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001069 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
1072 if (!scanhex(&cpu)) {
1073 /* print cpus waiting or in xmon */
1074 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001075 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001076 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001077 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001078 if (cpu == last_cpu + 1) {
1079 last_cpu = cpu;
1080 } else {
1081 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001082 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001083 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001084 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001085 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 }
1087 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001088 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001089 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 printf("\n");
1091 return 0;
1092 }
1093 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001094 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 printf("cpu 0x%x isn't in xmon\n", cpu);
1096 return 0;
1097 }
1098 xmon_taken = 0;
1099 mb();
1100 xmon_owner = cpu;
1101 timeout = 10000000;
1102 while (!xmon_taken) {
1103 if (--timeout == 0) {
1104 if (test_and_set_bit(0, &xmon_taken))
1105 break;
1106 /* take control back */
1107 mb();
1108 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001109 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 return 0;
1111 }
1112 barrier();
1113 }
1114 return 1;
1115#else
1116 return 0;
1117#endif /* CONFIG_SMP */
1118}
1119
1120static unsigned short fcstab[256] = {
1121 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1122 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1123 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1124 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1125 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1126 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1127 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1128 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1129 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1130 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1131 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1132 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1133 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1134 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1135 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1136 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1137 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1138 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1139 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1140 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1141 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1142 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1143 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1144 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1145 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1146 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1147 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1148 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1149 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1150 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1151 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1152 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1153};
1154
1155#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1156
1157static void
1158csum(void)
1159{
1160 unsigned int i;
1161 unsigned short fcs;
1162 unsigned char v;
1163
1164 if (!scanhex(&adrs))
1165 return;
1166 if (!scanhex(&ncsum))
1167 return;
1168 fcs = 0xffff;
1169 for (i = 0; i < ncsum; ++i) {
1170 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001171 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 break;
1173 }
1174 fcs = FCS(fcs, v);
1175 }
1176 printf("%x\n", fcs);
1177}
1178
1179/*
1180 * Check if this is a suitable place to put a breakpoint.
1181 */
1182static long check_bp_loc(unsigned long addr)
1183{
1184 unsigned int instr;
1185
1186 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001187 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 printf("Breakpoints may only be placed at kernel addresses\n");
1189 return 0;
1190 }
1191 if (!mread(addr, &instr, sizeof(instr))) {
1192 printf("Can't read instruction at address %lx\n", addr);
1193 return 0;
1194 }
1195 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1196 printf("Breakpoints may not be placed on mtmsrd or rfid "
1197 "instructions\n");
1198 return 0;
1199 }
1200 return 1;
1201}
1202
Michael Ellermane3bc8042012-08-23 22:09:13 +00001203static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 "Breakpoint command usage:\n"
1205 "b show breakpoints\n"
1206 "b <addr> [cnt] set breakpoint at given instr addr\n"
1207 "bc clear all breakpoints\n"
1208 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301209 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 "bd <addr> [cnt] set hardware data breakpoint\n"
1211 "";
1212
1213static void
1214bpt_cmds(void)
1215{
1216 int cmd;
1217 unsigned long a;
1218 int mode, i;
1219 struct bpt *bp;
1220 const char badaddr[] = "Only kernel addresses are permitted "
1221 "for breakpoints\n";
1222
1223 cmd = inchar();
1224 switch (cmd) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001225#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 case 'd': /* bd - hardware data breakpoint */
1227 mode = 7;
1228 cmd = inchar();
1229 if (cmd == 'r')
1230 mode = 5;
1231 else if (cmd == 'w')
1232 mode = 6;
1233 else
1234 termch = cmd;
1235 dabr.address = 0;
1236 dabr.enabled = 0;
1237 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001238 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 printf(badaddr);
1240 break;
1241 }
Michael Neuling9422de32012-12-20 14:06:44 +00001242 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 dabr.enabled = mode | BP_DABR;
1244 }
1245 break;
1246
1247 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301248 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 printf("Hardware instruction breakpoint "
1250 "not supported on this cpu\n");
1251 break;
1252 }
1253 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001254 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 iabr = NULL;
1256 }
1257 if (!scanhex(&a))
1258 break;
1259 if (!check_bp_loc(a))
1260 break;
1261 bp = new_breakpoint(a);
1262 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001263 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 iabr = bp;
1265 }
1266 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001267#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
1269 case 'c':
1270 if (!scanhex(&a)) {
1271 /* clear all breakpoints */
1272 for (i = 0; i < NBPTS; ++i)
1273 bpts[i].enabled = 0;
1274 iabr = NULL;
1275 dabr.enabled = 0;
1276 printf("All breakpoints cleared\n");
1277 break;
1278 }
1279
1280 if (a <= NBPTS && a >= 1) {
1281 /* assume a breakpoint number */
1282 bp = &bpts[a-1]; /* bp nums are 1 based */
1283 } else {
1284 /* assume a breakpoint address */
1285 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001286 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001287 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 break;
1289 }
1290 }
1291
Michael Ellerman736256e2014-05-26 21:02:14 +10001292 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 xmon_print_symbol(bp->address, " ", ")\n");
1294 bp->enabled = 0;
1295 break;
1296
1297 default:
1298 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001299 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if (cmd == '?') {
1301 printf(breakpoint_help_string);
1302 break;
1303 }
1304 termch = cmd;
1305 if (!scanhex(&a)) {
1306 /* print all breakpoints */
1307 printf(" type address\n");
1308 if (dabr.enabled) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001309 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 if (dabr.enabled & 1)
1311 printf("r");
1312 if (dabr.enabled & 2)
1313 printf("w");
1314 printf("]\n");
1315 }
1316 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1317 if (!bp->enabled)
1318 continue;
1319 printf("%2x %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001320 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 xmon_print_symbol(bp->address, " ", "\n");
1322 }
1323 break;
1324 }
1325
1326 if (!check_bp_loc(a))
1327 break;
1328 bp = new_breakpoint(a);
1329 if (bp != NULL)
1330 bp->enabled |= BP_TRAP;
1331 break;
1332 }
1333}
1334
1335/* Very cheap human name for vector lookup. */
1336static
1337const char *getvecname(unsigned long vec)
1338{
1339 char *ret;
1340
1341 switch (vec) {
1342 case 0x100: ret = "(System Reset)"; break;
1343 case 0x200: ret = "(Machine Check)"; break;
1344 case 0x300: ret = "(Data Access)"; break;
1345 case 0x380: ret = "(Data SLB Access)"; break;
1346 case 0x400: ret = "(Instruction Access)"; break;
1347 case 0x480: ret = "(Instruction SLB Access)"; break;
1348 case 0x500: ret = "(Hardware Interrupt)"; break;
1349 case 0x600: ret = "(Alignment)"; break;
1350 case 0x700: ret = "(Program Check)"; break;
1351 case 0x800: ret = "(FPU Unavailable)"; break;
1352 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001353 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1354 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 case 0xc00: ret = "(System Call)"; break;
1356 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001357 case 0xe40: ret = "(Emulation Assist)"; break;
1358 case 0xe60: ret = "(HMI)"; break;
1359 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 case 0xf00: ret = "(Performance Monitor)"; break;
1361 case 0xf20: ret = "(Altivec Unavailable)"; break;
1362 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001363 case 0x1500: ret = "(Denormalisation)"; break;
1364 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 default: ret = "";
1366 }
1367 return ret;
1368}
1369
1370static void get_function_bounds(unsigned long pc, unsigned long *startp,
1371 unsigned long *endp)
1372{
1373 unsigned long size, offset;
1374 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375
1376 *startp = *endp = 0;
1377 if (pc == 0)
1378 return;
1379 if (setjmp(bus_error_jmp) == 0) {
1380 catch_memory_errors = 1;
1381 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001382 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 if (name != NULL) {
1384 *startp = pc - offset;
1385 *endp = pc - offset + size;
1386 }
1387 sync();
1388 }
1389 catch_memory_errors = 0;
1390}
1391
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001392#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1393#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1394
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395static void xmon_show_stack(unsigned long sp, unsigned long lr,
1396 unsigned long pc)
1397{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001398 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 unsigned long ip;
1400 unsigned long newsp;
1401 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 struct pt_regs regs;
1403
Michael Ellerman0104cd62012-10-09 04:20:36 +00001404 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 if (sp < PAGE_OFFSET) {
1406 if (sp != 0)
1407 printf("SP (%lx) is in userspace\n", sp);
1408 break;
1409 }
1410
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001411 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 || !mread(sp, &newsp, sizeof(unsigned long))) {
1413 printf("Couldn't read stack frame at %lx\n", sp);
1414 break;
1415 }
1416
1417 /*
1418 * For the first stack frame, try to work out if
1419 * LR and/or the saved LR value in the bottommost
1420 * stack frame are valid.
1421 */
1422 if ((pc | lr) != 0) {
1423 unsigned long fnstart, fnend;
1424 unsigned long nextip;
1425 int printip = 1;
1426
1427 get_function_bounds(pc, &fnstart, &fnend);
1428 nextip = 0;
1429 if (newsp > sp)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001430 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 sizeof(unsigned long));
1432 if (lr == ip) {
1433 if (lr < PAGE_OFFSET
1434 || (fnstart <= lr && lr < fnend))
1435 printip = 0;
1436 } else if (lr == nextip) {
1437 printip = 0;
1438 } else if (lr >= PAGE_OFFSET
1439 && !(fnstart <= lr && lr < fnend)) {
1440 printf("[link register ] ");
1441 xmon_print_symbol(lr, " ", "\n");
1442 }
1443 if (printip) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001444 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 xmon_print_symbol(ip, " ", " (unreliable)\n");
1446 }
1447 pc = lr = 0;
1448
1449 } else {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001450 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 xmon_print_symbol(ip, " ", "\n");
1452 }
1453
1454 /* Look for "regshere" marker to see if this is
1455 an exception frame. */
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001456 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001457 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001458 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 != sizeof(regs)) {
1460 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001461 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 break;
1463 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001464 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 getvecname(TRAP(&regs)));
1466 pc = regs.nip;
1467 lr = regs.link;
1468 xmon_print_symbol(pc, " ", "\n");
1469 }
1470
1471 if (newsp == 0)
1472 break;
1473
1474 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476}
1477
1478static void backtrace(struct pt_regs *excp)
1479{
1480 unsigned long sp;
1481
1482 if (scanhex(&sp))
1483 xmon_show_stack(sp, 0, 0);
1484 else
1485 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1486 scannl();
1487}
1488
1489static void print_bug_trap(struct pt_regs *regs)
1490{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001491#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001492 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 unsigned long addr;
1494
1495 if (regs->msr & MSR_PR)
1496 return; /* not in kernel */
1497 addr = regs->nip; /* address of trap instruction */
1498 if (addr < PAGE_OFFSET)
1499 return;
1500 bug = find_bug(regs->nip);
1501 if (bug == NULL)
1502 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001503 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 return;
1505
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001506#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001507 printf("kernel BUG at %s:%u!\n",
1508 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001509#else
1510 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1511#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001512#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513}
1514
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001515static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516{
1517 unsigned long trap;
1518
1519#ifdef CONFIG_SMP
1520 printf("cpu 0x%x: ", smp_processor_id());
1521#endif /* CONFIG_SMP */
1522
1523 trap = TRAP(fp);
1524 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1525 printf(" pc: ");
1526 xmon_print_symbol(fp->nip, ": ", "\n");
1527
1528 printf(" lr: ", fp->link);
1529 xmon_print_symbol(fp->link, ": ", "\n");
1530
1531 printf(" sp: %lx\n", fp->gpr[1]);
1532 printf(" msr: %lx\n", fp->msr);
1533
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001534 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 printf(" dar: %lx\n", fp->dar);
1536 if (trap != 0x380)
1537 printf(" dsisr: %lx\n", fp->dsisr);
1538 }
1539
1540 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001541#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001542 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1543 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001544#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 if (current) {
1546 printf(" pid = %ld, comm = %s\n",
1547 current->pid, current->comm);
1548 }
1549
1550 if (trap == 0x700)
1551 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001552
1553 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554}
1555
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001556static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001558 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 unsigned long base;
1560 struct pt_regs regs;
1561
1562 if (scanhex(&base)) {
1563 if (setjmp(bus_error_jmp) == 0) {
1564 catch_memory_errors = 1;
1565 sync();
1566 regs = *(struct pt_regs *)base;
1567 sync();
1568 __delay(200);
1569 } else {
1570 catch_memory_errors = 0;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001571 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 base);
1573 return;
1574 }
1575 catch_memory_errors = 0;
1576 fp = &regs;
1577 }
1578
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001579#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 if (FULL_REGS(fp)) {
1581 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001582 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1584 } else {
1585 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001586 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1588 }
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001589#else
1590 for (n = 0; n < 32; ++n) {
1591 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1592 (n & 3) == 3? "\n": " ");
1593 if (n == 12 && !FULL_REGS(fp)) {
1594 printf("\n");
1595 break;
1596 }
1597 }
1598#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 printf("pc = ");
1600 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001601 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1602 printf("cfar= ");
1603 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1604 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 printf("lr = ");
1606 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001607 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1608 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001610 trap = TRAP(fp);
1611 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1612 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613}
1614
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001615static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616{
1617 int cmd;
1618 unsigned long nflush;
1619
1620 cmd = inchar();
1621 if (cmd != 'i')
1622 termch = cmd;
1623 scanhex((void *)&adrs);
1624 if (termch != '\n')
1625 termch = 0;
1626 nflush = 1;
1627 scanhex(&nflush);
1628 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1629 if (setjmp(bus_error_jmp) == 0) {
1630 catch_memory_errors = 1;
1631 sync();
1632
1633 if (cmd != 'i') {
1634 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1635 cflush((void *) adrs);
1636 } else {
1637 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1638 cinval((void *) adrs);
1639 }
1640 sync();
1641 /* wait a little while to see if we get a machine check */
1642 __delay(200);
1643 }
1644 catch_memory_errors = 0;
1645}
1646
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001647extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1648extern void xmon_mtspr(int spr, unsigned long value);
1649
1650static int
1651read_spr(int n, unsigned long *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 unsigned long ret = -1UL;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001654 int ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
1656 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001657 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 sync();
1659
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001660 ret = xmon_mfspr(n, *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
1662 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001663 *vp = ret;
1664 ok = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001666 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001668 return ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669}
1670
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001671static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672write_spr(int n, unsigned long val)
1673{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001675 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 sync();
1677
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001678 xmon_mtspr(n, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679
1680 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001681 } else {
1682 printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001684 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685}
1686
Michael Ellerman18461932016-07-07 22:54:29 +10001687static void dump_206_sprs(void)
1688{
1689#ifdef CONFIG_PPC64
1690 if (!cpu_has_feature(CPU_FTR_ARCH_206))
1691 return;
1692
1693 /* Actually some of these pre-date 2.06, but whatevs */
1694
1695 printf("srr0 = %.16x srr1 = %.16x dsisr = %.8x\n",
1696 mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
1697 printf("dscr = %.16x ppr = %.16x pir = %.8x\n",
1698 mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
1699
1700 if (!(mfmsr() & MSR_HV))
1701 return;
1702
1703 printf("sdr1 = %.16x hdar = %.16x hdsisr = %.8x\n",
1704 mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
1705 printf("hsrr0 = %.16x hsrr1 = %.16x hdec = %.8x\n",
1706 mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
1707 printf("lpcr = %.16x pcr = %.16x lpidr = %.8x\n",
1708 mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
1709 printf("hsprg0 = %.16x hsprg1 = %.16x\n",
1710 mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1));
1711 printf("dabr = %.16x dabrx = %.16x\n",
1712 mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
1713#endif
1714}
1715
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001716static void dump_207_sprs(void)
1717{
1718#ifdef CONFIG_PPC64
1719 unsigned long msr;
1720
1721 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
1722 return;
1723
1724 printf("dpdes = %.16x tir = %.16x cir = %.8x\n",
1725 mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
1726
1727 printf("fscr = %.16x tar = %.16x pspb = %.8x\n",
1728 mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
1729
1730 msr = mfmsr();
1731 if (msr & MSR_TM) {
1732 /* Only if TM has been enabled in the kernel */
1733 printf("tfhar = %.16x tfiar = %.16x texasr = %.16x\n",
1734 mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
1735 mfspr(SPRN_TEXASR));
1736 }
1737
1738 printf("mmcr0 = %.16x mmcr1 = %.16x mmcr2 = %.16x\n",
1739 mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
1740 printf("pmc1 = %.8x pmc2 = %.8x pmc3 = %.8x pmc4 = %.8x\n",
1741 mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
1742 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
1743 printf("mmcra = %.16x siar = %.16x pmc5 = %.8x\n",
1744 mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
1745 printf("sdar = %.16x sier = %.16x pmc6 = %.8x\n",
1746 mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
1747 printf("ebbhr = %.16x ebbrr = %.16x bescr = %.16x\n",
1748 mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
1749
1750 if (!(msr & MSR_HV))
1751 return;
1752
1753 printf("hfscr = %.16x dhdes = %.16x rpr = %.16x\n",
1754 mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
1755 printf("dawr = %.16x dawrx = %.16x ciabr = %.16x\n",
1756 mfspr(SPRN_DAWR), mfspr(SPRN_DAWRX), mfspr(SPRN_CIABR));
1757#endif
1758}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001760static void dump_one_spr(int spr, bool show_unimplemented)
1761{
1762 unsigned long val;
1763
1764 val = 0xdeadbeef;
1765 if (!read_spr(spr, &val)) {
1766 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1767 return;
1768 }
1769
1770 if (val == 0xdeadbeef) {
1771 /* Looks like read was a nop, confirm */
1772 val = 0x0badcafe;
1773 if (!read_spr(spr, &val)) {
1774 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1775 return;
1776 }
1777
1778 if (val == 0x0badcafe) {
1779 if (show_unimplemented)
1780 printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
1781 return;
1782 }
1783 }
1784
1785 printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
1786}
1787
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001788static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789{
Michael Ellerman13629da2016-07-07 22:54:27 +10001790 static unsigned long regno;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 int cmd;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001792 int spr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
1794 cmd = skipbl();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001795
1796 switch (cmd) {
1797 case '\n': {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001798 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 asm("mr %0,1" : "=r" (sp) :);
1800 asm("mr %0,2" : "=r" (toc) :);
1801
Michael Ellerman56346ad2016-07-07 22:54:28 +10001802 printf("msr = "REG" sprg0 = "REG"\n",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001803 mfmsr(), mfspr(SPRN_SPRG0));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001804 printf("pvr = "REG" sprg1 = "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001805 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001806 printf("dec = "REG" sprg2 = "REG"\n",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001807 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001808 printf("sp = "REG" sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
1809 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
1810
Michael Ellerman18461932016-07-07 22:54:29 +10001811 dump_206_sprs();
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001812 dump_207_sprs();
Michael Ellerman18461932016-07-07 22:54:29 +10001813
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 return;
1815 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001816 case 'w': {
1817 unsigned long val;
1818 scanhex(&regno);
1819 val = 0;
1820 read_spr(regno, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 scanhex(&val);
1822 write_spr(regno, val);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001823 dump_one_spr(regno, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001826 case 'r':
1827 scanhex(&regno);
1828 dump_one_spr(regno, true);
1829 break;
1830 case 'a':
1831 /* dump ALL SPRs */
1832 for (spr = 1; spr < 1024; ++spr)
1833 dump_one_spr(spr, false);
1834 break;
1835 }
1836
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 scannl();
1838}
1839
1840/*
1841 * Stuff for reading and writing memory safely
1842 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001843static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844mread(unsigned long adrs, void *buf, int size)
1845{
1846 volatile int n;
1847 char *p, *q;
1848
1849 n = 0;
1850 if (setjmp(bus_error_jmp) == 0) {
1851 catch_memory_errors = 1;
1852 sync();
1853 p = (char *)adrs;
1854 q = (char *)buf;
1855 switch (size) {
1856 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001857 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 break;
1859 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001860 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 break;
1862 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001863 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 break;
1865 default:
1866 for( ; n < size; ++n) {
1867 *q++ = *p++;
1868 sync();
1869 }
1870 }
1871 sync();
1872 /* wait a little while to see if we get a machine check */
1873 __delay(200);
1874 n = size;
1875 }
1876 catch_memory_errors = 0;
1877 return n;
1878}
1879
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001880static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881mwrite(unsigned long adrs, void *buf, int size)
1882{
1883 volatile int n;
1884 char *p, *q;
1885
1886 n = 0;
1887 if (setjmp(bus_error_jmp) == 0) {
1888 catch_memory_errors = 1;
1889 sync();
1890 p = (char *) adrs;
1891 q = (char *) buf;
1892 switch (size) {
1893 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001894 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 break;
1896 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001897 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 break;
1899 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001900 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 break;
1902 default:
1903 for ( ; n < size; ++n) {
1904 *p++ = *q++;
1905 sync();
1906 }
1907 }
1908 sync();
1909 /* wait a little while to see if we get a machine check */
1910 __delay(200);
1911 n = size;
1912 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10001913 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 }
1915 catch_memory_errors = 0;
1916 return n;
1917}
1918
1919static int fault_type;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001920static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921static char *fault_chars[] = { "--", "**", "##" };
1922
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001923static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001925 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 switch (TRAP(regs)) {
1927 case 0x200:
1928 fault_type = 0;
1929 break;
1930 case 0x300:
1931 case 0x380:
1932 fault_type = 1;
1933 break;
1934 default:
1935 fault_type = 2;
1936 }
1937
1938 longjmp(bus_error_jmp, 1);
1939
1940 return 0;
1941}
1942
1943#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1944
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001945static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946byterev(unsigned char *val, int size)
1947{
1948 int t;
1949
1950 switch (size) {
1951 case 2:
1952 SWAP(val[0], val[1], t);
1953 break;
1954 case 4:
1955 SWAP(val[0], val[3], t);
1956 SWAP(val[1], val[2], t);
1957 break;
1958 case 8: /* is there really any use for this? */
1959 SWAP(val[0], val[7], t);
1960 SWAP(val[1], val[6], t);
1961 SWAP(val[2], val[5], t);
1962 SWAP(val[3], val[4], t);
1963 break;
1964 }
1965}
1966
1967static int brev;
1968static int mnoread;
1969
Michael Ellermane3bc8042012-08-23 22:09:13 +00001970static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 "Memory examine command usage:\n"
1972 "m [addr] [flags] examine/change memory\n"
1973 " addr is optional. will start where left off.\n"
1974 " flags may include chars from this set:\n"
1975 " b modify by bytes (default)\n"
1976 " w modify by words (2 byte)\n"
1977 " l modify by longs (4 byte)\n"
1978 " d modify by doubleword (8 byte)\n"
1979 " r toggle reverse byte order mode\n"
1980 " n do not read memory (for i/o spaces)\n"
1981 " . ok to read (default)\n"
1982 "NOTE: flags are saved as defaults\n"
1983 "";
1984
Michael Ellermane3bc8042012-08-23 22:09:13 +00001985static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 "Memory examine subcommands:\n"
1987 " hexval write this val to current location\n"
1988 " 'string' write chars from string to this location\n"
1989 " ' increment address\n"
1990 " ^ decrement address\n"
1991 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1992 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1993 " ` clear no-read flag\n"
1994 " ; stay at this addr\n"
1995 " v change to byte mode\n"
1996 " w change to word (2 byte) mode\n"
1997 " l change to long (4 byte) mode\n"
1998 " u change to doubleword (8 byte) mode\n"
1999 " m addr change current addr\n"
2000 " n toggle no-read flag\n"
2001 " r toggle byte reverse flag\n"
2002 " < count back up count bytes\n"
2003 " > count skip forward count bytes\n"
2004 " x exit this mode\n"
2005 "";
2006
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002007static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008memex(void)
2009{
2010 int cmd, inc, i, nslash;
2011 unsigned long n;
2012 unsigned char val[16];
2013
2014 scanhex((void *)&adrs);
2015 cmd = skipbl();
2016 if (cmd == '?') {
2017 printf(memex_help_string);
2018 return;
2019 } else {
2020 termch = cmd;
2021 }
2022 last_cmd = "m\n";
2023 while ((cmd = skipbl()) != '\n') {
2024 switch( cmd ){
2025 case 'b': size = 1; break;
2026 case 'w': size = 2; break;
2027 case 'l': size = 4; break;
2028 case 'd': size = 8; break;
2029 case 'r': brev = !brev; break;
2030 case 'n': mnoread = 1; break;
2031 case '.': mnoread = 0; break;
2032 }
2033 }
2034 if( size <= 0 )
2035 size = 1;
2036 else if( size > 8 )
2037 size = 8;
2038 for(;;){
2039 if (!mnoread)
2040 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002041 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 if (!mnoread) {
2043 if (brev)
2044 byterev(val, size);
2045 putchar(' ');
2046 for (i = 0; i < n; ++i)
2047 printf("%.2x", val[i]);
2048 for (; i < size; ++i)
2049 printf("%s", fault_chars[fault_type]);
2050 }
2051 putchar(' ');
2052 inc = size;
2053 nslash = 0;
2054 for(;;){
2055 if( scanhex(&n) ){
2056 for (i = 0; i < size; ++i)
2057 val[i] = n >> (i * 8);
2058 if (!brev)
2059 byterev(val, size);
2060 mwrite(adrs, val, size);
2061 inc = size;
2062 }
2063 cmd = skipbl();
2064 if (cmd == '\n')
2065 break;
2066 inc = 0;
2067 switch (cmd) {
2068 case '\'':
2069 for(;;){
2070 n = inchar();
2071 if( n == '\\' )
2072 n = bsesc();
2073 else if( n == '\'' )
2074 break;
2075 for (i = 0; i < size; ++i)
2076 val[i] = n >> (i * 8);
2077 if (!brev)
2078 byterev(val, size);
2079 mwrite(adrs, val, size);
2080 adrs += size;
2081 }
2082 adrs -= size;
2083 inc = size;
2084 break;
2085 case ',':
2086 adrs += size;
2087 break;
2088 case '.':
2089 mnoread = 0;
2090 break;
2091 case ';':
2092 break;
2093 case 'x':
2094 case EOF:
2095 scannl();
2096 return;
2097 case 'b':
2098 case 'v':
2099 size = 1;
2100 break;
2101 case 'w':
2102 size = 2;
2103 break;
2104 case 'l':
2105 size = 4;
2106 break;
2107 case 'u':
2108 size = 8;
2109 break;
2110 case '^':
2111 adrs -= size;
2112 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 case '/':
2114 if (nslash > 0)
2115 adrs -= 1 << nslash;
2116 else
2117 nslash = 0;
2118 nslash += 4;
2119 adrs += 1 << nslash;
2120 break;
2121 case '\\':
2122 if (nslash < 0)
2123 adrs += 1 << -nslash;
2124 else
2125 nslash = 0;
2126 nslash -= 4;
2127 adrs -= 1 << -nslash;
2128 break;
2129 case 'm':
2130 scanhex((void *)&adrs);
2131 break;
2132 case 'n':
2133 mnoread = 1;
2134 break;
2135 case 'r':
2136 brev = !brev;
2137 break;
2138 case '<':
2139 n = size;
2140 scanhex(&n);
2141 adrs -= n;
2142 break;
2143 case '>':
2144 n = size;
2145 scanhex(&n);
2146 adrs += n;
2147 break;
2148 case '?':
2149 printf(memex_subcmd_help_string);
2150 break;
2151 }
2152 }
2153 adrs += inc;
2154 }
2155}
2156
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002157static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158bsesc(void)
2159{
2160 int c;
2161
2162 c = inchar();
2163 switch( c ){
2164 case 'n': c = '\n'; break;
2165 case 'r': c = '\r'; break;
2166 case 'b': c = '\b'; break;
2167 case 't': c = '\t'; break;
2168 }
2169 return c;
2170}
2171
Olaf Hering7e5b5932006-03-08 20:40:28 +01002172static void xmon_rawdump (unsigned long adrs, long ndump)
2173{
2174 long n, m, r, nr;
2175 unsigned char temp[16];
2176
2177 for (n = ndump; n > 0;) {
2178 r = n < 16? n: 16;
2179 nr = mread(adrs, temp, r);
2180 adrs += nr;
2181 for (m = 0; m < r; ++m) {
2182 if (m < nr)
2183 printf("%.2x", temp[m]);
2184 else
2185 printf("%s", fault_chars[fault_type]);
2186 }
2187 n -= r;
2188 if (nr < r)
2189 break;
2190 }
2191 printf("\n");
2192}
2193
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002194#ifdef CONFIG_PPC64
2195static void dump_one_paca(int cpu)
2196{
2197 struct paca_struct *p;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002198#ifdef CONFIG_PPC_STD_MMU_64
2199 int i = 0;
2200#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002201
2202 if (setjmp(bus_error_jmp) != 0) {
2203 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2204 return;
2205 }
2206
2207 catch_memory_errors = 1;
2208 sync();
2209
2210 p = &paca[cpu];
2211
2212 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2213
Michael Ellermanad987fc2015-10-14 16:58:36 +11002214 printf(" %-*s = %s\n", 20, "possible", cpu_possible(cpu) ? "yes" : "no");
2215 printf(" %-*s = %s\n", 20, "present", cpu_present(cpu) ? "yes" : "no");
2216 printf(" %-*s = %s\n", 20, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002217
2218#define DUMP(paca, name, format) \
Michael Ellermanad987fc2015-10-14 16:58:36 +11002219 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 20, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002220 offsetof(struct paca_struct, name));
2221
2222 DUMP(p, lock_token, "x");
2223 DUMP(p, paca_index, "x");
2224 DUMP(p, kernel_toc, "lx");
2225 DUMP(p, kernelbase, "lx");
2226 DUMP(p, kernel_msr, "lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002227 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302228#ifdef CONFIG_PPC_BOOK3S_64
2229 DUMP(p, mc_emergency_sp, "p");
2230 DUMP(p, in_mce, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002231 DUMP(p, hmi_event_available, "x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302232#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002233 DUMP(p, data_offset, "lx");
2234 DUMP(p, hw_cpu_id, "x");
2235 DUMP(p, cpu_start, "x");
2236 DUMP(p, kexec_state, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002237#ifdef CONFIG_PPC_STD_MMU_64
2238 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2239 u64 esid, vsid;
2240
2241 if (!p->slb_shadow_ptr)
2242 continue;
2243
2244 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2245 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
2246
2247 if (esid || vsid) {
2248 printf(" slb_shadow[%d]: = 0x%016lx 0x%016lx\n",
2249 i, esid, vsid);
2250 }
2251 }
2252 DUMP(p, vmalloc_sllp, "x");
2253 DUMP(p, slb_cache_ptr, "x");
2254 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2255 printf(" slb_cache[%d]: = 0x%016lx\n", i, p->slb_cache[i]);
2256#endif
2257 DUMP(p, dscr_default, "llx");
2258#ifdef CONFIG_PPC_BOOK3E
2259 DUMP(p, pgd, "p");
2260 DUMP(p, kernel_pgd, "p");
2261 DUMP(p, tcd_ptr, "p");
2262 DUMP(p, mc_kstack, "p");
2263 DUMP(p, crit_kstack, "p");
2264 DUMP(p, dbg_kstack, "p");
2265#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002266 DUMP(p, __current, "p");
2267 DUMP(p, kstack, "lx");
2268 DUMP(p, stab_rr, "lx");
2269 DUMP(p, saved_r1, "lx");
2270 DUMP(p, trap_save, "x");
2271 DUMP(p, soft_enabled, "x");
2272 DUMP(p, irq_happened, "x");
2273 DUMP(p, io_sync, "x");
2274 DUMP(p, irq_work_pending, "x");
2275 DUMP(p, nap_state_lost, "x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002276 DUMP(p, sprg_vdso, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002277
Michael Ellermanad987fc2015-10-14 16:58:36 +11002278#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
2279 DUMP(p, tm_scratch, "llx");
2280#endif
2281
2282#ifdef CONFIG_PPC_POWERNV
2283 DUMP(p, core_idle_state_ptr, "p");
2284 DUMP(p, thread_idle_state, "x");
2285 DUMP(p, thread_mask, "x");
2286 DUMP(p, subcore_sibling_mask, "x");
2287#endif
2288
Christophe Leroyc223c902016-05-17 08:33:46 +02002289 DUMP(p, accounting.user_time, "llx");
2290 DUMP(p, accounting.system_time, "llx");
2291 DUMP(p, accounting.user_time_scaled, "llx");
2292 DUMP(p, accounting.starttime, "llx");
2293 DUMP(p, accounting.starttime_user, "llx");
2294 DUMP(p, accounting.startspurr, "llx");
2295 DUMP(p, accounting.utime_sspurr, "llx");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002296 DUMP(p, stolen_time, "llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002297#undef DUMP
2298
2299 catch_memory_errors = 0;
2300 sync();
2301}
2302
2303static void dump_all_pacas(void)
2304{
2305 int cpu;
2306
2307 if (num_possible_cpus() == 0) {
2308 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2309 return;
2310 }
2311
2312 for_each_possible_cpu(cpu)
2313 dump_one_paca(cpu);
2314}
2315
2316static void dump_pacas(void)
2317{
2318 unsigned long num;
2319 int c;
2320
2321 c = inchar();
2322 if (c == 'a') {
2323 dump_all_pacas();
2324 return;
2325 }
2326
2327 termch = c; /* Put c back, it wasn't 'a' */
2328
2329 if (scanhex(&num))
2330 dump_one_paca(num);
2331 else
2332 dump_one_paca(xmon_owner);
2333}
2334#endif
2335
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002336static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337dump(void)
2338{
2339 int c;
2340
2341 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002342
2343#ifdef CONFIG_PPC64
2344 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002345 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002346 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002347 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002348 return;
2349 }
2350#endif
2351
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2353 termch = c;
2354 scanhex((void *)&adrs);
2355 if (termch != '\n')
2356 termch = 0;
2357 if (c == 'i') {
2358 scanhex(&nidump);
2359 if (nidump == 0)
2360 nidump = 16;
2361 else if (nidump > MAX_DUMP)
2362 nidump = MAX_DUMP;
2363 adrs += ppc_inst_dump(adrs, nidump, 1);
2364 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002365 } else if (c == 'l') {
2366 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002367 } else if (c == 'o') {
2368 dump_opal_msglog();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002369 } else if (c == 'r') {
2370 scanhex(&ndump);
2371 if (ndump == 0)
2372 ndump = 64;
2373 xmon_rawdump(adrs, ndump);
2374 adrs += ndump;
2375 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 } else {
2377 scanhex(&ndump);
2378 if (ndump == 0)
2379 ndump = 64;
2380 else if (ndump > MAX_DUMP)
2381 ndump = MAX_DUMP;
2382 prdump(adrs, ndump);
2383 adrs += ndump;
2384 last_cmd = "d\n";
2385 }
2386}
2387
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002388static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389prdump(unsigned long adrs, long ndump)
2390{
2391 long n, m, c, r, nr;
2392 unsigned char temp[16];
2393
2394 for (n = ndump; n > 0;) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002395 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 putchar(' ');
2397 r = n < 16? n: 16;
2398 nr = mread(adrs, temp, r);
2399 adrs += nr;
2400 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002401 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002402 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 if (m < nr)
2404 printf("%.2x", temp[m]);
2405 else
2406 printf("%s", fault_chars[fault_type]);
2407 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002408 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002409 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002410 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 printf(" |");
2414 for (m = 0; m < r; ++m) {
2415 if (m < nr) {
2416 c = temp[m];
2417 putchar(' ' <= c && c <= '~'? c: '.');
2418 } else
2419 putchar(' ');
2420 }
2421 n -= r;
2422 for (; m < 16; ++m)
2423 putchar(' ');
2424 printf("|\n");
2425 if (nr < r)
2426 break;
2427 }
2428}
2429
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002430typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2431
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002432static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002433generic_inst_dump(unsigned long adr, long count, int praddr,
2434 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435{
2436 int nr, dotted;
2437 unsigned long first_adr;
2438 unsigned long inst, last_inst = 0;
2439 unsigned char val[4];
2440
2441 dotted = 0;
2442 for (first_adr = adr; count > 0; --count, adr += 4) {
2443 nr = mread(adr, val, 4);
2444 if (nr == 0) {
2445 if (praddr) {
2446 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002447 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 }
2449 break;
2450 }
2451 inst = GETWORD(val);
2452 if (adr > first_adr && inst == last_inst) {
2453 if (!dotted) {
2454 printf(" ...\n");
2455 dotted = 1;
2456 }
2457 continue;
2458 }
2459 dotted = 0;
2460 last_inst = inst;
2461 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002462 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002464 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 printf("\n");
2466 }
2467 return adr - first_adr;
2468}
2469
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002470static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002471ppc_inst_dump(unsigned long adr, long count, int praddr)
2472{
2473 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2474}
2475
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476void
2477print_address(unsigned long addr)
2478{
2479 xmon_print_symbol(addr, "\t# ", "");
2480}
2481
Vinay Sridharf312deb2009-05-14 23:13:07 +00002482void
2483dump_log_buf(void)
2484{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002485 struct kmsg_dumper dumper = { .active = 1 };
2486 unsigned char buf[128];
2487 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002488
Michael Ellermane3bc8042012-08-23 22:09:13 +00002489 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002490 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002491 return;
2492 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002493
Michael Ellermane3bc8042012-08-23 22:09:13 +00002494 catch_memory_errors = 1;
2495 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002496
Michael Ellermanca5dd392012-08-23 22:09:12 +00002497 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002498 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002499 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2500 buf[len] = '\0';
2501 printf("%s", buf);
2502 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002503 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002504
Michael Ellermane3bc8042012-08-23 22:09:13 +00002505 sync();
2506 /* wait a little while to see if we get a machine check */
2507 __delay(200);
2508 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002509}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002511#ifdef CONFIG_PPC_POWERNV
2512static void dump_opal_msglog(void)
2513{
2514 unsigned char buf[128];
2515 ssize_t res;
2516 loff_t pos = 0;
2517
2518 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2519 printf("Machine is not running OPAL firmware.\n");
2520 return;
2521 }
2522
2523 if (setjmp(bus_error_jmp) != 0) {
2524 printf("Error dumping OPAL msglog!\n");
2525 return;
2526 }
2527
2528 catch_memory_errors = 1;
2529 sync();
2530
2531 xmon_start_pagination();
2532 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2533 if (res < 0) {
2534 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2535 break;
2536 }
2537 buf[res] = '\0';
2538 printf("%s", buf);
2539 pos += res;
2540 }
2541 xmon_end_pagination();
2542
2543 sync();
2544 /* wait a little while to see if we get a machine check */
2545 __delay(200);
2546 catch_memory_errors = 0;
2547}
2548#endif
2549
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550/*
2551 * Memory operations - move, set, print differences
2552 */
2553static unsigned long mdest; /* destination address */
2554static unsigned long msrc; /* source address */
2555static unsigned long mval; /* byte value to set memory to */
2556static unsigned long mcount; /* # bytes to affect */
2557static unsigned long mdiffs; /* max # differences to print */
2558
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002559static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560memops(int cmd)
2561{
2562 scanhex((void *)&mdest);
2563 if( termch != '\n' )
2564 termch = 0;
2565 scanhex((void *)(cmd == 's'? &mval: &msrc));
2566 if( termch != '\n' )
2567 termch = 0;
2568 scanhex((void *)&mcount);
2569 switch( cmd ){
2570 case 'm':
2571 memmove((void *)mdest, (void *)msrc, mcount);
2572 break;
2573 case 's':
2574 memset((void *)mdest, mval, mcount);
2575 break;
2576 case 'd':
2577 if( termch != '\n' )
2578 termch = 0;
2579 scanhex((void *)&mdiffs);
2580 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2581 break;
2582 }
2583}
2584
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002585static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2587{
2588 unsigned n, prt;
2589
2590 prt = 0;
2591 for( n = nb; n > 0; --n )
2592 if( *p1++ != *p2++ )
2593 if( ++prt <= maxpr )
2594 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2595 p1[-1], p2 - 1, p2[-1]);
2596 if( prt > maxpr )
2597 printf("Total of %d differences\n", prt);
2598}
2599
2600static unsigned mend;
2601static unsigned mask;
2602
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002603static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604memlocate(void)
2605{
2606 unsigned a, n;
2607 unsigned char val[4];
2608
2609 last_cmd = "ml";
2610 scanhex((void *)&mdest);
2611 if (termch != '\n') {
2612 termch = 0;
2613 scanhex((void *)&mend);
2614 if (termch != '\n') {
2615 termch = 0;
2616 scanhex((void *)&mval);
2617 mask = ~0;
2618 if (termch != '\n') termch = 0;
2619 scanhex((void *)&mask);
2620 }
2621 }
2622 n = 0;
2623 for (a = mdest; a < mend; a += 4) {
2624 if (mread(a, val, 4) == 4
2625 && ((GETWORD(val) ^ mval) & mask) == 0) {
2626 printf("%.16x: %.16x\n", a, GETWORD(val));
2627 if (++n >= 10)
2628 break;
2629 }
2630 }
2631}
2632
2633static unsigned long mskip = 0x1000;
2634static unsigned long mlim = 0xffffffff;
2635
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002636static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637memzcan(void)
2638{
2639 unsigned char v;
2640 unsigned a;
2641 int ok, ook;
2642
2643 scanhex(&mdest);
2644 if (termch != '\n') termch = 0;
2645 scanhex(&mskip);
2646 if (termch != '\n') termch = 0;
2647 scanhex(&mlim);
2648 ook = 0;
2649 for (a = mdest; a < mlim; a += mskip) {
2650 ok = mread(a, &v, 1);
2651 if (ok && !ook) {
2652 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 } else if (!ok && ook)
2654 printf("%.8x\n", a - mskip);
2655 ook = ok;
2656 if (a + mskip < a)
2657 break;
2658 }
2659 if (ook)
2660 printf("%.8x\n", a - mskip);
2661}
2662
Douglas Miller6dfb5402015-11-23 09:01:15 -06002663static void show_task(struct task_struct *tsk)
2664{
2665 char state;
2666
2667 /*
2668 * Cloned from kdb_task_state_char(), which is not entirely
2669 * appropriate for calling from xmon. This could be moved
2670 * to a common, generic, routine used by both.
2671 */
2672 state = (tsk->state == 0) ? 'R' :
2673 (tsk->state < 0) ? 'U' :
2674 (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
2675 (tsk->state & TASK_STOPPED) ? 'T' :
2676 (tsk->state & TASK_TRACED) ? 'C' :
2677 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
2678 (tsk->exit_state & EXIT_DEAD) ? 'E' :
2679 (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
2680
2681 printf("%p %016lx %6d %6d %c %2d %s\n", tsk,
2682 tsk->thread.ksp,
2683 tsk->pid, tsk->parent->pid,
2684 state, task_thread_info(tsk)->cpu,
2685 tsk->comm);
2686}
2687
2688static void show_tasks(void)
2689{
2690 unsigned long tskv;
2691 struct task_struct *tsk = NULL;
2692
2693 printf(" task_struct ->thread.ksp PID PPID S P CMD\n");
2694
2695 if (scanhex(&tskv))
2696 tsk = (struct task_struct *)tskv;
2697
2698 if (setjmp(bus_error_jmp) != 0) {
2699 catch_memory_errors = 0;
2700 printf("*** Error dumping task %p\n", tsk);
2701 return;
2702 }
2703
2704 catch_memory_errors = 1;
2705 sync();
2706
2707 if (tsk)
2708 show_task(tsk);
2709 else
2710 for_each_process(tsk)
2711 show_task(tsk);
2712
2713 sync();
2714 __delay(200);
2715 catch_memory_errors = 0;
2716}
2717
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002718static void proccall(void)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002719{
2720 unsigned long args[8];
2721 unsigned long ret;
2722 int i;
2723 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2724 unsigned long, unsigned long, unsigned long,
2725 unsigned long, unsigned long, unsigned long);
2726 callfunc_t func;
2727
2728 if (!scanhex(&adrs))
2729 return;
2730 if (termch != '\n')
2731 termch = 0;
2732 for (i = 0; i < 8; ++i)
2733 args[i] = 0;
2734 for (i = 0; i < 8; ++i) {
2735 if (!scanhex(&args[i]) || termch == '\n')
2736 break;
2737 termch = 0;
2738 }
2739 func = (callfunc_t) adrs;
2740 ret = 0;
2741 if (setjmp(bus_error_jmp) == 0) {
2742 catch_memory_errors = 1;
2743 sync();
2744 ret = func(args[0], args[1], args[2], args[3],
2745 args[4], args[5], args[6], args[7]);
2746 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10002747 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002748 } else {
2749 printf("*** %x exception occurred\n", fault_except);
2750 }
2751 catch_memory_errors = 0;
2752}
2753
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754/* Input scanning routines */
2755int
2756skipbl(void)
2757{
2758 int c;
2759
2760 if( termch != 0 ){
2761 c = termch;
2762 termch = 0;
2763 } else
2764 c = inchar();
2765 while( c == ' ' || c == '\t' )
2766 c = inchar();
2767 return c;
2768}
2769
2770#define N_PTREGS 44
2771static char *regnames[N_PTREGS] = {
2772 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2773 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2774 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2775 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002776 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2777#ifdef CONFIG_PPC64
2778 "softe",
2779#else
2780 "mq",
2781#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 "trap", "dar", "dsisr", "res"
2783};
2784
2785int
2786scanhex(unsigned long *vp)
2787{
2788 int c, d;
2789 unsigned long v;
2790
2791 c = skipbl();
2792 if (c == '%') {
2793 /* parse register name */
2794 char regname[8];
2795 int i;
2796
2797 for (i = 0; i < sizeof(regname) - 1; ++i) {
2798 c = inchar();
2799 if (!isalnum(c)) {
2800 termch = c;
2801 break;
2802 }
2803 regname[i] = c;
2804 }
2805 regname[i] = 0;
2806 for (i = 0; i < N_PTREGS; ++i) {
2807 if (strcmp(regnames[i], regname) == 0) {
2808 if (xmon_regs == NULL) {
2809 printf("regs not available\n");
2810 return 0;
2811 }
2812 *vp = ((unsigned long *)xmon_regs)[i];
2813 return 1;
2814 }
2815 }
2816 printf("invalid register name '%%%s'\n", regname);
2817 return 0;
2818 }
2819
2820 /* skip leading "0x" if any */
2821
2822 if (c == '0') {
2823 c = inchar();
2824 if (c == 'x') {
2825 c = inchar();
2826 } else {
2827 d = hexdigit(c);
2828 if (d == EOF) {
2829 termch = c;
2830 *vp = 0;
2831 return 1;
2832 }
2833 }
2834 } else if (c == '$') {
2835 int i;
2836 for (i=0; i<63; i++) {
2837 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02002838 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 termch = c;
2840 break;
2841 }
2842 tmpstr[i] = c;
2843 }
2844 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002845 *vp = 0;
2846 if (setjmp(bus_error_jmp) == 0) {
2847 catch_memory_errors = 1;
2848 sync();
2849 *vp = kallsyms_lookup_name(tmpstr);
2850 sync();
2851 }
2852 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 if (!(*vp)) {
2854 printf("unknown symbol '%s'\n", tmpstr);
2855 return 0;
2856 }
2857 return 1;
2858 }
2859
2860 d = hexdigit(c);
2861 if (d == EOF) {
2862 termch = c;
2863 return 0;
2864 }
2865 v = 0;
2866 do {
2867 v = (v << 4) + d;
2868 c = inchar();
2869 d = hexdigit(c);
2870 } while (d != EOF);
2871 termch = c;
2872 *vp = v;
2873 return 1;
2874}
2875
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002876static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877scannl(void)
2878{
2879 int c;
2880
2881 c = termch;
2882 termch = 0;
2883 while( c != '\n' )
2884 c = inchar();
2885}
2886
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002887static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888{
2889 if( '0' <= c && c <= '9' )
2890 return c - '0';
2891 if( 'A' <= c && c <= 'F' )
2892 return c - ('A' - 10);
2893 if( 'a' <= c && c <= 'f' )
2894 return c - ('a' - 10);
2895 return EOF;
2896}
2897
2898void
2899getstring(char *s, int size)
2900{
2901 int c;
2902
2903 c = skipbl();
2904 do {
2905 if( size > 1 ){
2906 *s++ = c;
2907 --size;
2908 }
2909 c = inchar();
2910 } while( c != ' ' && c != '\t' && c != '\n' );
2911 termch = c;
2912 *s = 0;
2913}
2914
2915static char line[256];
2916static char *lineptr;
2917
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002918static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919flush_input(void)
2920{
2921 lineptr = NULL;
2922}
2923
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002924static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925inchar(void)
2926{
2927 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002928 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 lineptr = NULL;
2930 return EOF;
2931 }
2932 lineptr = line;
2933 }
2934 return *lineptr++;
2935}
2936
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002937static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938take_input(char *str)
2939{
2940 lineptr = str;
2941}
2942
2943
2944static void
2945symbol_lookup(void)
2946{
2947 int type = inchar();
2948 unsigned long addr;
2949 static char tmp[64];
2950
2951 switch (type) {
2952 case 'a':
2953 if (scanhex(&addr))
2954 xmon_print_symbol(addr, ": ", "\n");
2955 termch = 0;
2956 break;
2957 case 's':
2958 getstring(tmp, 64);
2959 if (setjmp(bus_error_jmp) == 0) {
2960 catch_memory_errors = 1;
2961 sync();
2962 addr = kallsyms_lookup_name(tmp);
2963 if (addr)
2964 printf("%s: %lx\n", tmp, addr);
2965 else
2966 printf("Symbol '%s' not found.\n", tmp);
2967 sync();
2968 }
2969 catch_memory_errors = 0;
2970 termch = 0;
2971 break;
2972 }
2973}
2974
2975
2976/* Print an address in numeric and symbolic form (if possible) */
2977static void xmon_print_symbol(unsigned long address, const char *mid,
2978 const char *after)
2979{
2980 char *modname;
2981 const char *name = NULL;
2982 unsigned long offset, size;
2983
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002984 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 if (setjmp(bus_error_jmp) == 0) {
2986 catch_memory_errors = 1;
2987 sync();
2988 name = kallsyms_lookup(address, &size, &offset, &modname,
2989 tmpstr);
2990 sync();
2991 /* wait a little while to see if we get a machine check */
2992 __delay(200);
2993 }
2994
2995 catch_memory_errors = 0;
2996
2997 if (name) {
2998 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2999 if (modname)
3000 printf(" [%s]", modname);
3001 }
3002 printf("%s", after);
3003}
3004
Aneesh Kumar K.Vcaca2852016-04-29 23:26:07 +10003005#ifdef CONFIG_PPC_STD_MMU_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10003006void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007{
3008 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05303009 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11003010 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011
Michael Ellerman736256e2014-05-26 21:02:14 +10003012 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013
Michael Neuling584f8b72007-12-06 17:24:48 +11003014 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11003015 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
3016 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Anshuman Khandual8218a302015-07-29 12:40:04 +05303017 if (esid || vsid) {
will schmidtb3b95952007-12-07 08:22:23 +11003018 printf("%02d %016lx %016lx", i, esid, vsid);
Anshuman Khandual8218a302015-07-29 12:40:04 +05303019 if (esid & SLB_ESID_V) {
will schmidtb3b95952007-12-07 08:22:23 +11003020 llp = vsid & SLB_VSID_LLP;
3021 if (vsid & SLB_VSID_B_1T) {
3022 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
3023 GET_ESID_1T(esid),
3024 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
3025 llp);
3026 } else {
3027 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
3028 GET_ESID(esid),
3029 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
3030 llp);
3031 }
3032 } else
3033 printf("\n");
3034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 }
3036}
Paul Mackerrasf78541d2005-10-28 22:53:37 +10003037#endif
3038
3039#ifdef CONFIG_PPC_STD_MMU_32
3040void dump_segments(void)
3041{
3042 int i;
3043
3044 printf("sr0-15 =");
3045 for (i = 0; i < 16; ++i)
Christophe Leroy52d915c2018-11-16 17:31:08 +00003046 printf(" %x", mfsrin(i << 28));
Paul Mackerrasf78541d2005-10-28 22:53:37 +10003047 printf("\n");
3048}
3049#endif
3050
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003051#ifdef CONFIG_44x
3052static void dump_tlb_44x(void)
3053{
3054 int i;
3055
3056 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
3057 unsigned long w0,w1,w2;
3058 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
3059 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
3060 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
3061 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
3062 if (w0 & PPC44x_TLB_VALID) {
3063 printf("V %08x -> %01x%08x %c%c%c%c%c",
3064 w0 & PPC44x_TLB_EPN_MASK,
3065 w1 & PPC44x_TLB_ERPN_MASK,
3066 w1 & PPC44x_TLB_RPN_MASK,
3067 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
3068 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
3069 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
3070 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
3071 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
3072 }
3073 printf("\n");
3074 }
3075}
3076#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003077
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10003078#ifdef CONFIG_PPC_BOOK3E
3079static void dump_tlb_book3e(void)
3080{
3081 u32 mmucfg, pidmask, lpidmask;
3082 u64 ramask;
3083 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3084 int mmu_version;
3085 static const char *pgsz_names[] = {
3086 " 1K",
3087 " 2K",
3088 " 4K",
3089 " 8K",
3090 " 16K",
3091 " 32K",
3092 " 64K",
3093 "128K",
3094 "256K",
3095 "512K",
3096 " 1M",
3097 " 2M",
3098 " 4M",
3099 " 8M",
3100 " 16M",
3101 " 32M",
3102 " 64M",
3103 "128M",
3104 "256M",
3105 "512M",
3106 " 1G",
3107 " 2G",
3108 " 4G",
3109 " 8G",
3110 " 16G",
3111 " 32G",
3112 " 64G",
3113 "128G",
3114 "256G",
3115 "512G",
3116 " 1T",
3117 " 2T",
3118 };
3119
3120 /* Gather some infos about the MMU */
3121 mmucfg = mfspr(SPRN_MMUCFG);
3122 mmu_version = (mmucfg & 3) + 1;
3123 ntlbs = ((mmucfg >> 2) & 3) + 1;
3124 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3125 lpidsz = (mmucfg >> 24) & 0xf;
3126 rasz = (mmucfg >> 16) & 0x7f;
3127 if ((mmu_version > 1) && (mmucfg & 0x10000))
3128 lrat = 1;
3129 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3130 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3131 pidmask = (1ul << pidsz) - 1;
3132 lpidmask = (1ul << lpidsz) - 1;
3133 ramask = (1ull << rasz) - 1;
3134
3135 for (tlb = 0; tlb < ntlbs; tlb++) {
3136 u32 tlbcfg;
3137 int nent, assoc, new_cc = 1;
3138 printf("TLB %d:\n------\n", tlb);
3139 switch(tlb) {
3140 case 0:
3141 tlbcfg = mfspr(SPRN_TLB0CFG);
3142 break;
3143 case 1:
3144 tlbcfg = mfspr(SPRN_TLB1CFG);
3145 break;
3146 case 2:
3147 tlbcfg = mfspr(SPRN_TLB2CFG);
3148 break;
3149 case 3:
3150 tlbcfg = mfspr(SPRN_TLB3CFG);
3151 break;
3152 default:
3153 printf("Unsupported TLB number !\n");
3154 continue;
3155 }
3156 nent = tlbcfg & 0xfff;
3157 assoc = (tlbcfg >> 24) & 0xff;
3158 for (i = 0; i < nent; i++) {
3159 u32 mas0 = MAS0_TLBSEL(tlb);
3160 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3161 u64 mas2 = 0;
3162 u64 mas7_mas3;
3163 int esel = i, cc = i;
3164
3165 if (assoc != 0) {
3166 cc = i / assoc;
3167 esel = i % assoc;
3168 mas2 = cc * 0x1000;
3169 }
3170
3171 mas0 |= MAS0_ESEL(esel);
3172 mtspr(SPRN_MAS0, mas0);
3173 mtspr(SPRN_MAS1, mas1);
3174 mtspr(SPRN_MAS2, mas2);
3175 asm volatile("tlbre 0,0,0" : : : "memory");
3176 mas1 = mfspr(SPRN_MAS1);
3177 mas2 = mfspr(SPRN_MAS2);
3178 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3179 if (assoc && (i % assoc) == 0)
3180 new_cc = 1;
3181 if (!(mas1 & MAS1_VALID))
3182 continue;
3183 if (assoc == 0)
3184 printf("%04x- ", i);
3185 else if (new_cc)
3186 printf("%04x-%c", cc, 'A' + esel);
3187 else
3188 printf(" |%c", 'A' + esel);
3189 new_cc = 0;
3190 printf(" %016llx %04x %s %c%c AS%c",
3191 mas2 & ~0x3ffull,
3192 (mas1 >> 16) & 0x3fff,
3193 pgsz_names[(mas1 >> 7) & 0x1f],
3194 mas1 & MAS1_IND ? 'I' : ' ',
3195 mas1 & MAS1_IPROT ? 'P' : ' ',
3196 mas1 & MAS1_TS ? '1' : '0');
3197 printf(" %c%c%c%c%c%c%c",
3198 mas2 & MAS2_X0 ? 'a' : ' ',
3199 mas2 & MAS2_X1 ? 'v' : ' ',
3200 mas2 & MAS2_W ? 'w' : ' ',
3201 mas2 & MAS2_I ? 'i' : ' ',
3202 mas2 & MAS2_M ? 'm' : ' ',
3203 mas2 & MAS2_G ? 'g' : ' ',
3204 mas2 & MAS2_E ? 'e' : ' ');
3205 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3206 if (mas1 & MAS1_IND)
3207 printf(" %s\n",
3208 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3209 else
3210 printf(" U%c%c%c S%c%c%c\n",
3211 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3212 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3213 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3214 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3215 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3216 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3217 }
3218 }
3219}
3220#endif /* CONFIG_PPC_BOOK3E */
3221
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003222static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003224 if (enable) {
3225 __debugger = xmon;
3226 __debugger_ipi = xmon_ipi;
3227 __debugger_bpt = xmon_bpt;
3228 __debugger_sstep = xmon_sstep;
3229 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003230 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003231 __debugger_fault_handler = xmon_fault_handler;
Breno Leitao81175082018-11-08 15:12:42 -02003232
3233#ifdef CONFIG_PPC_PSERIES
3234 /*
3235 * Get the token here to avoid trying to get a lock
3236 * during the crash, causing a deadlock.
3237 */
3238 set_indicator_token = rtas_token("set-indicator");
3239#endif
Olaf Heringb13cfd172005-08-04 19:26:42 +02003240 } else {
3241 __debugger = NULL;
3242 __debugger_ipi = NULL;
3243 __debugger_bpt = NULL;
3244 __debugger_sstep = NULL;
3245 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003246 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003247 __debugger_fault_handler = NULL;
3248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003250
3251#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003252static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003253{
3254 /* ensure xmon is enabled */
3255 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003256 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003257}
3258
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003259static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003260 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003261 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003262 .action_msg = "Entering xmon",
3263};
3264
3265static int __init setup_xmon_sysrq(void)
3266{
3267 register_sysrq_key('x', &sysrq_xmon_op);
3268 return 0;
3269}
3270__initcall(setup_xmon_sysrq);
3271#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003272
Olaf Heringf5e6a282007-06-24 16:57:08 +10003273static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10003274
3275static int __init early_parse_xmon(char *p)
3276{
3277 if (!p || strncmp(p, "early", 5) == 0) {
3278 /* just "xmon" is equivalent to "xmon=early" */
3279 xmon_init(1);
3280 xmon_early = 1;
3281 } else if (strncmp(p, "on", 2) == 0)
3282 xmon_init(1);
3283 else if (strncmp(p, "off", 3) == 0)
3284 xmon_off = 1;
3285 else if (strncmp(p, "nobt", 4) == 0)
3286 xmon_no_auto_backtrace = 1;
3287 else
3288 return 1;
3289
3290 return 0;
3291}
3292early_param("xmon", early_parse_xmon);
3293
3294void __init xmon_setup(void)
3295{
3296#ifdef CONFIG_XMON_DEFAULT
3297 if (!xmon_off)
3298 xmon_init(1);
3299#endif
3300 if (xmon_early)
3301 debugger(NULL);
3302}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003303
Arnd Bergmanne0555952006-11-27 19:18:55 +01003304#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003305
3306struct spu_info {
3307 struct spu *spu;
3308 u64 saved_mfc_sr1_RW;
3309 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003310 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003311 u8 stopped_ok;
3312};
3313
3314#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3315
3316static struct spu_info spu_info[XMON_NUM_SPUS];
3317
3318void xmon_register_spus(struct list_head *list)
3319{
3320 struct spu *spu;
3321
3322 list_for_each_entry(spu, list, full_list) {
3323 if (spu->number >= XMON_NUM_SPUS) {
3324 WARN_ON(1);
3325 continue;
3326 }
3327
3328 spu_info[spu->number].spu = spu;
3329 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003330 spu_info[spu->number].dump_addr = (unsigned long)
3331 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003332 }
3333}
3334
3335static void stop_spus(void)
3336{
3337 struct spu *spu;
3338 int i;
3339 u64 tmp;
3340
3341 for (i = 0; i < XMON_NUM_SPUS; i++) {
3342 if (!spu_info[i].spu)
3343 continue;
3344
3345 if (setjmp(bus_error_jmp) == 0) {
3346 catch_memory_errors = 1;
3347 sync();
3348
3349 spu = spu_info[i].spu;
3350
3351 spu_info[i].saved_spu_runcntl_RW =
3352 in_be32(&spu->problem->spu_runcntl_RW);
3353
3354 tmp = spu_mfc_sr1_get(spu);
3355 spu_info[i].saved_mfc_sr1_RW = tmp;
3356
3357 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3358 spu_mfc_sr1_set(spu, tmp);
3359
3360 sync();
3361 __delay(200);
3362
3363 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003364
3365 printf("Stopped spu %.2d (was %s)\n", i,
3366 spu_info[i].saved_spu_runcntl_RW ?
3367 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003368 } else {
3369 catch_memory_errors = 0;
3370 printf("*** Error stopping spu %.2d\n", i);
3371 }
3372 catch_memory_errors = 0;
3373 }
3374}
3375
3376static void restart_spus(void)
3377{
3378 struct spu *spu;
3379 int i;
3380
3381 for (i = 0; i < XMON_NUM_SPUS; i++) {
3382 if (!spu_info[i].spu)
3383 continue;
3384
3385 if (!spu_info[i].stopped_ok) {
3386 printf("*** Error, spu %d was not successfully stopped"
3387 ", not restarting\n", i);
3388 continue;
3389 }
3390
3391 if (setjmp(bus_error_jmp) == 0) {
3392 catch_memory_errors = 1;
3393 sync();
3394
3395 spu = spu_info[i].spu;
3396 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3397 out_be32(&spu->problem->spu_runcntl_RW,
3398 spu_info[i].saved_spu_runcntl_RW);
3399
3400 sync();
3401 __delay(200);
3402
3403 printf("Restarted spu %.2d\n", i);
3404 } else {
3405 catch_memory_errors = 0;
3406 printf("*** Error restarting spu %.2d\n", i);
3407 }
3408 catch_memory_errors = 0;
3409 }
3410}
3411
Michael Ellermana8984972006-10-24 18:31:28 +02003412#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003413#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003414do { \
3415 if (setjmp(bus_error_jmp) == 0) { \
3416 catch_memory_errors = 1; \
3417 sync(); \
3418 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003419 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003420 sync(); \
3421 __delay(200); \
3422 } else { \
3423 catch_memory_errors = 0; \
3424 printf(" %-*s = *** Error reading field.\n", \
3425 DUMP_WIDTH, #field); \
3426 } \
3427 catch_memory_errors = 0; \
3428} while (0)
3429
Michael Ellerman437a0702006-11-23 00:46:39 +01003430#define DUMP_FIELD(obj, format, field) \
3431 DUMP_VALUE(format, field, obj->field)
3432
Michael Ellermana8984972006-10-24 18:31:28 +02003433static void dump_spu_fields(struct spu *spu)
3434{
3435 printf("Dumping spu fields at address %p:\n", spu);
3436
3437 DUMP_FIELD(spu, "0x%x", number);
3438 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003439 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3440 DUMP_FIELD(spu, "0x%p", local_store);
3441 DUMP_FIELD(spu, "0x%lx", ls_size);
3442 DUMP_FIELD(spu, "0x%x", node);
3443 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003444 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003445 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003446 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3447 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003448 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3449 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3450 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3451 DUMP_FIELD(spu, "0x%x", slb_replace);
3452 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003453 DUMP_FIELD(spu, "0x%p", mm);
3454 DUMP_FIELD(spu, "0x%p", ctx);
3455 DUMP_FIELD(spu, "0x%p", rq);
3456 DUMP_FIELD(spu, "0x%p", timestamp);
3457 DUMP_FIELD(spu, "0x%lx", problem_phys);
3458 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003459 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3460 in_be32(&spu->problem->spu_runcntl_RW));
3461 DUMP_VALUE("0x%x", problem->spu_status_R,
3462 in_be32(&spu->problem->spu_status_R));
3463 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3464 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003465 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003466 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003467}
3468
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003469int
3470spu_inst_dump(unsigned long adr, long count, int praddr)
3471{
3472 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3473}
3474
3475static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003476{
3477 unsigned long offset, addr, ls_addr;
3478
3479 if (setjmp(bus_error_jmp) == 0) {
3480 catch_memory_errors = 1;
3481 sync();
3482 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3483 sync();
3484 __delay(200);
3485 } else {
3486 catch_memory_errors = 0;
3487 printf("*** Error: accessing spu info for spu %d\n", num);
3488 return;
3489 }
3490 catch_memory_errors = 0;
3491
3492 if (scanhex(&offset))
3493 addr = ls_addr + offset;
3494 else
3495 addr = spu_info[num].dump_addr;
3496
3497 if (addr >= ls_addr + LS_SIZE) {
3498 printf("*** Error: address outside of local store\n");
3499 return;
3500 }
3501
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003502 switch (subcmd) {
3503 case 'i':
3504 addr += spu_inst_dump(addr, 16, 1);
3505 last_cmd = "sdi\n";
3506 break;
3507 default:
3508 prdump(addr, 64);
3509 addr += 64;
3510 last_cmd = "sd\n";
3511 break;
3512 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003513
3514 spu_info[num].dump_addr = addr;
3515}
3516
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003517static int do_spu_cmd(void)
3518{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003519 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003520 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003521
3522 cmd = inchar();
3523 switch (cmd) {
3524 case 's':
3525 stop_spus();
3526 break;
3527 case 'r':
3528 restart_spus();
3529 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003530 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003531 subcmd = inchar();
3532 if (isxdigit(subcmd) || subcmd == '\n')
3533 termch = subcmd;
3534 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003535 scanhex(&num);
3536 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003537 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003538 return 0;
3539 }
3540
3541 switch (cmd) {
3542 case 'f':
3543 dump_spu_fields(spu_info[num].spu);
3544 break;
3545 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003546 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003547 break;
3548 }
3549
Michael Ellermana8984972006-10-24 18:31:28 +02003550 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003551 default:
3552 return -1;
3553 }
3554
3555 return 0;
3556}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003557#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003558static int do_spu_cmd(void)
3559{
3560 return -1;
3561}
3562#endif