blob: 8345defa0e437f10a74fd370e2030411fcc46d01 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Routines providing a simple monitor for use on the PowerMac.
3 *
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004 * Copyright (C) 1996-2005 Paul Mackerras.
Michael Ellerman476792832006-10-03 14:12:08 +10005 * Copyright (C) 2001 PPC64 Team, IBM Corp
6 * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
Michael Ellerman56144ec2015-11-06 13:21:17 +110013
14#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/errno.h>
Ingo Molnar3f07c012017-02-08 18:51:30 +010016#include <linux/sched/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/smp.h>
18#include <linux/mm.h>
19#include <linux/reboot.h>
20#include <linux/delay.h>
21#include <linux/kallsyms.h>
Michael Ellermanca5dd392012-08-23 22:09:12 +000022#include <linux/kmsg_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040024#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110025#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080026#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010027#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080028#include <linux/bug.h>
Anton Blancharda71d64b2014-08-05 14:55:00 +100029#include <linux/nmi.h>
Vincent Bernat05b981f2014-07-15 13:43:47 +020030#include <linux/ctype.h>
Balbir Singh80eff6c2017-10-30 22:01:12 +110031#include <linux/highmem.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
Michael Ellerman7644d582017-02-10 12:04:56 +110033#include <asm/debugfs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <asm/ptrace.h>
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +100035#include <asm/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/string.h>
37#include <asm/prom.h>
38#include <asm/machdep.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100039#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <asm/processor.h>
41#include <asm/pgtable.h>
42#include <asm/mmu.h>
43#include <asm/mmu_context.h>
Michael Ellermanab83dc72018-03-08 13:54:42 +110044#include <asm/plpar_wrappers.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <asm/cputable.h>
46#include <asm/rtas.h>
47#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100048#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020049#include <asm/spu.h>
50#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110051#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000052#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010053#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000054#include <asm/hw_breakpoint.h>
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +100055#include <asm/xive.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110056#include <asm/opal.h>
57#include <asm/firmware.h>
Balbir Singhefe4fbb2017-06-27 17:48:58 +100058#include <asm/code-patching.h>
Boqun Feng302c7b02016-11-22 17:20:09 +080059#include <asm/sections.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110060
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100061#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100063#include <asm/paca.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010067#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100070static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071static unsigned long xmon_taken = 1;
72static int xmon_owner;
73static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000074#else
75#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#endif /* CONFIG_SMP */
77
Anton Blanchard5be34922010-01-12 00:50:14 +000078static unsigned long in_xmon __read_mostly = 0;
Pan Xinhui3b5bf422017-03-22 16:27:49 -030079static int xmon_on = IS_ENABLED(CONFIG_XMON_DEFAULT);
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];
Breno Leitaoed49f7f2017-08-02 17:14:06 -030089static int tracing_enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
Linus Torvalds1da177e2005-04-16 15:20:36 -070091static long bus_error_jmp[JMP_BUF_LEN];
92static int catch_memory_errors;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +100093static int catch_spr_faults;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96/* Breakpoint stuff */
97struct bpt {
98 unsigned long address;
99 unsigned int instr[2];
100 atomic_t ref_count;
101 int enabled;
102 unsigned long pad;
103};
104
105/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100106#define BP_CIABR 1
107#define BP_TRAP 2
108#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
110#define NBPTS 256
111static struct bpt bpts[NBPTS];
112static struct bpt dabr;
113static struct bpt *iabr;
114static unsigned bpinstr = 0x7fe00008; /* trap */
115
116#define BP_NUM(bp) ((bp) - bpts + 1)
117
118/* Prototypes */
119static int cmds(struct pt_regs *);
120static int mread(unsigned long, void *, int);
121static int mwrite(unsigned long, void *, int);
122static int handle_fault(struct pt_regs *);
123static void byterev(unsigned char *, int);
124static void memex(void);
125static int bsesc(void);
126static void dump(void);
Balbir Singh80eff6c2017-10-30 22:01:12 +1100127static void show_pte(unsigned long);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128static void prdump(unsigned long, long);
129static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000130static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100131
132#ifdef CONFIG_PPC_POWERNV
133static void dump_opal_msglog(void);
134#else
135static inline void dump_opal_msglog(void)
136{
137 printf("Machine is not running OPAL firmware.\n");
138}
139#endif
140
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static void backtrace(struct pt_regs *);
142static void excprint(struct pt_regs *);
143static void prregs(struct pt_regs *);
144static void memops(int);
145static void memlocate(void);
146static void memzcan(void);
147static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
148int skipbl(void);
149int scanhex(unsigned long *valp);
150static void scannl(void);
151static int hexdigit(int);
152void getstring(char *, int);
153static void flush_input(void);
154static int inchar(void);
155static void take_input(char *);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000156static int read_spr(int, unsigned long *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157static void write_spr(int, unsigned long);
158static void super_regs(void);
159static void remove_bpts(void);
160static void insert_bpts(void);
161static void remove_cpu_bpts(void);
162static void insert_cpu_bpts(void);
163static struct bpt *at_breakpoint(unsigned long pc);
164static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
165static int do_step(struct pt_regs *);
166static void bpt_cmds(void);
167static void cacheflush(void);
168static int cpu_cmd(void);
169static void csum(void);
170static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000171static void proccall(void);
Douglas Miller6dfb5402015-11-23 09:01:15 -0600172static void show_tasks(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173void dump_segments(void);
174static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200175static void xmon_show_stack(unsigned long sp, unsigned long lr,
176 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177static void xmon_print_symbol(unsigned long address, const char *mid,
178 const char *after);
179static const char *getvecname(unsigned long vec);
180
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200181static int do_spu_cmd(void);
182
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100183#ifdef CONFIG_44x
184static void dump_tlb_44x(void);
185#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000186#ifdef CONFIG_PPC_BOOK3E
187static void dump_tlb_book3e(void);
188#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100189
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000190#ifdef CONFIG_PPC64
191#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000192#else
193#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000194#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100196#ifdef __LITTLE_ENDIAN__
197#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
198#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100200#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202static char *help_string = "\
203Commands:\n\
204 b show breakpoints\n\
205 bd set data breakpoint\n\
206 bi set instruction breakpoint\n\
207 bc clear breakpoint\n"
208#ifdef CONFIG_SMP
209 "\
210 c print cpus stopped in xmon\n\
211 c# try to switch to cpu number h (in hex)\n"
212#endif
213 "\
214 C checksum\n\
215 d dump bytes\n\
Douglas Miller5e48dc02017-02-07 07:40:44 -0600216 d1 dump 1 byte values\n\
217 d2 dump 2 byte values\n\
218 d4 dump 4 byte values\n\
219 d8 dump 8 byte values\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 di dump instructions\n\
221 df dump float values\n\
222 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000223 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100224#ifdef CONFIG_PPC_POWERNV
225 "\
226 do dump the OPAL message log\n"
227#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000228#ifdef CONFIG_PPC64
229 "\
230 dp[#] dump paca for current cpu, or cpu #\n\
231 dpa dump paca for all possible cpus\n"
232#endif
233 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100234 dr dump stream of raw bytes\n\
Balbir Singh80eff6c2017-10-30 22:01:12 +1100235 dv dump virtual address translation \n\
Michael Ellerman56144ec2015-11-06 13:21:17 +1100236 dt dump the tracing buffers (uses printk)\n\
Breno Leitao4125d012017-08-02 17:14:05 -0300237 dtc dump the tracing buffers for current CPU (uses printk)\n\
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +1000238"
239#ifdef CONFIG_PPC_POWERNV
240" dx# dump xive on CPU #\n\
241 dxi# dump xive irq state #\n\
242 dxa dump xive on all CPUs\n"
243#endif
244" e print exception information\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 f flush cache\n\
246 la lookup symbol+offset of specified address\n\
247 ls lookup address of specified symbol\n\
Boqun Feng302c7b02016-11-22 17:20:09 +0800248 lp s [#] lookup address of percpu symbol s for current cpu, or cpu #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 m examine/change memory\n\
250 mm move a block of memory\n\
251 ms set a block of memory\n\
252 md compare two blocks of memory\n\
253 ml locate a block of memory\n\
254 mz zero a block of memory\n\
255 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000256 p call a procedure\n\
Douglas Miller6dfb5402015-11-23 09:01:15 -0600257 P list processes/tasks\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200259 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100260#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200261" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200262 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100263 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900264 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100265 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200266#endif
267" S print special registers\n\
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000268 Sa print all SPRs\n\
269 Sr # read SPR #\n\
270 Sw #v write v to SPR #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100273 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000274#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000275" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000276#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000277" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000278#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100279" u dump TLB\n"
280#endif
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300281" U show uptime information\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000282" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100283" # n limit output to n lines per page (for dp, dpa, dl)\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000284" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 zh halt\n"
286;
287
288static struct pt_regs *xmon_regs;
289
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000290static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291{
292 asm volatile("sync; isync");
293}
294
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000295static inline void store_inst(void *p)
296{
297 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
298}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000300static inline void cflush(void *p)
301{
302 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
303}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000305static inline void cinval(void *p)
306{
307 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
308}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530310/**
311 * write_ciabr() - write the CIABR SPR
312 * @ciabr: The value to write.
313 *
314 * This function writes a value to the CIARB register either directly
315 * through mtspr instruction if the kernel is in HV privilege mode or
316 * call a hypervisor function to achieve the same in case the kernel
317 * is in supervisor privilege mode.
318 */
319static void write_ciabr(unsigned long ciabr)
320{
321 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
322 return;
323
324 if (cpu_has_feature(CPU_FTR_HVMODE)) {
325 mtspr(SPRN_CIABR, ciabr);
326 return;
327 }
Michael Ellerman7c09c182018-03-08 13:54:41 +1100328 plpar_set_ciabr(ciabr);
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530329}
330
331/**
332 * set_ciabr() - set the CIABR
333 * @addr: The value to set.
334 *
335 * This function sets the correct privilege value into the the HW
336 * breakpoint address before writing it up in the CIABR register.
337 */
338static void set_ciabr(unsigned long addr)
339{
340 addr &= ~CIABR_PRIV;
341
342 if (cpu_has_feature(CPU_FTR_HVMODE))
343 addr |= CIABR_PRIV_HYPER;
344 else
345 addr |= CIABR_PRIV_SUPER;
346 write_ciabr(addr);
347}
348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349/*
350 * Disable surveillance (the service processor watchdog function)
351 * while we are in xmon.
352 * XXX we should re-enable it when we leave. :)
353 */
354#define SURVEILLANCE_TOKEN 9000
355
356static inline void disable_surveillance(void)
357{
358#ifdef CONFIG_PPC_PSERIES
359 /* Since this can't be a module, args should end up below 4GB. */
360 static struct rtas_args args;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100361 int token;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
363 /*
364 * At this point we have got all the cpus we can into
365 * xmon, so there is hopefully no other cpu calling RTAS
366 * at the moment, even though we don't take rtas.lock.
367 * If we did try to take rtas.lock there would be a
368 * real possibility of deadlock.
369 */
Michael Ellerman08eb1052015-11-24 22:26:09 +1100370 token = rtas_token("set-indicator");
371 if (token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100373
374 rtas_call_unlocked(&args, token, 3, 1, NULL, SURVEILLANCE_TOKEN, 0, 0);
375
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376#endif /* CONFIG_PPC_PSERIES */
377}
378
379#ifdef CONFIG_SMP
380static int xmon_speaker;
381
382static void get_output_lock(void)
383{
384 int me = smp_processor_id() + 0x100;
385 int last_speaker = 0, prev;
386 long timeout;
387
388 if (xmon_speaker == me)
389 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100392 last_speaker = cmpxchg(&xmon_speaker, 0, me);
393 if (last_speaker == 0)
394 return;
395
Michael Ellerman15075892013-12-23 23:46:05 +1100396 /*
397 * Wait a full second for the lock, we might be on a slow
398 * console, but check every 100us.
399 */
400 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100402 if (--timeout > 0) {
403 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100405 }
406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 /* hostile takeover */
408 prev = cmpxchg(&xmon_speaker, last_speaker, me);
409 if (prev == last_speaker)
410 return;
411 break;
412 }
413 }
414}
415
416static void release_output_lock(void)
417{
418 xmon_speaker = 0;
419}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000420
421int cpus_are_in_xmon(void)
422{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000423 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000424}
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000425
426static bool wait_for_other_cpus(int ncpus)
427{
428 unsigned long timeout;
429
430 /* We wait for 2s, which is a metric "little while" */
431 for (timeout = 20000; timeout != 0; --timeout) {
432 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
433 return true;
434 udelay(100);
435 barrier();
436 }
437
438 return false;
439}
440#endif /* CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
Josh Boyerdaf8f402009-09-23 03:51:04 +0000442static inline int unrecoverable_excp(struct pt_regs *regs)
443{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000444#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000445 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000446 return 0;
447#else
448 return ((regs->msr & MSR_RI) == 0);
449#endif
450}
451
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000452static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453{
454 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 struct bpt *bp;
456 long recurse_jmp[JMP_BUF_LEN];
457 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100458 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459#ifdef CONFIG_SMP
460 int cpu;
461 int secondary;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462#endif
463
Anton Blanchardf13659e2007-03-21 01:48:34 +1100464 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000465 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Breno Leitaoed49f7f2017-08-02 17:14:06 -0300467 tracing_enabled = tracing_is_on();
468 tracing_off();
469
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 bp = in_breakpoint_table(regs->nip, &offset);
471 if (bp != NULL) {
472 regs->nip = bp->address + offset;
473 atomic_dec(&bp->ref_count);
474 }
475
476 remove_cpu_bpts();
477
478#ifdef CONFIG_SMP
479 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000480 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000481 /*
482 * We catch SPR read/write faults here because the 0x700, 0xf60
483 * etc. handlers don't call debugger_fault_handler().
484 */
485 if (catch_spr_faults)
486 longjmp(bus_error_jmp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 get_output_lock();
488 excprint(regs);
489 printf("cpu 0x%x: Exception %lx %s in xmon, "
490 "returning to main loop\n",
491 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000492 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 longjmp(xmon_fault_jmp[cpu], 1);
494 }
495
496 if (setjmp(recurse_jmp) != 0) {
497 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000498 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 printf("xmon: WARNING: bad recursive fault "
500 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000501 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 goto waiting;
503 }
504 secondary = !(xmon_taken && cpu == xmon_owner);
505 goto cmdloop;
506 }
507
508 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000511 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000513 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 fromipi = 0;
515
516 if (!fromipi) {
517 get_output_lock();
518 excprint(regs);
519 if (bp) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +0200520 printf("cpu 0x%x stopped at breakpoint 0x%tx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 cpu, BP_NUM(bp));
522 xmon_print_symbol(regs->nip, " ", ")\n");
523 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000524 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 printf("WARNING: exception is not recoverable, "
526 "can't continue\n");
527 release_output_lock();
528 }
529
Michael Ellermand2b496e2013-12-23 23:46:06 +1100530 cpumask_set_cpu(cpu, &cpus_in_xmon);
531
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 waiting:
533 secondary = 1;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000534 spin_begin();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 while (secondary && !xmon_gate) {
536 if (in_xmon == 0) {
Nicholas Piggin064996d2017-09-29 13:29:40 +1000537 if (fromipi) {
538 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 goto leave;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000540 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 secondary = test_and_set_bit(0, &in_xmon);
542 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000543 spin_cpu_relax();
544 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000546 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
548 if (!secondary && !xmon_gate) {
549 /* we are the first cpu to come in */
550 /* interrupt other cpu(s) */
551 int ncpus = num_online_cpus();
552
553 xmon_owner = cpu;
554 mb();
555 if (ncpus > 1) {
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000556 /*
557 * A system reset (trap == 0x100) can be triggered on
558 * all CPUs, so when we come in via 0x100 try waiting
559 * for the other CPUs to come in before we send the
560 * debugger break (IPI). This is similar to
561 * crash_kexec_secondary().
562 */
563 if (TRAP(regs) != 0x100 || !wait_for_other_cpus(ncpus))
564 smp_send_debugger_break();
565
566 wait_for_other_cpus(ncpus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 }
568 remove_bpts();
569 disable_surveillance();
570 /* for breakpoint or single step, print the current instr. */
571 if (bp || TRAP(regs) == 0xd00)
572 ppc_inst_dump(regs->nip, 1, 0);
573 printf("enter ? for help\n");
574 mb();
575 xmon_gate = 1;
576 barrier();
Nicholas Piggin064996d2017-09-29 13:29:40 +1000577 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 }
579
580 cmdloop:
581 while (in_xmon) {
582 if (secondary) {
Nicholas Piggin064996d2017-09-29 13:29:40 +1000583 spin_begin();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 if (cpu == xmon_owner) {
585 if (!test_and_set_bit(0, &xmon_taken)) {
586 secondary = 0;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000587 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 continue;
589 }
590 /* missed it */
591 while (cpu == xmon_owner)
Nicholas Piggin064996d2017-09-29 13:29:40 +1000592 spin_cpu_relax();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000594 spin_cpu_relax();
595 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 } else {
597 cmd = cmds(regs);
598 if (cmd != 0) {
599 /* exiting xmon */
600 insert_bpts();
601 xmon_gate = 0;
602 wmb();
603 in_xmon = 0;
604 break;
605 }
606 /* have switched to some other cpu */
607 secondary = 1;
608 }
609 }
610 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000611 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613#else
614 /* UP is simple... */
615 if (in_xmon) {
616 printf("Exception %lx %s in xmon, returning to main loop\n",
617 regs->trap, getvecname(TRAP(regs)));
618 longjmp(xmon_fault_jmp[0], 1);
619 }
620 if (setjmp(recurse_jmp) == 0) {
621 xmon_fault_jmp[0] = recurse_jmp;
622 in_xmon = 1;
623
624 excprint(regs);
625 bp = at_breakpoint(regs->nip);
626 if (bp) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +0200627 printf("Stopped at breakpoint %tx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 xmon_print_symbol(regs->nip, " ", ")\n");
629 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000630 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 printf("WARNING: exception is not recoverable, "
632 "can't continue\n");
633 remove_bpts();
634 disable_surveillance();
635 /* for breakpoint or single step, print the current instr. */
636 if (bp || TRAP(regs) == 0xd00)
637 ppc_inst_dump(regs->nip, 1, 0);
638 printf("enter ? for help\n");
639 }
640
641 cmd = cmds(regs);
642
643 insert_bpts();
644 in_xmon = 0;
645#endif
646
Josh Boyercdd39042009-10-05 04:46:05 +0000647#ifdef CONFIG_BOOKE
648 if (regs->msr & MSR_DE) {
649 bp = at_breakpoint(regs->nip);
650 if (bp != NULL) {
651 regs->nip = (unsigned long) &bp->instr[0];
652 atomic_inc(&bp->ref_count);
653 }
654 }
655#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000656 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 bp = at_breakpoint(regs->nip);
658 if (bp != NULL) {
659 int stepped = emulate_step(regs, bp->instr[0]);
660 if (stepped == 0) {
661 regs->nip = (unsigned long) &bp->instr[0];
662 atomic_inc(&bp->ref_count);
663 } else if (stepped < 0) {
664 printf("Couldn't single-step %s instruction\n",
665 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
666 }
667 }
668 }
Josh Boyercdd39042009-10-05 04:46:05 +0000669#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 insert_cpu_bpts();
671
Anton Blancharda71d64b2014-08-05 14:55:00 +1000672 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100673 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000675 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676}
677
678int xmon(struct pt_regs *excp)
679{
680 struct pt_regs regs;
681
682 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000683 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 excp = &regs;
685 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 return xmon_core(excp, 0);
688}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000689EXPORT_SYMBOL(xmon);
690
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000691irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000692{
693 unsigned long flags;
694 local_irq_save(flags);
695 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000696 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000697 local_irq_restore(flags);
698 return IRQ_HANDLED;
699}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000701static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
703 struct bpt *bp;
704 unsigned long offset;
705
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000706 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 return 0;
708
709 /* Are we at the trap at bp->instr[1] for some bp? */
710 bp = in_breakpoint_table(regs->nip, &offset);
711 if (bp != NULL && offset == 4) {
712 regs->nip = bp->address + 4;
713 atomic_dec(&bp->ref_count);
714 return 1;
715 }
716
717 /* Are we at a breakpoint? */
718 bp = at_breakpoint(regs->nip);
719 if (!bp)
720 return 0;
721
722 xmon_core(regs, 0);
723
724 return 1;
725}
726
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000727static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728{
729 if (user_mode(regs))
730 return 0;
731 xmon_core(regs, 0);
732 return 1;
733}
734
Michael Neuling9422de32012-12-20 14:06:44 +0000735static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000737 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000739 if (dabr.enabled == 0)
740 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 xmon_core(regs, 0);
742 return 1;
743}
744
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000745static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000747 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000749 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 return 0;
751 xmon_core(regs, 0);
752 return 1;
753}
754
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000755static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756{
757#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000758 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 xmon_core(regs, 1);
760#endif
761 return 0;
762}
763
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000764static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
766 struct bpt *bp;
767 unsigned long offset;
768
769 if (in_xmon && catch_memory_errors)
770 handle_fault(regs); /* doesn't return */
771
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000772 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 bp = in_breakpoint_table(regs->nip, &offset);
774 if (bp != NULL) {
775 regs->nip = bp->address + offset;
776 atomic_dec(&bp->ref_count);
777 }
778 }
779
780 return 0;
781}
782
Michal Suchanek7daf5932018-05-23 20:00:54 +0200783/* Force enable xmon if not already enabled */
784static inline void force_enable_xmon(void)
785{
786 /* Enable xmon hooks if needed */
787 if (!xmon_on) {
788 printf("xmon: Enabling debugger hooks\n");
789 xmon_on = 1;
790 }
791}
792
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793static struct bpt *at_breakpoint(unsigned long pc)
794{
795 int i;
796 struct bpt *bp;
797
798 bp = bpts;
799 for (i = 0; i < NBPTS; ++i, ++bp)
800 if (bp->enabled && pc == bp->address)
801 return bp;
802 return NULL;
803}
804
805static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
806{
807 unsigned long off;
808
809 off = nip - (unsigned long) bpts;
810 if (off >= sizeof(bpts))
811 return NULL;
812 off %= sizeof(struct bpt);
813 if (off != offsetof(struct bpt, instr[0])
814 && off != offsetof(struct bpt, instr[1]))
815 return NULL;
816 *offp = off - offsetof(struct bpt, instr[0]);
817 return (struct bpt *) (nip - off);
818}
819
820static struct bpt *new_breakpoint(unsigned long a)
821{
822 struct bpt *bp;
823
824 a &= ~3UL;
825 bp = at_breakpoint(a);
826 if (bp)
827 return bp;
828
829 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
830 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
831 bp->address = a;
832 bp->instr[1] = bpinstr;
833 store_inst(&bp->instr[1]);
834 return bp;
835 }
836 }
837
838 printf("Sorry, no free breakpoints. Please clear one first.\n");
839 return NULL;
840}
841
842static void insert_bpts(void)
843{
844 int i;
845 struct bpt *bp;
846
847 bp = bpts;
848 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100849 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 continue;
851 if (mread(bp->address, &bp->instr[0], 4) != 4) {
852 printf("Couldn't read instruction at %lx, "
853 "disabling breakpoint there\n", bp->address);
854 bp->enabled = 0;
855 continue;
856 }
857 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
858 printf("Breakpoint at %lx is on an mtmsrd or rfid "
859 "instruction, disabling it\n", bp->address);
860 bp->enabled = 0;
861 continue;
862 }
863 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100864 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 continue;
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000866 if (patch_instruction((unsigned int *)bp->address,
867 bpinstr) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 printf("Couldn't write instruction at %lx, "
869 "disabling breakpoint there\n", bp->address);
870 bp->enabled &= ~BP_TRAP;
871 continue;
872 }
873 store_inst((void *)bp->address);
874 }
875}
876
877static void insert_cpu_bpts(void)
878{
Michael Neuling9422de32012-12-20 14:06:44 +0000879 struct arch_hw_breakpoint brk;
880
881 if (dabr.enabled) {
882 brk.address = dabr.address;
883 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
884 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400885 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000886 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530887
888 if (iabr)
889 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890}
891
892static void remove_bpts(void)
893{
894 int i;
895 struct bpt *bp;
896 unsigned instr;
897
898 bp = bpts;
899 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100900 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 continue;
902 if (mread(bp->address, &instr, 4) == 4
903 && instr == bpinstr
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000904 && patch_instruction(
905 (unsigned int *)bp->address, bp->instr[0]) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 printf("Couldn't remove breakpoint at %lx\n",
907 bp->address);
908 else
909 store_inst((void *)bp->address);
910 }
911}
912
913static void remove_cpu_bpts(void)
914{
Michael Neuling9422de32012-12-20 14:06:44 +0000915 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530916 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917}
918
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300919/* Based on uptime_proc_show(). */
920static void
921show_uptime(void)
922{
Arnd Bergmannf6bd74f2018-06-18 11:56:24 +0200923 struct timespec64 uptime;
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300924
925 if (setjmp(bus_error_jmp) == 0) {
926 catch_memory_errors = 1;
927 sync();
928
Arnd Bergmannf6bd74f2018-06-18 11:56:24 +0200929 ktime_get_coarse_boottime_ts64(&uptime);
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300930 printf("Uptime: %lu.%.2lu seconds\n", (unsigned long)uptime.tv_sec,
931 ((unsigned long)uptime.tv_nsec / (NSEC_PER_SEC/100)));
932
933 sync();
934 __delay(200); \
935 }
936 catch_memory_errors = 0;
937}
938
Sam bobroff958b7c82015-10-08 11:50:23 +1100939static void set_lpp_cmd(void)
940{
941 unsigned long lpp;
942
943 if (!scanhex(&lpp)) {
944 printf("Invalid number.\n");
945 lpp = 0;
946 }
947 xmon_set_pagination_lpp(lpp);
948}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949/* Command interpreting routine */
950static char *last_cmd;
951
952static int
953cmds(struct pt_regs *excp)
954{
955 int cmd = 0;
956
957 last_cmd = NULL;
958 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200959
Guilherme G. Piccolib5617832017-03-22 16:27:50 -0300960 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
Olaf Hering26c8af52006-09-08 16:29:21 +0200961
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 for(;;) {
963#ifdef CONFIG_SMP
964 printf("%x:", smp_processor_id());
965#endif /* CONFIG_SMP */
966 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 flush_input();
968 termch = 0;
969 cmd = skipbl();
970 if( cmd == '\n' ) {
971 if (last_cmd == NULL)
972 continue;
973 take_input(last_cmd);
974 last_cmd = NULL;
975 cmd = inchar();
976 }
977 switch (cmd) {
978 case 'm':
979 cmd = inchar();
980 switch (cmd) {
981 case 'm':
982 case 's':
983 case 'd':
984 memops(cmd);
985 break;
986 case 'l':
987 memlocate();
988 break;
989 case 'z':
990 memzcan();
991 break;
992 case 'i':
Michal Hocko9af744d2017-02-22 15:46:16 -0800993 show_mem(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 break;
995 default:
996 termch = cmd;
997 memex();
998 }
999 break;
1000 case 'd':
1001 dump();
1002 break;
1003 case 'l':
1004 symbol_lookup();
1005 break;
1006 case 'r':
1007 prregs(excp); /* print regs */
1008 break;
1009 case 'e':
1010 excprint(excp);
1011 break;
1012 case 'S':
1013 super_regs();
1014 break;
1015 case 't':
1016 backtrace(excp);
1017 break;
1018 case 'f':
1019 cacheflush();
1020 break;
1021 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +02001022 if (do_spu_cmd() == 0)
1023 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 if (do_step(excp))
1025 return cmd;
1026 break;
1027 case 'x':
1028 case 'X':
Breno Leitaoed49f7f2017-08-02 17:14:06 -03001029 if (tracing_enabled)
1030 tracing_on();
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001031 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001033 printf(" <no input ...>\n");
1034 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 return cmd;
1036 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +10001037 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 break;
Sam bobroff958b7c82015-10-08 11:50:23 +11001039 case '#':
1040 set_lpp_cmd();
1041 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 case 'b':
1043 bpt_cmds();
1044 break;
1045 case 'C':
1046 csum();
1047 break;
1048 case 'c':
1049 if (cpu_cmd())
1050 return 0;
1051 break;
1052 case 'z':
1053 bootcmds();
1054 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001055 case 'p':
1056 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -06001058 case 'P':
1059 show_tasks();
1060 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001061#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 case 'u':
1063 dump_segments();
1064 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +11001065#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11001066 case 'u':
1067 dump_tlb_44x();
1068 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +00001069#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10001070 case 'u':
1071 dump_tlb_book3e();
1072 break;
1073#endif
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -03001074 case 'U':
1075 show_uptime();
1076 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 default:
1078 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +00001079 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if (' ' < cmd && cmd <= '~')
1081 putchar(cmd);
1082 else
1083 printf("\\x%x", cmd);
1084 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +00001085 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 printf(" (type ? for help)\n");
1087 break;
1088 }
1089 }
1090}
1091
Josh Boyercdd39042009-10-05 04:46:05 +00001092#ifdef CONFIG_BOOKE
1093static int do_step(struct pt_regs *regs)
1094{
1095 regs->msr |= MSR_DE;
1096 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1097 return 1;
1098}
1099#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100/*
1101 * Step a single instruction.
1102 * Some instructions we emulate, others we execute with MSR_SE set.
1103 */
1104static int do_step(struct pt_regs *regs)
1105{
1106 unsigned int instr;
1107 int stepped;
1108
Michal Suchanek7daf5932018-05-23 20:00:54 +02001109 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001111 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 if (mread(regs->nip, &instr, 4) == 4) {
1113 stepped = emulate_step(regs, instr);
1114 if (stepped < 0) {
1115 printf("Couldn't single-step %s instruction\n",
1116 (IS_RFID(instr)? "rfid": "mtmsrd"));
1117 return 0;
1118 }
1119 if (stepped > 0) {
1120 regs->trap = 0xd00 | (regs->trap & 1);
1121 printf("stepped to ");
1122 xmon_print_symbol(regs->nip, " ", "\n");
1123 ppc_inst_dump(regs->nip, 1, 0);
1124 return 0;
1125 }
1126 }
1127 }
1128 regs->msr |= MSR_SE;
1129 return 1;
1130}
Josh Boyercdd39042009-10-05 04:46:05 +00001131#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133static void bootcmds(void)
1134{
1135 int cmd;
1136
1137 cmd = inchar();
1138 if (cmd == 'r')
1139 ppc_md.restart(NULL);
1140 else if (cmd == 'h')
1141 ppc_md.halt();
1142 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001143 if (pm_power_off)
1144 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145}
1146
1147static int cpu_cmd(void)
1148{
1149#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001150 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
1153 if (!scanhex(&cpu)) {
1154 /* print cpus waiting or in xmon */
1155 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001156 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001157 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001158 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001159 if (cpu == last_cpu + 1) {
1160 last_cpu = cpu;
1161 } else {
1162 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001163 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001164 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001165 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 }
1168 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001169 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001170 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 printf("\n");
1172 return 0;
1173 }
1174 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001175 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001176 printf("cpu 0x%lx isn't in xmon\n", cpu);
Michael Ellerman7b087292018-05-02 23:07:26 +10001177#ifdef CONFIG_PPC64
1178 printf("backtrace of paca[0x%lx].saved_r1 (possibly stale):\n", cpu);
1179 xmon_show_stack(paca_ptrs[cpu]->saved_r1, 0, 0);
1180#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 return 0;
1182 }
1183 xmon_taken = 0;
1184 mb();
1185 xmon_owner = cpu;
1186 timeout = 10000000;
1187 while (!xmon_taken) {
1188 if (--timeout == 0) {
1189 if (test_and_set_bit(0, &xmon_taken))
1190 break;
1191 /* take control back */
1192 mb();
1193 xmon_owner = smp_processor_id();
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001194 printf("cpu 0x%lx didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 return 0;
1196 }
1197 barrier();
1198 }
1199 return 1;
1200#else
1201 return 0;
1202#endif /* CONFIG_SMP */
1203}
1204
1205static unsigned short fcstab[256] = {
1206 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1207 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1208 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1209 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1210 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1211 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1212 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1213 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1214 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1215 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1216 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1217 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1218 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1219 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1220 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1221 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1222 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1223 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1224 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1225 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1226 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1227 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1228 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1229 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1230 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1231 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1232 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1233 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1234 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1235 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1236 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1237 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1238};
1239
1240#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1241
1242static void
1243csum(void)
1244{
1245 unsigned int i;
1246 unsigned short fcs;
1247 unsigned char v;
1248
1249 if (!scanhex(&adrs))
1250 return;
1251 if (!scanhex(&ncsum))
1252 return;
1253 fcs = 0xffff;
1254 for (i = 0; i < ncsum; ++i) {
1255 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001256 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 break;
1258 }
1259 fcs = FCS(fcs, v);
1260 }
1261 printf("%x\n", fcs);
1262}
1263
1264/*
1265 * Check if this is a suitable place to put a breakpoint.
1266 */
1267static long check_bp_loc(unsigned long addr)
1268{
1269 unsigned int instr;
1270
1271 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001272 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 printf("Breakpoints may only be placed at kernel addresses\n");
1274 return 0;
1275 }
1276 if (!mread(addr, &instr, sizeof(instr))) {
1277 printf("Can't read instruction at address %lx\n", addr);
1278 return 0;
1279 }
1280 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1281 printf("Breakpoints may not be placed on mtmsrd or rfid "
1282 "instructions\n");
1283 return 0;
1284 }
1285 return 1;
1286}
1287
Michael Ellermane3bc8042012-08-23 22:09:13 +00001288static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 "Breakpoint command usage:\n"
1290 "b show breakpoints\n"
1291 "b <addr> [cnt] set breakpoint at given instr addr\n"
1292 "bc clear all breakpoints\n"
1293 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301294 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 "bd <addr> [cnt] set hardware data breakpoint\n"
1296 "";
1297
1298static void
1299bpt_cmds(void)
1300{
1301 int cmd;
1302 unsigned long a;
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001303 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 struct bpt *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
1306 cmd = inchar();
1307 switch (cmd) {
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001308#ifndef CONFIG_PPC_8xx
1309 static const char badaddr[] = "Only kernel addresses are permitted for breakpoints\n";
1310 int mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 case 'd': /* bd - hardware data breakpoint */
Michael Neuling9bc2bd52018-03-27 15:37:19 +11001312 if (!ppc_breakpoint_available()) {
1313 printf("Hardware data breakpoint not supported on this cpu\n");
1314 break;
1315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 mode = 7;
1317 cmd = inchar();
1318 if (cmd == 'r')
1319 mode = 5;
1320 else if (cmd == 'w')
1321 mode = 6;
1322 else
1323 termch = cmd;
1324 dabr.address = 0;
1325 dabr.enabled = 0;
1326 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001327 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 printf(badaddr);
1329 break;
1330 }
Michael Neuling9422de32012-12-20 14:06:44 +00001331 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 dabr.enabled = mode | BP_DABR;
1333 }
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301334
1335 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 break;
1337
1338 case 'i': /* bi - hardware instr breakpoint */
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301339 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 printf("Hardware instruction breakpoint "
1341 "not supported on this cpu\n");
1342 break;
1343 }
1344 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001345 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 iabr = NULL;
1347 }
1348 if (!scanhex(&a))
1349 break;
1350 if (!check_bp_loc(a))
1351 break;
1352 bp = new_breakpoint(a);
1353 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001354 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 iabr = bp;
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301356 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 }
1358 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001359#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
1361 case 'c':
1362 if (!scanhex(&a)) {
1363 /* clear all breakpoints */
1364 for (i = 0; i < NBPTS; ++i)
1365 bpts[i].enabled = 0;
1366 iabr = NULL;
1367 dabr.enabled = 0;
1368 printf("All breakpoints cleared\n");
1369 break;
1370 }
1371
1372 if (a <= NBPTS && a >= 1) {
1373 /* assume a breakpoint number */
1374 bp = &bpts[a-1]; /* bp nums are 1 based */
1375 } else {
1376 /* assume a breakpoint address */
1377 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001378 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001379 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 break;
1381 }
1382 }
1383
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001384 printf("Cleared breakpoint %tx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 xmon_print_symbol(bp->address, " ", ")\n");
1386 bp->enabled = 0;
1387 break;
1388
1389 default:
1390 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001391 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 if (cmd == '?') {
1393 printf(breakpoint_help_string);
1394 break;
1395 }
1396 termch = cmd;
1397 if (!scanhex(&a)) {
1398 /* print all breakpoints */
1399 printf(" type address\n");
1400 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001401 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 if (dabr.enabled & 1)
1403 printf("r");
1404 if (dabr.enabled & 2)
1405 printf("w");
1406 printf("]\n");
1407 }
1408 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1409 if (!bp->enabled)
1410 continue;
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001411 printf("%tx %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001412 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 xmon_print_symbol(bp->address, " ", "\n");
1414 }
1415 break;
1416 }
1417
1418 if (!check_bp_loc(a))
1419 break;
1420 bp = new_breakpoint(a);
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301421 if (bp != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 bp->enabled |= BP_TRAP;
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301423 force_enable_xmon();
1424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 break;
1426 }
1427}
1428
1429/* Very cheap human name for vector lookup. */
1430static
1431const char *getvecname(unsigned long vec)
1432{
1433 char *ret;
1434
1435 switch (vec) {
1436 case 0x100: ret = "(System Reset)"; break;
1437 case 0x200: ret = "(Machine Check)"; break;
1438 case 0x300: ret = "(Data Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001439 case 0x380:
1440 if (radix_enabled())
1441 ret = "(Data Access Out of Range)";
1442 else
1443 ret = "(Data SLB Access)";
1444 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 case 0x400: ret = "(Instruction Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001446 case 0x480:
1447 if (radix_enabled())
1448 ret = "(Instruction Access Out of Range)";
1449 else
1450 ret = "(Instruction SLB Access)";
1451 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 case 0x500: ret = "(Hardware Interrupt)"; break;
1453 case 0x600: ret = "(Alignment)"; break;
1454 case 0x700: ret = "(Program Check)"; break;
1455 case 0x800: ret = "(FPU Unavailable)"; break;
1456 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001457 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1458 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 case 0xc00: ret = "(System Call)"; break;
1460 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001461 case 0xe40: ret = "(Emulation Assist)"; break;
1462 case 0xe60: ret = "(HMI)"; break;
1463 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 case 0xf00: ret = "(Performance Monitor)"; break;
1465 case 0xf20: ret = "(Altivec Unavailable)"; break;
1466 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001467 case 0x1500: ret = "(Denormalisation)"; break;
1468 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 default: ret = "";
1470 }
1471 return ret;
1472}
1473
1474static void get_function_bounds(unsigned long pc, unsigned long *startp,
1475 unsigned long *endp)
1476{
1477 unsigned long size, offset;
1478 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
1480 *startp = *endp = 0;
1481 if (pc == 0)
1482 return;
1483 if (setjmp(bus_error_jmp) == 0) {
1484 catch_memory_errors = 1;
1485 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001486 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 if (name != NULL) {
1488 *startp = pc - offset;
1489 *endp = pc - offset + size;
1490 }
1491 sync();
1492 }
1493 catch_memory_errors = 0;
1494}
1495
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001496#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1497#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1498
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499static void xmon_show_stack(unsigned long sp, unsigned long lr,
1500 unsigned long pc)
1501{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001502 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 unsigned long ip;
1504 unsigned long newsp;
1505 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 struct pt_regs regs;
1507
Michael Ellerman0104cd62012-10-09 04:20:36 +00001508 while (max_to_print--) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301509 if (!is_kernel_addr(sp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 if (sp != 0)
1511 printf("SP (%lx) is in userspace\n", sp);
1512 break;
1513 }
1514
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001515 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 || !mread(sp, &newsp, sizeof(unsigned long))) {
1517 printf("Couldn't read stack frame at %lx\n", sp);
1518 break;
1519 }
1520
1521 /*
1522 * For the first stack frame, try to work out if
1523 * LR and/or the saved LR value in the bottommost
1524 * stack frame are valid.
1525 */
1526 if ((pc | lr) != 0) {
1527 unsigned long fnstart, fnend;
1528 unsigned long nextip;
1529 int printip = 1;
1530
1531 get_function_bounds(pc, &fnstart, &fnend);
1532 nextip = 0;
1533 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001534 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 sizeof(unsigned long));
1536 if (lr == ip) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301537 if (!is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 || (fnstart <= lr && lr < fnend))
1539 printip = 0;
1540 } else if (lr == nextip) {
1541 printip = 0;
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301542 } else if (is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 && !(fnstart <= lr && lr < fnend)) {
1544 printf("[link register ] ");
1545 xmon_print_symbol(lr, " ", "\n");
1546 }
1547 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001548 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 xmon_print_symbol(ip, " ", " (unreliable)\n");
1550 }
1551 pc = lr = 0;
1552
1553 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001554 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 xmon_print_symbol(ip, " ", "\n");
1556 }
1557
1558 /* Look for "regshere" marker to see if this is
1559 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001560 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001561 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001562 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 != sizeof(regs)) {
1564 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001565 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 break;
1567 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001568 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 getvecname(TRAP(&regs)));
1570 pc = regs.nip;
1571 lr = regs.link;
1572 xmon_print_symbol(pc, " ", "\n");
1573 }
1574
1575 if (newsp == 0)
1576 break;
1577
1578 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580}
1581
1582static void backtrace(struct pt_regs *excp)
1583{
1584 unsigned long sp;
1585
1586 if (scanhex(&sp))
1587 xmon_show_stack(sp, 0, 0);
1588 else
1589 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1590 scannl();
1591}
1592
1593static void print_bug_trap(struct pt_regs *regs)
1594{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001595#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001596 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 unsigned long addr;
1598
1599 if (regs->msr & MSR_PR)
1600 return; /* not in kernel */
1601 addr = regs->nip; /* address of trap instruction */
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301602 if (!is_kernel_addr(addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 return;
1604 bug = find_bug(regs->nip);
1605 if (bug == NULL)
1606 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001607 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 return;
1609
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001610#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001611 printf("kernel BUG at %s:%u!\n",
1612 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001613#else
Michael Ellermand8104182017-12-06 23:23:28 +11001614 printf("kernel BUG at %px!\n", (void *)bug->bug_addr);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001615#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001616#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617}
1618
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001619static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620{
1621 unsigned long trap;
1622
1623#ifdef CONFIG_SMP
1624 printf("cpu 0x%x: ", smp_processor_id());
1625#endif /* CONFIG_SMP */
1626
1627 trap = TRAP(fp);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001628 printf("Vector: %lx %s at [%px]\n", fp->trap, getvecname(trap), fp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 printf(" pc: ");
1630 xmon_print_symbol(fp->nip, ": ", "\n");
1631
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001632 printf(" lr: ");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 xmon_print_symbol(fp->link, ": ", "\n");
1634
1635 printf(" sp: %lx\n", fp->gpr[1]);
1636 printf(" msr: %lx\n", fp->msr);
1637
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001638 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 printf(" dar: %lx\n", fp->dar);
1640 if (trap != 0x380)
1641 printf(" dsisr: %lx\n", fp->dsisr);
1642 }
1643
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001644 printf(" current = 0x%px\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001645#ifdef CONFIG_PPC64
Nicholas Piggin3130a7b2018-05-10 11:04:24 +10001646 printf(" paca = 0x%px\t irqmask: 0x%02x\t irq_happened: 0x%02x\n",
Madhavan Srinivasan4e26bc42017-12-20 09:25:50 +05301647 local_paca, local_paca->irq_soft_mask, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001648#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 if (current) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001650 printf(" pid = %d, comm = %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 current->pid, current->comm);
1652 }
1653
1654 if (trap == 0x700)
1655 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001656
1657 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658}
1659
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001660static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001662 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 unsigned long base;
1664 struct pt_regs regs;
1665
1666 if (scanhex(&base)) {
1667 if (setjmp(bus_error_jmp) == 0) {
1668 catch_memory_errors = 1;
1669 sync();
1670 regs = *(struct pt_regs *)base;
1671 sync();
1672 __delay(200);
1673 } else {
1674 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001675 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 base);
1677 return;
1678 }
1679 catch_memory_errors = 0;
1680 fp = &regs;
1681 }
1682
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001683#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 if (FULL_REGS(fp)) {
1685 for (n = 0; n < 16; ++n)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001686 printf("R%.2d = "REG" R%.2d = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1688 } else {
1689 for (n = 0; n < 7; ++n)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001690 printf("R%.2d = "REG" R%.2d = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1692 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001693#else
1694 for (n = 0; n < 32; ++n) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001695 printf("R%.2d = %.8lx%s", n, fp->gpr[n],
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001696 (n & 3) == 3? "\n": " ");
1697 if (n == 12 && !FULL_REGS(fp)) {
1698 printf("\n");
1699 break;
1700 }
1701 }
1702#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 printf("pc = ");
1704 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001705 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1706 printf("cfar= ");
1707 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 printf("lr = ");
1710 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001711 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1712 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001714 trap = TRAP(fp);
1715 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1716 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717}
1718
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001719static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720{
1721 int cmd;
1722 unsigned long nflush;
1723
1724 cmd = inchar();
1725 if (cmd != 'i')
1726 termch = cmd;
1727 scanhex((void *)&adrs);
1728 if (termch != '\n')
1729 termch = 0;
1730 nflush = 1;
1731 scanhex(&nflush);
1732 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1733 if (setjmp(bus_error_jmp) == 0) {
1734 catch_memory_errors = 1;
1735 sync();
1736
1737 if (cmd != 'i') {
1738 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1739 cflush((void *) adrs);
1740 } else {
1741 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1742 cinval((void *) adrs);
1743 }
1744 sync();
1745 /* wait a little while to see if we get a machine check */
1746 __delay(200);
1747 }
1748 catch_memory_errors = 0;
1749}
1750
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001751extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1752extern void xmon_mtspr(int spr, unsigned long value);
1753
1754static int
1755read_spr(int n, unsigned long *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 unsigned long ret = -1UL;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001758 int ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
1760 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001761 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 sync();
1763
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001764 ret = xmon_mfspr(n, *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
1766 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001767 *vp = ret;
1768 ok = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001770 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001772 return ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773}
1774
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001775static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776write_spr(int n, unsigned long val)
1777{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001779 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 sync();
1781
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001782 xmon_mtspr(n, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783
1784 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001785 } else {
1786 printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001788 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789}
1790
Michael Ellerman18461932016-07-07 22:54:29 +10001791static void dump_206_sprs(void)
1792{
1793#ifdef CONFIG_PPC64
1794 if (!cpu_has_feature(CPU_FTR_ARCH_206))
1795 return;
1796
1797 /* Actually some of these pre-date 2.06, but whatevs */
1798
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001799 printf("srr0 = %.16lx srr1 = %.16lx dsisr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001800 mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001801 printf("dscr = %.16lx ppr = %.16lx pir = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001802 mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001803 printf("amr = %.16lx uamor = %.16lx\n",
1804 mfspr(SPRN_AMR), mfspr(SPRN_UAMOR));
Michael Ellerman18461932016-07-07 22:54:29 +10001805
1806 if (!(mfmsr() & MSR_HV))
1807 return;
1808
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001809 printf("sdr1 = %.16lx hdar = %.16lx hdsisr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001810 mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001811 printf("hsrr0 = %.16lx hsrr1 = %.16lx hdec = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001812 mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001813 printf("lpcr = %.16lx pcr = %.16lx lpidr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001814 mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001815 printf("hsprg0 = %.16lx hsprg1 = %.16lx amor = %.16lx\n",
1816 mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1), mfspr(SPRN_AMOR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001817 printf("dabr = %.16lx dabrx = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001818 mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
1819#endif
1820}
1821
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001822static void dump_207_sprs(void)
1823{
1824#ifdef CONFIG_PPC64
1825 unsigned long msr;
1826
1827 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
1828 return;
1829
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001830 printf("dpdes = %.16lx tir = %.16lx cir = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001831 mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
1832
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001833 printf("fscr = %.16lx tar = %.16lx pspb = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001834 mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
1835
1836 msr = mfmsr();
1837 if (msr & MSR_TM) {
1838 /* Only if TM has been enabled in the kernel */
Balbir Singhc47a9402017-08-29 17:22:36 +10001839 printf("tfhar = %.16lx tfiar = %.16lx texasr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001840 mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
1841 mfspr(SPRN_TEXASR));
1842 }
1843
Balbir Singhc47a9402017-08-29 17:22:36 +10001844 printf("mmcr0 = %.16lx mmcr1 = %.16lx mmcr2 = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001845 mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001846 printf("pmc1 = %.8lx pmc2 = %.8lx pmc3 = %.8lx pmc4 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001847 mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
1848 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001849 printf("mmcra = %.16lx siar = %.16lx pmc5 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001850 mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001851 printf("sdar = %.16lx sier = %.16lx pmc6 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001852 mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
Balbir Singhc47a9402017-08-29 17:22:36 +10001853 printf("ebbhr = %.16lx ebbrr = %.16lx bescr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001854 mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001855 printf("iamr = %.16lx\n", mfspr(SPRN_IAMR));
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001856
1857 if (!(msr & MSR_HV))
1858 return;
1859
Balbir Singhc47a9402017-08-29 17:22:36 +10001860 printf("hfscr = %.16lx dhdes = %.16lx rpr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001861 mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001862 printf("dawr = %.16lx dawrx = %.16lx ciabr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001863 mfspr(SPRN_DAWR), mfspr(SPRN_DAWRX), mfspr(SPRN_CIABR));
1864#endif
1865}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
Balbir Singhd1e1b352017-08-30 21:45:09 +10001867static void dump_300_sprs(void)
1868{
1869#ifdef CONFIG_PPC64
1870 bool hv = mfmsr() & MSR_HV;
1871
1872 if (!cpu_has_feature(CPU_FTR_ARCH_300))
1873 return;
1874
1875 printf("pidr = %.16lx tidr = %.16lx\n",
1876 mfspr(SPRN_PID), mfspr(SPRN_TIDR));
1877 printf("asdr = %.16lx psscr = %.16lx\n",
1878 mfspr(SPRN_ASDR), hv ? mfspr(SPRN_PSSCR)
1879 : mfspr(SPRN_PSSCR_PR));
1880
1881 if (!hv)
1882 return;
1883
1884 printf("ptcr = %.16lx\n",
1885 mfspr(SPRN_PTCR));
1886#endif
1887}
1888
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001889static void dump_one_spr(int spr, bool show_unimplemented)
1890{
1891 unsigned long val;
1892
1893 val = 0xdeadbeef;
1894 if (!read_spr(spr, &val)) {
1895 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1896 return;
1897 }
1898
1899 if (val == 0xdeadbeef) {
1900 /* Looks like read was a nop, confirm */
1901 val = 0x0badcafe;
1902 if (!read_spr(spr, &val)) {
1903 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1904 return;
1905 }
1906
1907 if (val == 0x0badcafe) {
1908 if (show_unimplemented)
1909 printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
1910 return;
1911 }
1912 }
1913
1914 printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
1915}
1916
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001917static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918{
Michael Ellerman13629da2016-07-07 22:54:27 +10001919 static unsigned long regno;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 int cmd;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001921 int spr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
1923 cmd = skipbl();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001924
1925 switch (cmd) {
1926 case '\n': {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001927 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 asm("mr %0,1" : "=r" (sp) :);
1929 asm("mr %0,2" : "=r" (toc) :);
1930
Michael Ellerman56346ad2016-07-07 22:54:28 +10001931 printf("msr = "REG" sprg0 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001932 mfmsr(), mfspr(SPRN_SPRG0));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001933 printf("pvr = "REG" sprg1 = "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001934 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001935 printf("dec = "REG" sprg2 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001936 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
Michael Ellerman56346ad2016-07-07 22:54:28 +10001937 printf("sp = "REG" sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
1938 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
1939
Michael Ellerman18461932016-07-07 22:54:29 +10001940 dump_206_sprs();
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001941 dump_207_sprs();
Balbir Singhd1e1b352017-08-30 21:45:09 +10001942 dump_300_sprs();
Michael Ellerman18461932016-07-07 22:54:29 +10001943
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 return;
1945 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001946 case 'w': {
1947 unsigned long val;
1948 scanhex(&regno);
1949 val = 0;
1950 read_spr(regno, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 scanhex(&val);
1952 write_spr(regno, val);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001953 dump_one_spr(regno, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001956 case 'r':
1957 scanhex(&regno);
1958 dump_one_spr(regno, true);
1959 break;
1960 case 'a':
1961 /* dump ALL SPRs */
1962 for (spr = 1; spr < 1024; ++spr)
1963 dump_one_spr(spr, false);
1964 break;
1965 }
1966
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 scannl();
1968}
1969
1970/*
1971 * Stuff for reading and writing memory safely
1972 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001973static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974mread(unsigned long adrs, void *buf, int size)
1975{
1976 volatile int n;
1977 char *p, *q;
1978
1979 n = 0;
1980 if (setjmp(bus_error_jmp) == 0) {
1981 catch_memory_errors = 1;
1982 sync();
1983 p = (char *)adrs;
1984 q = (char *)buf;
1985 switch (size) {
1986 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001987 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 break;
1989 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001990 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 break;
1992 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001993 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 break;
1995 default:
1996 for( ; n < size; ++n) {
1997 *q++ = *p++;
1998 sync();
1999 }
2000 }
2001 sync();
2002 /* wait a little while to see if we get a machine check */
2003 __delay(200);
2004 n = size;
2005 }
2006 catch_memory_errors = 0;
2007 return n;
2008}
2009
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002010static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011mwrite(unsigned long adrs, void *buf, int size)
2012{
2013 volatile int n;
2014 char *p, *q;
2015
2016 n = 0;
2017 if (setjmp(bus_error_jmp) == 0) {
2018 catch_memory_errors = 1;
2019 sync();
2020 p = (char *) adrs;
2021 q = (char *) buf;
2022 switch (size) {
2023 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002024 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 break;
2026 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002027 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 break;
2029 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002030 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 break;
2032 default:
2033 for ( ; n < size; ++n) {
2034 *p++ = *q++;
2035 sync();
2036 }
2037 }
2038 sync();
2039 /* wait a little while to see if we get a machine check */
2040 __delay(200);
2041 n = size;
2042 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10002043 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 }
2045 catch_memory_errors = 0;
2046 return n;
2047}
2048
2049static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002050static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051static char *fault_chars[] = { "--", "**", "##" };
2052
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002053static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002055 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 switch (TRAP(regs)) {
2057 case 0x200:
2058 fault_type = 0;
2059 break;
2060 case 0x300:
2061 case 0x380:
2062 fault_type = 1;
2063 break;
2064 default:
2065 fault_type = 2;
2066 }
2067
2068 longjmp(bus_error_jmp, 1);
2069
2070 return 0;
2071}
2072
2073#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
2074
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002075static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076byterev(unsigned char *val, int size)
2077{
2078 int t;
2079
2080 switch (size) {
2081 case 2:
2082 SWAP(val[0], val[1], t);
2083 break;
2084 case 4:
2085 SWAP(val[0], val[3], t);
2086 SWAP(val[1], val[2], t);
2087 break;
2088 case 8: /* is there really any use for this? */
2089 SWAP(val[0], val[7], t);
2090 SWAP(val[1], val[6], t);
2091 SWAP(val[2], val[5], t);
2092 SWAP(val[3], val[4], t);
2093 break;
2094 }
2095}
2096
2097static int brev;
2098static int mnoread;
2099
Michael Ellermane3bc8042012-08-23 22:09:13 +00002100static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 "Memory examine command usage:\n"
2102 "m [addr] [flags] examine/change memory\n"
2103 " addr is optional. will start where left off.\n"
2104 " flags may include chars from this set:\n"
2105 " b modify by bytes (default)\n"
2106 " w modify by words (2 byte)\n"
2107 " l modify by longs (4 byte)\n"
2108 " d modify by doubleword (8 byte)\n"
2109 " r toggle reverse byte order mode\n"
2110 " n do not read memory (for i/o spaces)\n"
2111 " . ok to read (default)\n"
2112 "NOTE: flags are saved as defaults\n"
2113 "";
2114
Michael Ellermane3bc8042012-08-23 22:09:13 +00002115static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 "Memory examine subcommands:\n"
2117 " hexval write this val to current location\n"
2118 " 'string' write chars from string to this location\n"
2119 " ' increment address\n"
2120 " ^ decrement address\n"
2121 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
2122 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
2123 " ` clear no-read flag\n"
2124 " ; stay at this addr\n"
2125 " v change to byte mode\n"
2126 " w change to word (2 byte) mode\n"
2127 " l change to long (4 byte) mode\n"
2128 " u change to doubleword (8 byte) mode\n"
2129 " m addr change current addr\n"
2130 " n toggle no-read flag\n"
2131 " r toggle byte reverse flag\n"
2132 " < count back up count bytes\n"
2133 " > count skip forward count bytes\n"
2134 " x exit this mode\n"
2135 "";
2136
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002137static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138memex(void)
2139{
2140 int cmd, inc, i, nslash;
2141 unsigned long n;
2142 unsigned char val[16];
2143
2144 scanhex((void *)&adrs);
2145 cmd = skipbl();
2146 if (cmd == '?') {
2147 printf(memex_help_string);
2148 return;
2149 } else {
2150 termch = cmd;
2151 }
2152 last_cmd = "m\n";
2153 while ((cmd = skipbl()) != '\n') {
2154 switch( cmd ){
2155 case 'b': size = 1; break;
2156 case 'w': size = 2; break;
2157 case 'l': size = 4; break;
2158 case 'd': size = 8; break;
2159 case 'r': brev = !brev; break;
2160 case 'n': mnoread = 1; break;
2161 case '.': mnoread = 0; break;
2162 }
2163 }
2164 if( size <= 0 )
2165 size = 1;
2166 else if( size > 8 )
2167 size = 8;
2168 for(;;){
2169 if (!mnoread)
2170 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002171 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 if (!mnoread) {
2173 if (brev)
2174 byterev(val, size);
2175 putchar(' ');
2176 for (i = 0; i < n; ++i)
2177 printf("%.2x", val[i]);
2178 for (; i < size; ++i)
2179 printf("%s", fault_chars[fault_type]);
2180 }
2181 putchar(' ');
2182 inc = size;
2183 nslash = 0;
2184 for(;;){
2185 if( scanhex(&n) ){
2186 for (i = 0; i < size; ++i)
2187 val[i] = n >> (i * 8);
2188 if (!brev)
2189 byterev(val, size);
2190 mwrite(adrs, val, size);
2191 inc = size;
2192 }
2193 cmd = skipbl();
2194 if (cmd == '\n')
2195 break;
2196 inc = 0;
2197 switch (cmd) {
2198 case '\'':
2199 for(;;){
2200 n = inchar();
2201 if( n == '\\' )
2202 n = bsesc();
2203 else if( n == '\'' )
2204 break;
2205 for (i = 0; i < size; ++i)
2206 val[i] = n >> (i * 8);
2207 if (!brev)
2208 byterev(val, size);
2209 mwrite(adrs, val, size);
2210 adrs += size;
2211 }
2212 adrs -= size;
2213 inc = size;
2214 break;
2215 case ',':
2216 adrs += size;
2217 break;
2218 case '.':
2219 mnoread = 0;
2220 break;
2221 case ';':
2222 break;
2223 case 'x':
2224 case EOF:
2225 scannl();
2226 return;
2227 case 'b':
2228 case 'v':
2229 size = 1;
2230 break;
2231 case 'w':
2232 size = 2;
2233 break;
2234 case 'l':
2235 size = 4;
2236 break;
2237 case 'u':
2238 size = 8;
2239 break;
2240 case '^':
2241 adrs -= size;
2242 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 case '/':
2244 if (nslash > 0)
2245 adrs -= 1 << nslash;
2246 else
2247 nslash = 0;
2248 nslash += 4;
2249 adrs += 1 << nslash;
2250 break;
2251 case '\\':
2252 if (nslash < 0)
2253 adrs += 1 << -nslash;
2254 else
2255 nslash = 0;
2256 nslash -= 4;
2257 adrs -= 1 << -nslash;
2258 break;
2259 case 'm':
2260 scanhex((void *)&adrs);
2261 break;
2262 case 'n':
2263 mnoread = 1;
2264 break;
2265 case 'r':
2266 brev = !brev;
2267 break;
2268 case '<':
2269 n = size;
2270 scanhex(&n);
2271 adrs -= n;
2272 break;
2273 case '>':
2274 n = size;
2275 scanhex(&n);
2276 adrs += n;
2277 break;
2278 case '?':
2279 printf(memex_subcmd_help_string);
2280 break;
2281 }
2282 }
2283 adrs += inc;
2284 }
2285}
2286
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002287static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288bsesc(void)
2289{
2290 int c;
2291
2292 c = inchar();
2293 switch( c ){
2294 case 'n': c = '\n'; break;
2295 case 'r': c = '\r'; break;
2296 case 'b': c = '\b'; break;
2297 case 't': c = '\t'; break;
2298 }
2299 return c;
2300}
2301
Olaf Hering7e5b5932006-03-08 20:40:28 +01002302static void xmon_rawdump (unsigned long adrs, long ndump)
2303{
2304 long n, m, r, nr;
2305 unsigned char temp[16];
2306
2307 for (n = ndump; n > 0;) {
2308 r = n < 16? n: 16;
2309 nr = mread(adrs, temp, r);
2310 adrs += nr;
2311 for (m = 0; m < r; ++m) {
2312 if (m < nr)
2313 printf("%.2x", temp[m]);
2314 else
2315 printf("%s", fault_chars[fault_type]);
2316 }
2317 n -= r;
2318 if (nr < r)
2319 break;
2320 }
2321 printf("\n");
2322}
2323
Breno Leitao4125d012017-08-02 17:14:05 -03002324static void dump_tracing(void)
2325{
2326 int c;
2327
2328 c = inchar();
2329 if (c == 'c')
2330 ftrace_dump(DUMP_ORIG);
2331 else
2332 ftrace_dump(DUMP_ALL);
Breno Leitao4125d012017-08-02 17:14:05 -03002333}
2334
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002335#ifdef CONFIG_PPC64
2336static void dump_one_paca(int cpu)
2337{
2338 struct paca_struct *p;
Michael Ellerman4e003742017-10-19 15:08:43 +11002339#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellermanad987fc2015-10-14 16:58:36 +11002340 int i = 0;
2341#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002342
2343 if (setjmp(bus_error_jmp) != 0) {
2344 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2345 return;
2346 }
2347
2348 catch_memory_errors = 1;
2349 sync();
2350
Nicholas Piggind2e60072018-02-14 01:08:12 +10002351 p = paca_ptrs[cpu];
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002352
Michael Ellermand8104182017-12-06 23:23:28 +11002353 printf("paca for cpu 0x%x @ %px:\n", cpu, p);
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002354
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002355 printf(" %-*s = %s\n", 25, "possible", cpu_possible(cpu) ? "yes" : "no");
2356 printf(" %-*s = %s\n", 25, "present", cpu_present(cpu) ? "yes" : "no");
2357 printf(" %-*s = %s\n", 25, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002358
Michael Ellerman66716832018-05-21 21:06:19 +10002359#define DUMP(paca, name, format) \
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002360 printf(" %-*s = "format"\t(0x%lx)\n", 25, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002361 offsetof(struct paca_struct, name));
2362
Michael Ellerman66716832018-05-21 21:06:19 +10002363 DUMP(p, lock_token, "%#-*x");
2364 DUMP(p, paca_index, "%#-*x");
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002365 DUMP(p, kernel_toc, "%#-*llx");
2366 DUMP(p, kernelbase, "%#-*llx");
2367 DUMP(p, kernel_msr, "%#-*llx");
Michael Ellerman66716832018-05-21 21:06:19 +10002368 DUMP(p, emergency_sp, "%-*px");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302369#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman66716832018-05-21 21:06:19 +10002370 DUMP(p, nmi_emergency_sp, "%-*px");
2371 DUMP(p, mc_emergency_sp, "%-*px");
2372 DUMP(p, in_nmi, "%#-*x");
2373 DUMP(p, in_mce, "%#-*x");
2374 DUMP(p, hmi_event_available, "%#-*x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302375#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002376 DUMP(p, data_offset, "%#-*llx");
Michael Ellerman66716832018-05-21 21:06:19 +10002377 DUMP(p, hw_cpu_id, "%#-*x");
2378 DUMP(p, cpu_start, "%#-*x");
2379 DUMP(p, kexec_state, "%#-*x");
Michael Ellerman4e003742017-10-19 15:08:43 +11002380#ifdef CONFIG_PPC_BOOK3S_64
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002381 if (!early_radix_enabled()) {
2382 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2383 u64 esid, vsid;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002384
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002385 if (!p->slb_shadow_ptr)
2386 continue;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002387
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002388 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2389 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
Michael Ellermanad987fc2015-10-14 16:58:36 +11002390
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002391 if (esid || vsid) {
2392 printf(" %-*s[%d] = 0x%016llx 0x%016llx\n",
2393 22, "slb_shadow", i, esid, vsid);
2394 }
Michael Ellermanad987fc2015-10-14 16:58:36 +11002395 }
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002396 DUMP(p, vmalloc_sllp, "%#-*x");
Michael Ellerman54be0b92018-10-02 23:56:39 +10002397 DUMP(p, stab_rr, "%#-*llx");
Nicholas Piggin82d8f4c2018-09-15 01:30:50 +10002398
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002399 if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) {
2400 DUMP(p, slb_cache_ptr, "%#-*x");
2401 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2402 printf(" %-*s[%d] = 0x%016x\n",
2403 22, "slb_cache", i, p->slb_cache[i]);
2404 }
Nicholas Piggin82d8f4c2018-09-15 01:30:50 +10002405 }
Michael Ellerman274920a2018-01-10 23:49:12 +11002406
Michael Ellerman66716832018-05-21 21:06:19 +10002407 DUMP(p, rfi_flush_fallback_area, "%-*px");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002408#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002409 DUMP(p, dscr_default, "%#-*llx");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002410#ifdef CONFIG_PPC_BOOK3E
Michael Ellerman66716832018-05-21 21:06:19 +10002411 DUMP(p, pgd, "%-*px");
2412 DUMP(p, kernel_pgd, "%-*px");
2413 DUMP(p, tcd_ptr, "%-*px");
2414 DUMP(p, mc_kstack, "%-*px");
2415 DUMP(p, crit_kstack, "%-*px");
2416 DUMP(p, dbg_kstack, "%-*px");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002417#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002418 DUMP(p, __current, "%-*px");
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002419 DUMP(p, kstack, "%#-*llx");
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002420 printf(" %-*s = 0x%016llx\n", 25, "kstack_base", p->kstack & ~(THREAD_SIZE - 1));
Michael Ellerman50530f52018-10-12 13:58:52 +11002421#ifdef CONFIG_STACKPROTECTOR
2422 DUMP(p, canary, "%#-*lx");
2423#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002424 DUMP(p, saved_r1, "%#-*llx");
Michael Ellerman66716832018-05-21 21:06:19 +10002425 DUMP(p, trap_save, "%#-*x");
2426 DUMP(p, irq_soft_mask, "%#-*x");
2427 DUMP(p, irq_happened, "%#-*x");
2428 DUMP(p, io_sync, "%#-*x");
2429 DUMP(p, irq_work_pending, "%#-*x");
2430 DUMP(p, nap_state_lost, "%#-*x");
2431 DUMP(p, sprg_vdso, "%#-*llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002432
Michael Ellermanad987fc2015-10-14 16:58:36 +11002433#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
Michael Ellerman66716832018-05-21 21:06:19 +10002434 DUMP(p, tm_scratch, "%#-*llx");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002435#endif
2436
2437#ifdef CONFIG_PPC_POWERNV
Michael Ellerman66716832018-05-21 21:06:19 +10002438 DUMP(p, core_idle_state_ptr, "%-*px");
2439 DUMP(p, thread_idle_state, "%#-*x");
2440 DUMP(p, thread_mask, "%#-*x");
2441 DUMP(p, subcore_sibling_mask, "%#-*x");
Michael Ellerman2e0986d2018-05-21 19:47:20 +10002442 DUMP(p, requested_psscr, "%#-*llx");
2443 DUMP(p, stop_sprs.pid, "%#-*llx");
2444 DUMP(p, stop_sprs.ldbar, "%#-*llx");
2445 DUMP(p, stop_sprs.fscr, "%#-*llx");
2446 DUMP(p, stop_sprs.hfscr, "%#-*llx");
2447 DUMP(p, stop_sprs.mmcr1, "%#-*llx");
2448 DUMP(p, stop_sprs.mmcr2, "%#-*llx");
2449 DUMP(p, stop_sprs.mmcra, "%#-*llx");
2450 DUMP(p, dont_stop.counter, "%#-*x");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002451#endif
2452
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002453 DUMP(p, accounting.utime, "%#-*lx");
2454 DUMP(p, accounting.stime, "%#-*lx");
2455 DUMP(p, accounting.utime_scaled, "%#-*lx");
2456 DUMP(p, accounting.starttime, "%#-*lx");
2457 DUMP(p, accounting.starttime_user, "%#-*lx");
2458 DUMP(p, accounting.startspurr, "%#-*lx");
2459 DUMP(p, accounting.utime_sspurr, "%#-*lx");
2460 DUMP(p, accounting.steal_time, "%#-*lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002461#undef DUMP
2462
2463 catch_memory_errors = 0;
2464 sync();
2465}
2466
2467static void dump_all_pacas(void)
2468{
2469 int cpu;
2470
2471 if (num_possible_cpus() == 0) {
2472 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2473 return;
2474 }
2475
2476 for_each_possible_cpu(cpu)
2477 dump_one_paca(cpu);
2478}
2479
2480static void dump_pacas(void)
2481{
2482 unsigned long num;
2483 int c;
2484
2485 c = inchar();
2486 if (c == 'a') {
2487 dump_all_pacas();
2488 return;
2489 }
2490
2491 termch = c; /* Put c back, it wasn't 'a' */
2492
2493 if (scanhex(&num))
2494 dump_one_paca(num);
2495 else
2496 dump_one_paca(xmon_owner);
2497}
2498#endif
2499
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002500#ifdef CONFIG_PPC_POWERNV
2501static void dump_one_xive(int cpu)
2502{
2503 unsigned int hwid = get_hard_smp_processor_id(cpu);
2504
2505 opal_xive_dump(XIVE_DUMP_TM_HYP, hwid);
2506 opal_xive_dump(XIVE_DUMP_TM_POOL, hwid);
2507 opal_xive_dump(XIVE_DUMP_TM_OS, hwid);
2508 opal_xive_dump(XIVE_DUMP_TM_USER, hwid);
2509 opal_xive_dump(XIVE_DUMP_VP, hwid);
2510 opal_xive_dump(XIVE_DUMP_EMU_STATE, hwid);
2511
2512 if (setjmp(bus_error_jmp) != 0) {
2513 catch_memory_errors = 0;
2514 printf("*** Error dumping xive on cpu %d\n", cpu);
2515 return;
2516 }
2517
2518 catch_memory_errors = 1;
2519 sync();
2520 xmon_xive_do_dump(cpu);
2521 sync();
2522 __delay(200);
2523 catch_memory_errors = 0;
2524}
2525
2526static void dump_all_xives(void)
2527{
2528 int cpu;
2529
2530 if (num_possible_cpus() == 0) {
2531 printf("No possible cpus, use 'dx #' to dump individual cpus\n");
2532 return;
2533 }
2534
2535 for_each_possible_cpu(cpu)
2536 dump_one_xive(cpu);
2537}
2538
2539static void dump_one_xive_irq(u32 num)
2540{
2541 s64 rc;
2542 __be64 vp;
2543 u8 prio;
2544 __be32 lirq;
2545
2546 rc = opal_xive_get_irq_config(num, &vp, &prio, &lirq);
2547 xmon_printf("IRQ 0x%x config: vp=0x%llx prio=%d lirq=0x%x (rc=%lld)\n",
2548 num, be64_to_cpu(vp), prio, be32_to_cpu(lirq), rc);
2549}
2550
2551static void dump_xives(void)
2552{
2553 unsigned long num;
2554 int c;
2555
Breno Leitao402e1722017-10-17 16:20:18 -02002556 if (!xive_enabled()) {
2557 printf("Xive disabled on this system\n");
2558 return;
2559 }
2560
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002561 c = inchar();
2562 if (c == 'a') {
2563 dump_all_xives();
2564 return;
2565 } else if (c == 'i') {
2566 if (scanhex(&num))
2567 dump_one_xive_irq(num);
2568 return;
2569 }
2570
2571 termch = c; /* Put c back, it wasn't 'a' */
2572
2573 if (scanhex(&num))
2574 dump_one_xive(num);
2575 else
2576 dump_one_xive(xmon_owner);
2577}
2578#endif /* CONFIG_PPC_POWERNV */
2579
Douglas Miller5e48dc02017-02-07 07:40:44 -06002580static void dump_by_size(unsigned long addr, long count, int size)
2581{
2582 unsigned char temp[16];
2583 int i, j;
2584 u64 val;
2585
2586 count = ALIGN(count, 16);
2587
2588 for (i = 0; i < count; i += 16, addr += 16) {
2589 printf(REG, addr);
2590
2591 if (mread(addr, temp, 16) != 16) {
2592 printf("\nFaulted reading %d bytes from 0x"REG"\n", 16, addr);
2593 return;
2594 }
2595
2596 for (j = 0; j < 16; j += size) {
2597 putchar(' ');
2598 switch (size) {
2599 case 1: val = temp[j]; break;
2600 case 2: val = *(u16 *)&temp[j]; break;
2601 case 4: val = *(u32 *)&temp[j]; break;
2602 case 8: val = *(u64 *)&temp[j]; break;
2603 default: val = 0;
2604 }
2605
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002606 printf("%0*llx", size * 2, val);
Douglas Miller5e48dc02017-02-07 07:40:44 -06002607 }
2608 printf("\n");
2609 }
2610}
2611
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002612static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613dump(void)
2614{
Douglas Miller5e48dc02017-02-07 07:40:44 -06002615 static char last[] = { "d?\n" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 int c;
2617
2618 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002619
2620#ifdef CONFIG_PPC64
2621 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002622 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002623 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002624 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002625 return;
2626 }
2627#endif
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002628#ifdef CONFIG_PPC_POWERNV
2629 if (c == 'x') {
2630 xmon_start_pagination();
2631 dump_xives();
2632 xmon_end_pagination();
2633 return;
2634 }
2635#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002636
Breno Leitao4125d012017-08-02 17:14:05 -03002637 if (c == 't') {
2638 dump_tracing();
2639 return;
2640 }
2641
Douglas Miller5e48dc02017-02-07 07:40:44 -06002642 if (c == '\n')
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 termch = c;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002644
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 scanhex((void *)&adrs);
2646 if (termch != '\n')
2647 termch = 0;
2648 if (c == 'i') {
2649 scanhex(&nidump);
2650 if (nidump == 0)
2651 nidump = 16;
2652 else if (nidump > MAX_DUMP)
2653 nidump = MAX_DUMP;
2654 adrs += ppc_inst_dump(adrs, nidump, 1);
2655 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002656 } else if (c == 'l') {
2657 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002658 } else if (c == 'o') {
2659 dump_opal_msglog();
Balbir Singh80eff6c2017-10-30 22:01:12 +11002660 } else if (c == 'v') {
2661 /* dump virtual to physical translation */
2662 show_pte(adrs);
Olaf Hering7e5b5932006-03-08 20:40:28 +01002663 } else if (c == 'r') {
2664 scanhex(&ndump);
2665 if (ndump == 0)
2666 ndump = 64;
2667 xmon_rawdump(adrs, ndump);
2668 adrs += ndump;
2669 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 } else {
2671 scanhex(&ndump);
2672 if (ndump == 0)
2673 ndump = 64;
2674 else if (ndump > MAX_DUMP)
2675 ndump = MAX_DUMP;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002676
2677 switch (c) {
2678 case '8':
2679 case '4':
2680 case '2':
2681 case '1':
2682 ndump = ALIGN(ndump, 16);
2683 dump_by_size(adrs, ndump, c - '0');
2684 last[1] = c;
2685 last_cmd = last;
2686 break;
2687 default:
2688 prdump(adrs, ndump);
2689 last_cmd = "d\n";
2690 }
2691
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 adrs += ndump;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 }
2694}
2695
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002696static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697prdump(unsigned long adrs, long ndump)
2698{
2699 long n, m, c, r, nr;
2700 unsigned char temp[16];
2701
2702 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002703 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 putchar(' ');
2705 r = n < 16? n: 16;
2706 nr = mread(adrs, temp, r);
2707 adrs += nr;
2708 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002709 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002710 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 if (m < nr)
2712 printf("%.2x", temp[m]);
2713 else
2714 printf("%s", fault_chars[fault_type]);
2715 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002716 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002717 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002718 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002720 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 printf(" |");
2722 for (m = 0; m < r; ++m) {
2723 if (m < nr) {
2724 c = temp[m];
2725 putchar(' ' <= c && c <= '~'? c: '.');
2726 } else
2727 putchar(' ');
2728 }
2729 n -= r;
2730 for (; m < 16; ++m)
2731 putchar(' ');
2732 printf("|\n");
2733 if (nr < r)
2734 break;
2735 }
2736}
2737
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002738typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2739
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002740static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002741generic_inst_dump(unsigned long adr, long count, int praddr,
2742 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743{
2744 int nr, dotted;
2745 unsigned long first_adr;
Michael Ellerman941d8102018-07-16 23:52:14 +10002746 unsigned int inst, last_inst = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 unsigned char val[4];
2748
2749 dotted = 0;
2750 for (first_adr = adr; count > 0; --count, adr += 4) {
2751 nr = mread(adr, val, 4);
2752 if (nr == 0) {
2753 if (praddr) {
2754 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002755 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 }
2757 break;
2758 }
2759 inst = GETWORD(val);
2760 if (adr > first_adr && inst == last_inst) {
2761 if (!dotted) {
2762 printf(" ...\n");
2763 dotted = 1;
2764 }
2765 continue;
2766 }
2767 dotted = 0;
2768 last_inst = inst;
2769 if (praddr)
Michael Ellerman941d8102018-07-16 23:52:14 +10002770 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002772 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 printf("\n");
2774 }
2775 return adr - first_adr;
2776}
2777
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002778static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002779ppc_inst_dump(unsigned long adr, long count, int praddr)
2780{
2781 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2782}
2783
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784void
2785print_address(unsigned long addr)
2786{
2787 xmon_print_symbol(addr, "\t# ", "");
2788}
2789
Vinay Sridharf312deb2009-05-14 23:13:07 +00002790void
2791dump_log_buf(void)
2792{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002793 struct kmsg_dumper dumper = { .active = 1 };
2794 unsigned char buf[128];
2795 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002796
Michael Ellermane3bc8042012-08-23 22:09:13 +00002797 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002798 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002799 return;
2800 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002801
Michael Ellermane3bc8042012-08-23 22:09:13 +00002802 catch_memory_errors = 1;
2803 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002804
Michael Ellermanca5dd392012-08-23 22:09:12 +00002805 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002806 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002807 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2808 buf[len] = '\0';
2809 printf("%s", buf);
2810 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002811 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002812
Michael Ellermane3bc8042012-08-23 22:09:13 +00002813 sync();
2814 /* wait a little while to see if we get a machine check */
2815 __delay(200);
2816 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002817}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002819#ifdef CONFIG_PPC_POWERNV
2820static void dump_opal_msglog(void)
2821{
2822 unsigned char buf[128];
2823 ssize_t res;
2824 loff_t pos = 0;
2825
2826 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2827 printf("Machine is not running OPAL firmware.\n");
2828 return;
2829 }
2830
2831 if (setjmp(bus_error_jmp) != 0) {
2832 printf("Error dumping OPAL msglog!\n");
2833 return;
2834 }
2835
2836 catch_memory_errors = 1;
2837 sync();
2838
2839 xmon_start_pagination();
2840 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2841 if (res < 0) {
2842 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2843 break;
2844 }
2845 buf[res] = '\0';
2846 printf("%s", buf);
2847 pos += res;
2848 }
2849 xmon_end_pagination();
2850
2851 sync();
2852 /* wait a little while to see if we get a machine check */
2853 __delay(200);
2854 catch_memory_errors = 0;
2855}
2856#endif
2857
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858/*
2859 * Memory operations - move, set, print differences
2860 */
2861static unsigned long mdest; /* destination address */
2862static unsigned long msrc; /* source address */
2863static unsigned long mval; /* byte value to set memory to */
2864static unsigned long mcount; /* # bytes to affect */
2865static unsigned long mdiffs; /* max # differences to print */
2866
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002867static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868memops(int cmd)
2869{
2870 scanhex((void *)&mdest);
2871 if( termch != '\n' )
2872 termch = 0;
2873 scanhex((void *)(cmd == 's'? &mval: &msrc));
2874 if( termch != '\n' )
2875 termch = 0;
2876 scanhex((void *)&mcount);
2877 switch( cmd ){
2878 case 'm':
2879 memmove((void *)mdest, (void *)msrc, mcount);
2880 break;
2881 case 's':
2882 memset((void *)mdest, mval, mcount);
2883 break;
2884 case 'd':
2885 if( termch != '\n' )
2886 termch = 0;
2887 scanhex((void *)&mdiffs);
2888 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2889 break;
2890 }
2891}
2892
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002893static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2895{
2896 unsigned n, prt;
2897
2898 prt = 0;
2899 for( n = nb; n > 0; --n )
2900 if( *p1++ != *p2++ )
2901 if( ++prt <= maxpr )
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002902 printf("%px %.2x # %px %.2x\n", p1 - 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 p1[-1], p2 - 1, p2[-1]);
2904 if( prt > maxpr )
2905 printf("Total of %d differences\n", prt);
2906}
2907
2908static unsigned mend;
2909static unsigned mask;
2910
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002911static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912memlocate(void)
2913{
2914 unsigned a, n;
2915 unsigned char val[4];
2916
2917 last_cmd = "ml";
2918 scanhex((void *)&mdest);
2919 if (termch != '\n') {
2920 termch = 0;
2921 scanhex((void *)&mend);
2922 if (termch != '\n') {
2923 termch = 0;
2924 scanhex((void *)&mval);
2925 mask = ~0;
2926 if (termch != '\n') termch = 0;
2927 scanhex((void *)&mask);
2928 }
2929 }
2930 n = 0;
2931 for (a = mdest; a < mend; a += 4) {
2932 if (mread(a, val, 4) == 4
2933 && ((GETWORD(val) ^ mval) & mask) == 0) {
2934 printf("%.16x: %.16x\n", a, GETWORD(val));
2935 if (++n >= 10)
2936 break;
2937 }
2938 }
2939}
2940
2941static unsigned long mskip = 0x1000;
2942static unsigned long mlim = 0xffffffff;
2943
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002944static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945memzcan(void)
2946{
2947 unsigned char v;
2948 unsigned a;
2949 int ok, ook;
2950
2951 scanhex(&mdest);
2952 if (termch != '\n') termch = 0;
2953 scanhex(&mskip);
2954 if (termch != '\n') termch = 0;
2955 scanhex(&mlim);
2956 ook = 0;
2957 for (a = mdest; a < mlim; a += mskip) {
2958 ok = mread(a, &v, 1);
2959 if (ok && !ook) {
2960 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 } else if (!ok && ook)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002962 printf("%.8lx\n", a - mskip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 ook = ok;
2964 if (a + mskip < a)
2965 break;
2966 }
2967 if (ook)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002968 printf("%.8lx\n", a - mskip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969}
2970
Douglas Miller6dfb5402015-11-23 09:01:15 -06002971static void show_task(struct task_struct *tsk)
2972{
2973 char state;
2974
2975 /*
2976 * Cloned from kdb_task_state_char(), which is not entirely
2977 * appropriate for calling from xmon. This could be moved
2978 * to a common, generic, routine used by both.
2979 */
2980 state = (tsk->state == 0) ? 'R' :
2981 (tsk->state < 0) ? 'U' :
2982 (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
2983 (tsk->state & TASK_STOPPED) ? 'T' :
2984 (tsk->state & TASK_TRACED) ? 'C' :
2985 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
2986 (tsk->exit_state & EXIT_DEAD) ? 'E' :
2987 (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
2988
Michael Ellermand8104182017-12-06 23:23:28 +11002989 printf("%px %016lx %6d %6d %c %2d %s\n", tsk,
Douglas Miller6dfb5402015-11-23 09:01:15 -06002990 tsk->thread.ksp,
2991 tsk->pid, tsk->parent->pid,
2992 state, task_thread_info(tsk)->cpu,
2993 tsk->comm);
2994}
2995
Balbir Singh80eff6c2017-10-30 22:01:12 +11002996#ifdef CONFIG_PPC_BOOK3S_64
2997void format_pte(void *ptep, unsigned long pte)
2998{
Christophe Leroy26973fa2018-10-09 13:51:56 +00002999 pte_t entry = __pte(pte);
3000
Balbir Singh80eff6c2017-10-30 22:01:12 +11003001 printf("ptep @ 0x%016lx = 0x%016lx\n", (unsigned long)ptep, pte);
3002 printf("Maps physical address = 0x%016lx\n", pte & PTE_RPN_MASK);
3003
3004 printf("Flags = %s%s%s%s%s\n",
Christophe Leroy26973fa2018-10-09 13:51:56 +00003005 pte_young(entry) ? "Accessed " : "",
3006 pte_dirty(entry) ? "Dirty " : "",
3007 pte_read(entry) ? "Read " : "",
3008 pte_write(entry) ? "Write " : "",
3009 pte_exec(entry) ? "Exec " : "");
Balbir Singh80eff6c2017-10-30 22:01:12 +11003010}
3011
3012static void show_pte(unsigned long addr)
3013{
3014 unsigned long tskv = 0;
3015 struct task_struct *tsk = NULL;
3016 struct mm_struct *mm;
3017 pgd_t *pgdp, *pgdir;
3018 pud_t *pudp;
3019 pmd_t *pmdp;
3020 pte_t *ptep;
3021
3022 if (!scanhex(&tskv))
3023 mm = &init_mm;
3024 else
3025 tsk = (struct task_struct *)tskv;
3026
3027 if (tsk == NULL)
3028 mm = &init_mm;
3029 else
3030 mm = tsk->active_mm;
3031
3032 if (setjmp(bus_error_jmp) != 0) {
3033 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11003034 printf("*** Error dumping pte for task %px\n", tsk);
Balbir Singh80eff6c2017-10-30 22:01:12 +11003035 return;
3036 }
3037
3038 catch_memory_errors = 1;
3039 sync();
3040
3041 if (mm == &init_mm) {
3042 pgdp = pgd_offset_k(addr);
3043 pgdir = pgd_offset_k(0);
3044 } else {
3045 pgdp = pgd_offset(mm, addr);
3046 pgdir = pgd_offset(mm, 0);
3047 }
3048
3049 if (pgd_none(*pgdp)) {
3050 printf("no linux page table for address\n");
3051 return;
3052 }
3053
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003054 printf("pgd @ 0x%px\n", pgdir);
Balbir Singh80eff6c2017-10-30 22:01:12 +11003055
3056 if (pgd_huge(*pgdp)) {
3057 format_pte(pgdp, pgd_val(*pgdp));
3058 return;
3059 }
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003060 printf("pgdp @ 0x%px = 0x%016lx\n", pgdp, pgd_val(*pgdp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003061
3062 pudp = pud_offset(pgdp, addr);
3063
3064 if (pud_none(*pudp)) {
3065 printf("No valid PUD\n");
3066 return;
3067 }
3068
3069 if (pud_huge(*pudp)) {
3070 format_pte(pudp, pud_val(*pudp));
3071 return;
3072 }
3073
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003074 printf("pudp @ 0x%px = 0x%016lx\n", pudp, pud_val(*pudp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003075
3076 pmdp = pmd_offset(pudp, addr);
3077
3078 if (pmd_none(*pmdp)) {
3079 printf("No valid PMD\n");
3080 return;
3081 }
3082
3083 if (pmd_huge(*pmdp)) {
3084 format_pte(pmdp, pmd_val(*pmdp));
3085 return;
3086 }
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003087 printf("pmdp @ 0x%px = 0x%016lx\n", pmdp, pmd_val(*pmdp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003088
3089 ptep = pte_offset_map(pmdp, addr);
3090 if (pte_none(*ptep)) {
3091 printf("no valid PTE\n");
3092 return;
3093 }
3094
3095 format_pte(ptep, pte_val(*ptep));
3096
3097 sync();
3098 __delay(200);
3099 catch_memory_errors = 0;
3100}
3101#else
3102static void show_pte(unsigned long addr)
3103{
3104 printf("show_pte not yet implemented\n");
3105}
3106#endif /* CONFIG_PPC_BOOK3S_64 */
3107
Douglas Miller6dfb5402015-11-23 09:01:15 -06003108static void show_tasks(void)
3109{
3110 unsigned long tskv;
3111 struct task_struct *tsk = NULL;
3112
3113 printf(" task_struct ->thread.ksp PID PPID S P CMD\n");
3114
3115 if (scanhex(&tskv))
3116 tsk = (struct task_struct *)tskv;
3117
3118 if (setjmp(bus_error_jmp) != 0) {
3119 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11003120 printf("*** Error dumping task %px\n", tsk);
Douglas Miller6dfb5402015-11-23 09:01:15 -06003121 return;
3122 }
3123
3124 catch_memory_errors = 1;
3125 sync();
3126
3127 if (tsk)
3128 show_task(tsk);
3129 else
3130 for_each_process(tsk)
3131 show_task(tsk);
3132
3133 sync();
3134 __delay(200);
3135 catch_memory_errors = 0;
3136}
3137
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003138static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003139{
3140 unsigned long args[8];
3141 unsigned long ret;
3142 int i;
3143 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
3144 unsigned long, unsigned long, unsigned long,
3145 unsigned long, unsigned long, unsigned long);
3146 callfunc_t func;
3147
3148 if (!scanhex(&adrs))
3149 return;
3150 if (termch != '\n')
3151 termch = 0;
3152 for (i = 0; i < 8; ++i)
3153 args[i] = 0;
3154 for (i = 0; i < 8; ++i) {
3155 if (!scanhex(&args[i]) || termch == '\n')
3156 break;
3157 termch = 0;
3158 }
3159 func = (callfunc_t) adrs;
3160 ret = 0;
3161 if (setjmp(bus_error_jmp) == 0) {
3162 catch_memory_errors = 1;
3163 sync();
3164 ret = func(args[0], args[1], args[2], args[3],
3165 args[4], args[5], args[6], args[7]);
3166 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10003167 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003168 } else {
3169 printf("*** %x exception occurred\n", fault_except);
3170 }
3171 catch_memory_errors = 0;
3172}
3173
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174/* Input scanning routines */
3175int
3176skipbl(void)
3177{
3178 int c;
3179
3180 if( termch != 0 ){
3181 c = termch;
3182 termch = 0;
3183 } else
3184 c = inchar();
3185 while( c == ' ' || c == '\t' )
3186 c = inchar();
3187 return c;
3188}
3189
3190#define N_PTREGS 44
Yisheng Xie0abbf2b2018-05-31 19:11:25 +08003191static const char *regnames[N_PTREGS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
3193 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
3194 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
3195 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003196 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
3197#ifdef CONFIG_PPC64
3198 "softe",
3199#else
3200 "mq",
3201#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 "trap", "dar", "dsisr", "res"
3203};
3204
3205int
3206scanhex(unsigned long *vp)
3207{
3208 int c, d;
3209 unsigned long v;
3210
3211 c = skipbl();
3212 if (c == '%') {
3213 /* parse register name */
3214 char regname[8];
3215 int i;
3216
3217 for (i = 0; i < sizeof(regname) - 1; ++i) {
3218 c = inchar();
3219 if (!isalnum(c)) {
3220 termch = c;
3221 break;
3222 }
3223 regname[i] = c;
3224 }
3225 regname[i] = 0;
Yisheng Xie0abbf2b2018-05-31 19:11:25 +08003226 i = match_string(regnames, N_PTREGS, regname);
3227 if (i < 0) {
3228 printf("invalid register name '%%%s'\n", regname);
3229 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 }
Yisheng Xie0abbf2b2018-05-31 19:11:25 +08003231 if (xmon_regs == NULL) {
3232 printf("regs not available\n");
3233 return 0;
3234 }
3235 *vp = ((unsigned long *)xmon_regs)[i];
3236 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 }
3238
3239 /* skip leading "0x" if any */
3240
3241 if (c == '0') {
3242 c = inchar();
3243 if (c == 'x') {
3244 c = inchar();
3245 } else {
3246 d = hexdigit(c);
3247 if (d == EOF) {
3248 termch = c;
3249 *vp = 0;
3250 return 1;
3251 }
3252 }
3253 } else if (c == '$') {
3254 int i;
3255 for (i=0; i<63; i++) {
3256 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02003257 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 termch = c;
3259 break;
3260 }
3261 tmpstr[i] = c;
3262 }
3263 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07003264 *vp = 0;
3265 if (setjmp(bus_error_jmp) == 0) {
3266 catch_memory_errors = 1;
3267 sync();
3268 *vp = kallsyms_lookup_name(tmpstr);
3269 sync();
3270 }
3271 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 if (!(*vp)) {
3273 printf("unknown symbol '%s'\n", tmpstr);
3274 return 0;
3275 }
3276 return 1;
3277 }
3278
3279 d = hexdigit(c);
3280 if (d == EOF) {
3281 termch = c;
3282 return 0;
3283 }
3284 v = 0;
3285 do {
3286 v = (v << 4) + d;
3287 c = inchar();
3288 d = hexdigit(c);
3289 } while (d != EOF);
3290 termch = c;
3291 *vp = v;
3292 return 1;
3293}
3294
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003295static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296scannl(void)
3297{
3298 int c;
3299
3300 c = termch;
3301 termch = 0;
3302 while( c != '\n' )
3303 c = inchar();
3304}
3305
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003306static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307{
3308 if( '0' <= c && c <= '9' )
3309 return c - '0';
3310 if( 'A' <= c && c <= 'F' )
3311 return c - ('A' - 10);
3312 if( 'a' <= c && c <= 'f' )
3313 return c - ('a' - 10);
3314 return EOF;
3315}
3316
3317void
3318getstring(char *s, int size)
3319{
3320 int c;
3321
3322 c = skipbl();
3323 do {
3324 if( size > 1 ){
3325 *s++ = c;
3326 --size;
3327 }
3328 c = inchar();
3329 } while( c != ' ' && c != '\t' && c != '\n' );
3330 termch = c;
3331 *s = 0;
3332}
3333
3334static char line[256];
3335static char *lineptr;
3336
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003337static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338flush_input(void)
3339{
3340 lineptr = NULL;
3341}
3342
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003343static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344inchar(void)
3345{
3346 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003347 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 lineptr = NULL;
3349 return EOF;
3350 }
3351 lineptr = line;
3352 }
3353 return *lineptr++;
3354}
3355
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003356static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357take_input(char *str)
3358{
3359 lineptr = str;
3360}
3361
3362
3363static void
3364symbol_lookup(void)
3365{
3366 int type = inchar();
Boqun Feng302c7b02016-11-22 17:20:09 +08003367 unsigned long addr, cpu;
3368 void __percpu *ptr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 static char tmp[64];
3370
3371 switch (type) {
3372 case 'a':
3373 if (scanhex(&addr))
3374 xmon_print_symbol(addr, ": ", "\n");
3375 termch = 0;
3376 break;
3377 case 's':
3378 getstring(tmp, 64);
3379 if (setjmp(bus_error_jmp) == 0) {
3380 catch_memory_errors = 1;
3381 sync();
3382 addr = kallsyms_lookup_name(tmp);
3383 if (addr)
3384 printf("%s: %lx\n", tmp, addr);
3385 else
3386 printf("Symbol '%s' not found.\n", tmp);
3387 sync();
3388 }
3389 catch_memory_errors = 0;
3390 termch = 0;
3391 break;
Boqun Feng302c7b02016-11-22 17:20:09 +08003392 case 'p':
3393 getstring(tmp, 64);
3394 if (setjmp(bus_error_jmp) == 0) {
3395 catch_memory_errors = 1;
3396 sync();
3397 ptr = (void __percpu *)kallsyms_lookup_name(tmp);
3398 sync();
3399 }
3400
3401 if (ptr &&
3402 ptr >= (void __percpu *)__per_cpu_start &&
3403 ptr < (void __percpu *)__per_cpu_end)
3404 {
3405 if (scanhex(&cpu) && cpu < num_possible_cpus()) {
3406 addr = (unsigned long)per_cpu_ptr(ptr, cpu);
3407 } else {
3408 cpu = raw_smp_processor_id();
3409 addr = (unsigned long)this_cpu_ptr(ptr);
3410 }
3411
3412 printf("%s for cpu 0x%lx: %lx\n", tmp, cpu, addr);
3413 } else {
3414 printf("Percpu symbol '%s' not found.\n", tmp);
3415 }
3416
3417 catch_memory_errors = 0;
3418 termch = 0;
3419 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 }
3421}
3422
3423
3424/* Print an address in numeric and symbolic form (if possible) */
3425static void xmon_print_symbol(unsigned long address, const char *mid,
3426 const char *after)
3427{
3428 char *modname;
3429 const char *name = NULL;
3430 unsigned long offset, size;
3431
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003432 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 if (setjmp(bus_error_jmp) == 0) {
3434 catch_memory_errors = 1;
3435 sync();
3436 name = kallsyms_lookup(address, &size, &offset, &modname,
3437 tmpstr);
3438 sync();
3439 /* wait a little while to see if we get a machine check */
3440 __delay(200);
3441 }
3442
3443 catch_memory_errors = 0;
3444
3445 if (name) {
3446 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
3447 if (modname)
3448 printf(" [%s]", modname);
3449 }
3450 printf("%s", after);
3451}
3452
Michael Ellerman4e003742017-10-19 15:08:43 +11003453#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10003454void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455{
3456 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05303457 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11003458 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459
Michael Ellerman736256e2014-05-26 21:02:14 +10003460 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461
Michael Neuling584f8b72007-12-06 17:24:48 +11003462 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11003463 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
3464 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Michael Ellerman85673642017-04-24 10:35:14 +10003465
3466 if (!esid && !vsid)
3467 continue;
3468
3469 printf("%02d %016lx %016lx", i, esid, vsid);
3470
3471 if (!(esid & SLB_ESID_V)) {
3472 printf("\n");
3473 continue;
3474 }
3475
3476 llp = vsid & SLB_VSID_LLP;
3477 if (vsid & SLB_VSID_B_1T) {
3478 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
3479 GET_ESID_1T(esid),
3480 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
3481 llp);
3482 } else {
3483 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
3484 GET_ESID(esid),
3485 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
3486 llp);
will schmidtb3b95952007-12-07 08:22:23 +11003487 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 }
3489}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003490#endif
3491
3492#ifdef CONFIG_PPC_STD_MMU_32
3493void dump_segments(void)
3494{
3495 int i;
3496
3497 printf("sr0-15 =");
3498 for (i = 0; i < 16; ++i)
3499 printf(" %x", mfsrin(i));
3500 printf("\n");
3501}
3502#endif
3503
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003504#ifdef CONFIG_44x
3505static void dump_tlb_44x(void)
3506{
3507 int i;
3508
3509 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
3510 unsigned long w0,w1,w2;
3511 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
3512 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
3513 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003514 printf("[%02x] %08lx %08lx %08lx ", i, w0, w1, w2);
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003515 if (w0 & PPC44x_TLB_VALID) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003516 printf("V %08lx -> %01lx%08lx %c%c%c%c%c",
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003517 w0 & PPC44x_TLB_EPN_MASK,
3518 w1 & PPC44x_TLB_ERPN_MASK,
3519 w1 & PPC44x_TLB_RPN_MASK,
3520 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
3521 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
3522 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
3523 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
3524 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
3525 }
3526 printf("\n");
3527 }
3528}
3529#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003530
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10003531#ifdef CONFIG_PPC_BOOK3E
3532static void dump_tlb_book3e(void)
3533{
3534 u32 mmucfg, pidmask, lpidmask;
3535 u64 ramask;
3536 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3537 int mmu_version;
3538 static const char *pgsz_names[] = {
3539 " 1K",
3540 " 2K",
3541 " 4K",
3542 " 8K",
3543 " 16K",
3544 " 32K",
3545 " 64K",
3546 "128K",
3547 "256K",
3548 "512K",
3549 " 1M",
3550 " 2M",
3551 " 4M",
3552 " 8M",
3553 " 16M",
3554 " 32M",
3555 " 64M",
3556 "128M",
3557 "256M",
3558 "512M",
3559 " 1G",
3560 " 2G",
3561 " 4G",
3562 " 8G",
3563 " 16G",
3564 " 32G",
3565 " 64G",
3566 "128G",
3567 "256G",
3568 "512G",
3569 " 1T",
3570 " 2T",
3571 };
3572
3573 /* Gather some infos about the MMU */
3574 mmucfg = mfspr(SPRN_MMUCFG);
3575 mmu_version = (mmucfg & 3) + 1;
3576 ntlbs = ((mmucfg >> 2) & 3) + 1;
3577 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3578 lpidsz = (mmucfg >> 24) & 0xf;
3579 rasz = (mmucfg >> 16) & 0x7f;
3580 if ((mmu_version > 1) && (mmucfg & 0x10000))
3581 lrat = 1;
3582 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3583 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3584 pidmask = (1ul << pidsz) - 1;
3585 lpidmask = (1ul << lpidsz) - 1;
3586 ramask = (1ull << rasz) - 1;
3587
3588 for (tlb = 0; tlb < ntlbs; tlb++) {
3589 u32 tlbcfg;
3590 int nent, assoc, new_cc = 1;
3591 printf("TLB %d:\n------\n", tlb);
3592 switch(tlb) {
3593 case 0:
3594 tlbcfg = mfspr(SPRN_TLB0CFG);
3595 break;
3596 case 1:
3597 tlbcfg = mfspr(SPRN_TLB1CFG);
3598 break;
3599 case 2:
3600 tlbcfg = mfspr(SPRN_TLB2CFG);
3601 break;
3602 case 3:
3603 tlbcfg = mfspr(SPRN_TLB3CFG);
3604 break;
3605 default:
3606 printf("Unsupported TLB number !\n");
3607 continue;
3608 }
3609 nent = tlbcfg & 0xfff;
3610 assoc = (tlbcfg >> 24) & 0xff;
3611 for (i = 0; i < nent; i++) {
3612 u32 mas0 = MAS0_TLBSEL(tlb);
3613 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3614 u64 mas2 = 0;
3615 u64 mas7_mas3;
3616 int esel = i, cc = i;
3617
3618 if (assoc != 0) {
3619 cc = i / assoc;
3620 esel = i % assoc;
3621 mas2 = cc * 0x1000;
3622 }
3623
3624 mas0 |= MAS0_ESEL(esel);
3625 mtspr(SPRN_MAS0, mas0);
3626 mtspr(SPRN_MAS1, mas1);
3627 mtspr(SPRN_MAS2, mas2);
3628 asm volatile("tlbre 0,0,0" : : : "memory");
3629 mas1 = mfspr(SPRN_MAS1);
3630 mas2 = mfspr(SPRN_MAS2);
3631 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3632 if (assoc && (i % assoc) == 0)
3633 new_cc = 1;
3634 if (!(mas1 & MAS1_VALID))
3635 continue;
3636 if (assoc == 0)
3637 printf("%04x- ", i);
3638 else if (new_cc)
3639 printf("%04x-%c", cc, 'A' + esel);
3640 else
3641 printf(" |%c", 'A' + esel);
3642 new_cc = 0;
3643 printf(" %016llx %04x %s %c%c AS%c",
3644 mas2 & ~0x3ffull,
3645 (mas1 >> 16) & 0x3fff,
3646 pgsz_names[(mas1 >> 7) & 0x1f],
3647 mas1 & MAS1_IND ? 'I' : ' ',
3648 mas1 & MAS1_IPROT ? 'P' : ' ',
3649 mas1 & MAS1_TS ? '1' : '0');
3650 printf(" %c%c%c%c%c%c%c",
3651 mas2 & MAS2_X0 ? 'a' : ' ',
3652 mas2 & MAS2_X1 ? 'v' : ' ',
3653 mas2 & MAS2_W ? 'w' : ' ',
3654 mas2 & MAS2_I ? 'i' : ' ',
3655 mas2 & MAS2_M ? 'm' : ' ',
3656 mas2 & MAS2_G ? 'g' : ' ',
3657 mas2 & MAS2_E ? 'e' : ' ');
3658 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3659 if (mas1 & MAS1_IND)
3660 printf(" %s\n",
3661 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3662 else
3663 printf(" U%c%c%c S%c%c%c\n",
3664 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3665 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3666 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3667 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3668 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3669 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3670 }
3671 }
3672}
3673#endif /* CONFIG_PPC_BOOK3E */
3674
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003675static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003677 if (enable) {
3678 __debugger = xmon;
3679 __debugger_ipi = xmon_ipi;
3680 __debugger_bpt = xmon_bpt;
3681 __debugger_sstep = xmon_sstep;
3682 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003683 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003684 __debugger_fault_handler = xmon_fault_handler;
3685 } else {
3686 __debugger = NULL;
3687 __debugger_ipi = NULL;
3688 __debugger_bpt = NULL;
3689 __debugger_sstep = NULL;
3690 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003691 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003692 __debugger_fault_handler = NULL;
3693 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003695
3696#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003697static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003698{
3699 /* ensure xmon is enabled */
3700 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003701 debugger(get_irq_regs());
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003702 if (!xmon_on)
3703 xmon_init(0);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003704}
3705
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003706static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003707 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003708 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003709 .action_msg = "Entering xmon",
3710};
3711
3712static int __init setup_xmon_sysrq(void)
3713{
3714 register_sysrq_key('x', &sysrq_xmon_op);
3715 return 0;
3716}
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003717device_initcall(setup_xmon_sysrq);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003718#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003719
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003720#ifdef CONFIG_DEBUG_FS
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05303721static void clear_all_bpt(void)
3722{
3723 int i;
3724
3725 /* clear/unpatch all breakpoints */
3726 remove_bpts();
3727 remove_cpu_bpts();
3728
3729 /* Disable all breakpoints */
3730 for (i = 0; i < NBPTS; ++i)
3731 bpts[i].enabled = 0;
3732
3733 /* Clear any data or iabr breakpoints */
3734 if (iabr || dabr.enabled) {
3735 iabr = NULL;
3736 dabr.enabled = 0;
3737 }
3738
3739 printf("xmon: All breakpoints cleared\n");
3740}
3741
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003742static int xmon_dbgfs_set(void *data, u64 val)
3743{
3744 xmon_on = !!val;
3745 xmon_init(xmon_on);
3746
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05303747 /* make sure all breakpoints removed when disabling */
3748 if (!xmon_on)
3749 clear_all_bpt();
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003750 return 0;
3751}
3752
3753static int xmon_dbgfs_get(void *data, u64 *val)
3754{
3755 *val = xmon_on;
3756 return 0;
3757}
3758
3759DEFINE_SIMPLE_ATTRIBUTE(xmon_dbgfs_ops, xmon_dbgfs_get,
3760 xmon_dbgfs_set, "%llu\n");
3761
3762static int __init setup_xmon_dbgfs(void)
3763{
3764 debugfs_create_file("xmon", 0600, powerpc_debugfs_root, NULL,
3765 &xmon_dbgfs_ops);
3766 return 0;
3767}
3768device_initcall(setup_xmon_dbgfs);
3769#endif /* CONFIG_DEBUG_FS */
3770
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003771static int xmon_early __initdata;
Michael Ellerman476792832006-10-03 14:12:08 +10003772
3773static int __init early_parse_xmon(char *p)
3774{
3775 if (!p || strncmp(p, "early", 5) == 0) {
3776 /* just "xmon" is equivalent to "xmon=early" */
3777 xmon_init(1);
3778 xmon_early = 1;
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003779 xmon_on = 1;
3780 } else if (strncmp(p, "on", 2) == 0) {
Michael Ellerman476792832006-10-03 14:12:08 +10003781 xmon_init(1);
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003782 xmon_on = 1;
3783 } else if (strncmp(p, "off", 3) == 0)
3784 xmon_on = 0;
Michael Ellerman476792832006-10-03 14:12:08 +10003785 else
3786 return 1;
3787
3788 return 0;
3789}
3790early_param("xmon", early_parse_xmon);
3791
3792void __init xmon_setup(void)
3793{
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003794 if (xmon_on)
Michael Ellerman476792832006-10-03 14:12:08 +10003795 xmon_init(1);
Michael Ellerman476792832006-10-03 14:12:08 +10003796 if (xmon_early)
3797 debugger(NULL);
3798}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003799
Arnd Bergmanne0555952006-11-27 19:18:55 +01003800#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003801
3802struct spu_info {
3803 struct spu *spu;
3804 u64 saved_mfc_sr1_RW;
3805 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003806 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003807 u8 stopped_ok;
3808};
3809
3810#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3811
3812static struct spu_info spu_info[XMON_NUM_SPUS];
3813
3814void xmon_register_spus(struct list_head *list)
3815{
3816 struct spu *spu;
3817
3818 list_for_each_entry(spu, list, full_list) {
3819 if (spu->number >= XMON_NUM_SPUS) {
3820 WARN_ON(1);
3821 continue;
3822 }
3823
3824 spu_info[spu->number].spu = spu;
3825 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003826 spu_info[spu->number].dump_addr = (unsigned long)
3827 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003828 }
3829}
3830
3831static void stop_spus(void)
3832{
3833 struct spu *spu;
3834 int i;
3835 u64 tmp;
3836
3837 for (i = 0; i < XMON_NUM_SPUS; i++) {
3838 if (!spu_info[i].spu)
3839 continue;
3840
3841 if (setjmp(bus_error_jmp) == 0) {
3842 catch_memory_errors = 1;
3843 sync();
3844
3845 spu = spu_info[i].spu;
3846
3847 spu_info[i].saved_spu_runcntl_RW =
3848 in_be32(&spu->problem->spu_runcntl_RW);
3849
3850 tmp = spu_mfc_sr1_get(spu);
3851 spu_info[i].saved_mfc_sr1_RW = tmp;
3852
3853 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3854 spu_mfc_sr1_set(spu, tmp);
3855
3856 sync();
3857 __delay(200);
3858
3859 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003860
3861 printf("Stopped spu %.2d (was %s)\n", i,
3862 spu_info[i].saved_spu_runcntl_RW ?
3863 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003864 } else {
3865 catch_memory_errors = 0;
3866 printf("*** Error stopping spu %.2d\n", i);
3867 }
3868 catch_memory_errors = 0;
3869 }
3870}
3871
3872static void restart_spus(void)
3873{
3874 struct spu *spu;
3875 int i;
3876
3877 for (i = 0; i < XMON_NUM_SPUS; i++) {
3878 if (!spu_info[i].spu)
3879 continue;
3880
3881 if (!spu_info[i].stopped_ok) {
3882 printf("*** Error, spu %d was not successfully stopped"
3883 ", not restarting\n", i);
3884 continue;
3885 }
3886
3887 if (setjmp(bus_error_jmp) == 0) {
3888 catch_memory_errors = 1;
3889 sync();
3890
3891 spu = spu_info[i].spu;
3892 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3893 out_be32(&spu->problem->spu_runcntl_RW,
3894 spu_info[i].saved_spu_runcntl_RW);
3895
3896 sync();
3897 __delay(200);
3898
3899 printf("Restarted spu %.2d\n", i);
3900 } else {
3901 catch_memory_errors = 0;
3902 printf("*** Error restarting spu %.2d\n", i);
3903 }
3904 catch_memory_errors = 0;
3905 }
3906}
3907
Michael Ellermana8984972006-10-24 18:31:28 +02003908#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003909#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003910do { \
3911 if (setjmp(bus_error_jmp) == 0) { \
3912 catch_memory_errors = 1; \
3913 sync(); \
3914 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003915 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003916 sync(); \
3917 __delay(200); \
3918 } else { \
3919 catch_memory_errors = 0; \
3920 printf(" %-*s = *** Error reading field.\n", \
3921 DUMP_WIDTH, #field); \
3922 } \
3923 catch_memory_errors = 0; \
3924} while (0)
3925
Michael Ellerman437a0702006-11-23 00:46:39 +01003926#define DUMP_FIELD(obj, format, field) \
3927 DUMP_VALUE(format, field, obj->field)
3928
Michael Ellermana8984972006-10-24 18:31:28 +02003929static void dump_spu_fields(struct spu *spu)
3930{
3931 printf("Dumping spu fields at address %p:\n", spu);
3932
3933 DUMP_FIELD(spu, "0x%x", number);
3934 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003935 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3936 DUMP_FIELD(spu, "0x%p", local_store);
3937 DUMP_FIELD(spu, "0x%lx", ls_size);
3938 DUMP_FIELD(spu, "0x%x", node);
3939 DUMP_FIELD(spu, "0x%lx", flags);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003940 DUMP_FIELD(spu, "%llu", class_0_pending);
3941 DUMP_FIELD(spu, "0x%llx", class_0_dar);
3942 DUMP_FIELD(spu, "0x%llx", class_1_dar);
3943 DUMP_FIELD(spu, "0x%llx", class_1_dsisr);
3944 DUMP_FIELD(spu, "0x%x", irqs[0]);
3945 DUMP_FIELD(spu, "0x%x", irqs[1]);
3946 DUMP_FIELD(spu, "0x%x", irqs[2]);
Michael Ellermana8984972006-10-24 18:31:28 +02003947 DUMP_FIELD(spu, "0x%x", slb_replace);
3948 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003949 DUMP_FIELD(spu, "0x%p", mm);
3950 DUMP_FIELD(spu, "0x%p", ctx);
3951 DUMP_FIELD(spu, "0x%p", rq);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003952 DUMP_FIELD(spu, "0x%llx", timestamp);
Michael Ellermana8984972006-10-24 18:31:28 +02003953 DUMP_FIELD(spu, "0x%lx", problem_phys);
3954 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003955 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3956 in_be32(&spu->problem->spu_runcntl_RW));
3957 DUMP_VALUE("0x%x", problem->spu_status_R,
3958 in_be32(&spu->problem->spu_status_R));
3959 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3960 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003961 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003962 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003963}
3964
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003965int
3966spu_inst_dump(unsigned long adr, long count, int praddr)
3967{
3968 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3969}
3970
3971static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003972{
3973 unsigned long offset, addr, ls_addr;
3974
3975 if (setjmp(bus_error_jmp) == 0) {
3976 catch_memory_errors = 1;
3977 sync();
3978 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3979 sync();
3980 __delay(200);
3981 } else {
3982 catch_memory_errors = 0;
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003983 printf("*** Error: accessing spu info for spu %ld\n", num);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003984 return;
3985 }
3986 catch_memory_errors = 0;
3987
3988 if (scanhex(&offset))
3989 addr = ls_addr + offset;
3990 else
3991 addr = spu_info[num].dump_addr;
3992
3993 if (addr >= ls_addr + LS_SIZE) {
3994 printf("*** Error: address outside of local store\n");
3995 return;
3996 }
3997
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003998 switch (subcmd) {
3999 case 'i':
4000 addr += spu_inst_dump(addr, 16, 1);
4001 last_cmd = "sdi\n";
4002 break;
4003 default:
4004 prdump(addr, 64);
4005 addr += 64;
4006 last_cmd = "sd\n";
4007 break;
4008 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01004009
4010 spu_info[num].dump_addr = addr;
4011}
4012
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004013static int do_spu_cmd(void)
4014{
Michael Ellerman24a24c82006-11-23 00:46:41 +01004015 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004016 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004017
4018 cmd = inchar();
4019 switch (cmd) {
4020 case 's':
4021 stop_spus();
4022 break;
4023 case 'r':
4024 restart_spus();
4025 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01004026 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004027 subcmd = inchar();
4028 if (isxdigit(subcmd) || subcmd == '\n')
4029 termch = subcmd;
4030 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01004031 scanhex(&num);
4032 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02004033 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01004034 return 0;
4035 }
4036
4037 switch (cmd) {
4038 case 'f':
4039 dump_spu_fields(spu_info[num].spu);
4040 break;
4041 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004042 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01004043 break;
4044 }
4045
Michael Ellermana8984972006-10-24 18:31:28 +02004046 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004047 default:
4048 return -1;
4049 }
4050
4051 return 0;
4052}
Arnd Bergmanne0555952006-11-27 19:18:55 +01004053#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004054static int do_spu_cmd(void)
4055{
4056 return -1;
4057}
4058#endif