blob: 0a438b51dbb52ad94fa1e6c1579186a44140ec48 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * Routines providing a simple monitor for use on the PowerMac.
4 *
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11005 * Copyright (C) 1996-2005 Paul Mackerras.
Michael Ellerman476792832006-10-03 14:12:08 +10006 * Copyright (C) 2001 PPC64 Team, IBM Corp
7 * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 */
Michael Ellerman56144ec2015-11-06 13:21:17 +11009
10#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/errno.h>
Ingo Molnar3f07c012017-02-08 18:51:30 +010012#include <linux/sched/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/smp.h>
14#include <linux/mm.h>
15#include <linux/reboot.h>
16#include <linux/delay.h>
17#include <linux/kallsyms.h>
Michael Ellermanca5dd392012-08-23 22:09:12 +000018#include <linux/kmsg_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040020#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110021#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080022#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010023#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080024#include <linux/bug.h>
Anton Blancharda71d64b2014-08-05 14:55:00 +100025#include <linux/nmi.h>
Vincent Bernat05b981f2014-07-15 13:43:47 +020026#include <linux/ctype.h>
Balbir Singh80eff6c2017-10-30 22:01:12 +110027#include <linux/highmem.h>
Christopher M. Riedl69393cb2019-09-07 01:11:24 -050028#include <linux/security.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Michael Ellerman7644d582017-02-10 12:04:56 +110030#include <asm/debugfs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <asm/ptrace.h>
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +100032#include <asm/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/string.h>
34#include <asm/prom.h>
35#include <asm/machdep.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100036#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <asm/processor.h>
38#include <asm/pgtable.h>
39#include <asm/mmu.h>
40#include <asm/mmu_context.h>
Michael Ellermanab83dc72018-03-08 13:54:42 +110041#include <asm/plpar_wrappers.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <asm/cputable.h>
43#include <asm/rtas.h>
44#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100045#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020046#include <asm/spu.h>
47#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110048#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000049#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010050#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000051#include <asm/hw_breakpoint.h>
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +100052#include <asm/xive.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110053#include <asm/opal.h>
54#include <asm/firmware.h>
Balbir Singhefe4fbb2017-06-27 17:48:58 +100055#include <asm/code-patching.h>
Boqun Feng302c7b02016-11-22 17:20:09 +080056#include <asm/sections.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110057
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100058#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100060#include <asm/paca.h>
61#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010064#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100067static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static unsigned long xmon_taken = 1;
69static int xmon_owner;
70static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000071#else
72#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#endif /* CONFIG_SMP */
74
Breno Leitao8d4a8622018-11-08 15:12:42 -020075#ifdef CONFIG_PPC_PSERIES
76static int set_indicator_token = RTAS_UNKNOWN_SERVICE;
77#endif
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);
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -050080static bool xmon_is_ro = IS_ENABLED(CONFIG_XMON_DEFAULT_RO_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
82static unsigned long adrs;
83static int size = 1;
84#define MAX_DUMP (128 * 1024)
85static unsigned long ndump = 64;
86static unsigned long nidump = 16;
87static unsigned long ncsum = 4096;
88static int termch;
89static char tmpstr[128];
Breno Leitaoed49f7f2017-08-02 17:14:06 -030090static int tracing_enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Linus Torvalds1da177e2005-04-16 15:20:36 -070092static long bus_error_jmp[JMP_BUF_LEN];
93static int catch_memory_errors;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +100094static int catch_spr_faults;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97/* Breakpoint stuff */
98struct bpt {
99 unsigned long address;
100 unsigned int instr[2];
101 atomic_t ref_count;
102 int enabled;
103 unsigned long pad;
104};
105
106/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100107#define BP_CIABR 1
108#define BP_TRAP 2
109#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
111#define NBPTS 256
112static struct bpt bpts[NBPTS];
113static struct bpt dabr;
114static struct bpt *iabr;
115static unsigned bpinstr = 0x7fe00008; /* trap */
116
117#define BP_NUM(bp) ((bp) - bpts + 1)
118
119/* Prototypes */
120static int cmds(struct pt_regs *);
121static int mread(unsigned long, void *, int);
122static int mwrite(unsigned long, void *, int);
123static int handle_fault(struct pt_regs *);
124static void byterev(unsigned char *, int);
125static void memex(void);
126static int bsesc(void);
127static void dump(void);
Balbir Singh80eff6c2017-10-30 22:01:12 +1100128static void show_pte(unsigned long);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129static void prdump(unsigned long, long);
130static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000131static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100132
133#ifdef CONFIG_PPC_POWERNV
134static void dump_opal_msglog(void);
135#else
136static inline void dump_opal_msglog(void)
137{
138 printf("Machine is not running OPAL firmware.\n");
139}
140#endif
141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static void backtrace(struct pt_regs *);
143static void excprint(struct pt_regs *);
144static void prregs(struct pt_regs *);
145static void memops(int);
146static void memlocate(void);
147static void memzcan(void);
148static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
149int skipbl(void);
150int scanhex(unsigned long *valp);
151static void scannl(void);
152static int hexdigit(int);
153void getstring(char *, int);
154static void flush_input(void);
155static int inchar(void);
156static void take_input(char *);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000157static int read_spr(int, unsigned long *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158static void write_spr(int, unsigned long);
159static void super_regs(void);
160static void remove_bpts(void);
161static void insert_bpts(void);
162static void remove_cpu_bpts(void);
163static void insert_cpu_bpts(void);
164static struct bpt *at_breakpoint(unsigned long pc);
165static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
166static int do_step(struct pt_regs *);
167static void bpt_cmds(void);
168static void cacheflush(void);
169static int cpu_cmd(void);
170static void csum(void);
171static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000172static void proccall(void);
Douglas Miller6dfb5402015-11-23 09:01:15 -0600173static void show_tasks(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174void dump_segments(void);
175static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200176static void xmon_show_stack(unsigned long sp, unsigned long lr,
177 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178static void xmon_print_symbol(unsigned long address, const char *mid,
179 const char *after);
180static const char *getvecname(unsigned long vec);
181
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200182static int do_spu_cmd(void);
183
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100184#ifdef CONFIG_44x
185static void dump_tlb_44x(void);
186#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000187#ifdef CONFIG_PPC_BOOK3E
188static void dump_tlb_book3e(void);
189#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100190
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500191static void clear_all_bpt(void);
192
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000193#ifdef CONFIG_PPC64
194#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000195#else
196#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000197#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100199#ifdef __LITTLE_ENDIAN__
200#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
201#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100203#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -0500205static const char *xmon_ro_msg = "Operation disabled: xmon in read-only mode\n";
206
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207static char *help_string = "\
208Commands:\n\
209 b show breakpoints\n\
210 bd set data breakpoint\n\
211 bi set instruction breakpoint\n\
212 bc clear breakpoint\n"
213#ifdef CONFIG_SMP
214 "\
215 c print cpus stopped in xmon\n\
216 c# try to switch to cpu number h (in hex)\n"
217#endif
218 "\
219 C checksum\n\
220 d dump bytes\n\
Douglas Miller5e48dc02017-02-07 07:40:44 -0600221 d1 dump 1 byte values\n\
222 d2 dump 2 byte values\n\
223 d4 dump 4 byte values\n\
224 d8 dump 8 byte values\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 di dump instructions\n\
226 df dump float values\n\
227 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000228 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100229#ifdef CONFIG_PPC_POWERNV
230 "\
231 do dump the OPAL message log\n"
232#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000233#ifdef CONFIG_PPC64
234 "\
235 dp[#] dump paca for current cpu, or cpu #\n\
236 dpa dump paca for all possible cpus\n"
237#endif
238 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100239 dr dump stream of raw bytes\n\
Balbir Singh80eff6c2017-10-30 22:01:12 +1100240 dv dump virtual address translation \n\
Michael Ellerman56144ec2015-11-06 13:21:17 +1100241 dt dump the tracing buffers (uses printk)\n\
Breno Leitao4125d012017-08-02 17:14:05 -0300242 dtc dump the tracing buffers for current CPU (uses printk)\n\
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +1000243"
244#ifdef CONFIG_PPC_POWERNV
245" dx# dump xive on CPU #\n\
246 dxi# dump xive irq state #\n\
247 dxa dump xive on all CPUs\n"
248#endif
249" e print exception information\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 f flush cache\n\
251 la lookup symbol+offset of specified address\n\
252 ls lookup address of specified symbol\n\
Boqun Feng302c7b02016-11-22 17:20:09 +0800253 lp s [#] lookup address of percpu symbol s for current cpu, or cpu #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 m examine/change memory\n\
255 mm move a block of memory\n\
256 ms set a block of memory\n\
257 md compare two blocks of memory\n\
258 ml locate a block of memory\n\
259 mz zero a block of memory\n\
260 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000261 p call a procedure\n\
Douglas Miller6dfb5402015-11-23 09:01:15 -0600262 P list processes/tasks\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200264 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100265#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200266" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200267 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100268 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900269 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100270 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200271#endif
272" S print special registers\n\
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000273 Sa print all SPRs\n\
274 Sr # read SPR #\n\
275 Sw #v write v to SPR #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100278 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000279#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000280" u dump segment table or SLB\n"
Christophe Leroy68289ae2018-11-17 10:25:02 +0000281#elif defined(CONFIG_PPC_BOOK3S_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000282" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000283#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100284" u dump TLB\n"
285#endif
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300286" U show uptime information\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000287" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100288" # n limit output to n lines per page (for dp, dpa, dl)\n"
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500289" zr reboot\n"
290" zh halt\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291;
292
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500293#ifdef CONFIG_SECURITY
294static bool xmon_is_locked_down(void)
295{
296 static bool lockdown;
297
298 if (!lockdown) {
299 lockdown = !!security_locked_down(LOCKDOWN_XMON_RW);
300 if (lockdown) {
301 printf("xmon: Disabled due to kernel lockdown\n");
302 xmon_is_ro = true;
303 }
304 }
305
306 if (!xmon_is_ro) {
307 xmon_is_ro = !!security_locked_down(LOCKDOWN_XMON_WR);
308 if (xmon_is_ro)
309 printf("xmon: Read-only due to kernel lockdown\n");
310 }
311
312 return lockdown;
313}
314#else /* CONFIG_SECURITY */
315static inline bool xmon_is_locked_down(void)
316{
317 return false;
318}
319#endif
320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321static struct pt_regs *xmon_regs;
322
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000323static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
325 asm volatile("sync; isync");
326}
327
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000328static inline void store_inst(void *p)
329{
330 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
331}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000333static inline void cflush(void *p)
334{
335 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
336}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000338static inline void cinval(void *p)
339{
340 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
341}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530343/**
344 * write_ciabr() - write the CIABR SPR
345 * @ciabr: The value to write.
346 *
347 * This function writes a value to the CIARB register either directly
348 * through mtspr instruction if the kernel is in HV privilege mode or
349 * call a hypervisor function to achieve the same in case the kernel
350 * is in supervisor privilege mode.
351 */
352static void write_ciabr(unsigned long ciabr)
353{
354 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
355 return;
356
357 if (cpu_has_feature(CPU_FTR_HVMODE)) {
358 mtspr(SPRN_CIABR, ciabr);
359 return;
360 }
Michael Ellerman7c09c182018-03-08 13:54:41 +1100361 plpar_set_ciabr(ciabr);
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530362}
363
364/**
365 * set_ciabr() - set the CIABR
366 * @addr: The value to set.
367 *
368 * This function sets the correct privilege value into the the HW
369 * breakpoint address before writing it up in the CIABR register.
370 */
371static void set_ciabr(unsigned long addr)
372{
373 addr &= ~CIABR_PRIV;
374
375 if (cpu_has_feature(CPU_FTR_HVMODE))
376 addr |= CIABR_PRIV_HYPER;
377 else
378 addr |= CIABR_PRIV_SUPER;
379 write_ciabr(addr);
380}
381
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382/*
383 * Disable surveillance (the service processor watchdog function)
384 * while we are in xmon.
385 * XXX we should re-enable it when we leave. :)
386 */
387#define SURVEILLANCE_TOKEN 9000
388
389static inline void disable_surveillance(void)
390{
391#ifdef CONFIG_PPC_PSERIES
392 /* Since this can't be a module, args should end up below 4GB. */
393 static struct rtas_args args;
394
395 /*
396 * At this point we have got all the cpus we can into
397 * xmon, so there is hopefully no other cpu calling RTAS
398 * at the moment, even though we don't take rtas.lock.
399 * If we did try to take rtas.lock there would be a
400 * real possibility of deadlock.
401 */
Breno Leitao8d4a8622018-11-08 15:12:42 -0200402 if (set_indicator_token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100404
Breno Leitao8d4a8622018-11-08 15:12:42 -0200405 rtas_call_unlocked(&args, set_indicator_token, 3, 1, NULL,
406 SURVEILLANCE_TOKEN, 0, 0);
Michael Ellerman08eb1052015-11-24 22:26:09 +1100407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408#endif /* CONFIG_PPC_PSERIES */
409}
410
411#ifdef CONFIG_SMP
412static int xmon_speaker;
413
414static void get_output_lock(void)
415{
416 int me = smp_processor_id() + 0x100;
417 int last_speaker = 0, prev;
418 long timeout;
419
420 if (xmon_speaker == me)
421 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100424 last_speaker = cmpxchg(&xmon_speaker, 0, me);
425 if (last_speaker == 0)
426 return;
427
Michael Ellerman15075892013-12-23 23:46:05 +1100428 /*
429 * Wait a full second for the lock, we might be on a slow
430 * console, but check every 100us.
431 */
432 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100434 if (--timeout > 0) {
435 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100437 }
438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 /* hostile takeover */
440 prev = cmpxchg(&xmon_speaker, last_speaker, me);
441 if (prev == last_speaker)
442 return;
443 break;
444 }
445 }
446}
447
448static void release_output_lock(void)
449{
450 xmon_speaker = 0;
451}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000452
453int cpus_are_in_xmon(void)
454{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000455 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000456}
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000457
458static bool wait_for_other_cpus(int ncpus)
459{
460 unsigned long timeout;
461
462 /* We wait for 2s, which is a metric "little while" */
463 for (timeout = 20000; timeout != 0; --timeout) {
464 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
465 return true;
466 udelay(100);
467 barrier();
468 }
469
470 return false;
471}
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500472#else /* CONFIG_SMP */
473static inline void get_output_lock(void) {}
474static inline void release_output_lock(void) {}
475#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Josh Boyerdaf8f402009-09-23 03:51:04 +0000477static inline int unrecoverable_excp(struct pt_regs *regs)
478{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000479#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000480 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000481 return 0;
482#else
483 return ((regs->msr & MSR_RI) == 0);
484#endif
485}
486
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000487static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
489 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 struct bpt *bp;
491 long recurse_jmp[JMP_BUF_LEN];
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500492 bool locked_down;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100494 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495#ifdef CONFIG_SMP
496 int cpu;
497 int secondary;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498#endif
499
Anton Blanchardf13659e2007-03-21 01:48:34 +1100500 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000501 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500503 locked_down = xmon_is_locked_down();
504
Naveen N. Raoaaf06662019-06-27 15:29:40 +0530505 if (!fromipi) {
506 tracing_enabled = tracing_is_on();
507 tracing_off();
508 }
Breno Leitaoed49f7f2017-08-02 17:14:06 -0300509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 bp = in_breakpoint_table(regs->nip, &offset);
511 if (bp != NULL) {
512 regs->nip = bp->address + offset;
513 atomic_dec(&bp->ref_count);
514 }
515
516 remove_cpu_bpts();
517
518#ifdef CONFIG_SMP
519 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000520 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000521 /*
522 * We catch SPR read/write faults here because the 0x700, 0xf60
523 * etc. handlers don't call debugger_fault_handler().
524 */
525 if (catch_spr_faults)
526 longjmp(bus_error_jmp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 get_output_lock();
528 excprint(regs);
529 printf("cpu 0x%x: Exception %lx %s in xmon, "
530 "returning to main loop\n",
531 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000532 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 longjmp(xmon_fault_jmp[cpu], 1);
534 }
535
536 if (setjmp(recurse_jmp) != 0) {
537 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000538 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 printf("xmon: WARNING: bad recursive fault "
540 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000541 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 goto waiting;
543 }
544 secondary = !(xmon_taken && cpu == xmon_owner);
545 goto cmdloop;
546 }
547
548 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
550 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000551 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000553 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 fromipi = 0;
555
556 if (!fromipi) {
557 get_output_lock();
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500558 if (!locked_down)
559 excprint(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 if (bp) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +0200561 printf("cpu 0x%x stopped at breakpoint 0x%tx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 cpu, BP_NUM(bp));
563 xmon_print_symbol(regs->nip, " ", ")\n");
564 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000565 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 printf("WARNING: exception is not recoverable, "
567 "can't continue\n");
568 release_output_lock();
569 }
570
Michael Ellermand2b496e2013-12-23 23:46:06 +1100571 cpumask_set_cpu(cpu, &cpus_in_xmon);
572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 waiting:
574 secondary = 1;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000575 spin_begin();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 while (secondary && !xmon_gate) {
577 if (in_xmon == 0) {
Nicholas Piggin064996d2017-09-29 13:29:40 +1000578 if (fromipi) {
579 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 goto leave;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 secondary = test_and_set_bit(0, &in_xmon);
583 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000584 spin_cpu_relax();
585 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000587 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589 if (!secondary && !xmon_gate) {
590 /* we are the first cpu to come in */
591 /* interrupt other cpu(s) */
592 int ncpus = num_online_cpus();
593
594 xmon_owner = cpu;
595 mb();
596 if (ncpus > 1) {
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000597 /*
598 * A system reset (trap == 0x100) can be triggered on
599 * all CPUs, so when we come in via 0x100 try waiting
600 * for the other CPUs to come in before we send the
601 * debugger break (IPI). This is similar to
602 * crash_kexec_secondary().
603 */
604 if (TRAP(regs) != 0x100 || !wait_for_other_cpus(ncpus))
605 smp_send_debugger_break();
606
607 wait_for_other_cpus(ncpus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 }
609 remove_bpts();
610 disable_surveillance();
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500611
612 if (!locked_down) {
613 /* for breakpoint or single step, print curr insn */
614 if (bp || TRAP(regs) == 0xd00)
615 ppc_inst_dump(regs->nip, 1, 0);
616 printf("enter ? for help\n");
617 }
618
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 mb();
620 xmon_gate = 1;
621 barrier();
Nicholas Piggin064996d2017-09-29 13:29:40 +1000622 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
624
625 cmdloop:
626 while (in_xmon) {
627 if (secondary) {
Nicholas Piggin064996d2017-09-29 13:29:40 +1000628 spin_begin();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 if (cpu == xmon_owner) {
630 if (!test_and_set_bit(0, &xmon_taken)) {
631 secondary = 0;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000632 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 continue;
634 }
635 /* missed it */
636 while (cpu == xmon_owner)
Nicholas Piggin064996d2017-09-29 13:29:40 +1000637 spin_cpu_relax();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000639 spin_cpu_relax();
640 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 } else {
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500642 if (!locked_down)
643 cmd = cmds(regs);
644 if (locked_down || cmd != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 /* exiting xmon */
646 insert_bpts();
647 xmon_gate = 0;
648 wmb();
649 in_xmon = 0;
650 break;
651 }
652 /* have switched to some other cpu */
653 secondary = 1;
654 }
655 }
656 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000657 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659#else
660 /* UP is simple... */
661 if (in_xmon) {
662 printf("Exception %lx %s in xmon, returning to main loop\n",
663 regs->trap, getvecname(TRAP(regs)));
664 longjmp(xmon_fault_jmp[0], 1);
665 }
666 if (setjmp(recurse_jmp) == 0) {
667 xmon_fault_jmp[0] = recurse_jmp;
668 in_xmon = 1;
669
670 excprint(regs);
671 bp = at_breakpoint(regs->nip);
672 if (bp) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +0200673 printf("Stopped at breakpoint %tx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 xmon_print_symbol(regs->nip, " ", ")\n");
675 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000676 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 printf("WARNING: exception is not recoverable, "
678 "can't continue\n");
679 remove_bpts();
680 disable_surveillance();
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500681 if (!locked_down) {
682 /* for breakpoint or single step, print current insn */
683 if (bp || TRAP(regs) == 0xd00)
684 ppc_inst_dump(regs->nip, 1, 0);
685 printf("enter ? for help\n");
686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
688
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500689 if (!locked_down)
690 cmd = cmds(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
692 insert_bpts();
693 in_xmon = 0;
694#endif
695
Josh Boyercdd39042009-10-05 04:46:05 +0000696#ifdef CONFIG_BOOKE
697 if (regs->msr & MSR_DE) {
698 bp = at_breakpoint(regs->nip);
699 if (bp != NULL) {
700 regs->nip = (unsigned long) &bp->instr[0];
701 atomic_inc(&bp->ref_count);
702 }
703 }
704#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000705 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 bp = at_breakpoint(regs->nip);
707 if (bp != NULL) {
708 int stepped = emulate_step(regs, bp->instr[0]);
709 if (stepped == 0) {
710 regs->nip = (unsigned long) &bp->instr[0];
711 atomic_inc(&bp->ref_count);
712 } else if (stepped < 0) {
713 printf("Couldn't single-step %s instruction\n",
714 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
715 }
716 }
717 }
Josh Boyercdd39042009-10-05 04:46:05 +0000718#endif
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500719 if (locked_down)
720 clear_all_bpt();
721 else
722 insert_cpu_bpts();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
Anton Blancharda71d64b2014-08-05 14:55:00 +1000724 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100725 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000727 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728}
729
730int xmon(struct pt_regs *excp)
731{
732 struct pt_regs regs;
733
734 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000735 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 excp = &regs;
737 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200738
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return xmon_core(excp, 0);
740}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000741EXPORT_SYMBOL(xmon);
742
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000743irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000744{
745 unsigned long flags;
746 local_irq_save(flags);
747 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000748 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000749 local_irq_restore(flags);
750 return IRQ_HANDLED;
751}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000753static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754{
755 struct bpt *bp;
756 unsigned long offset;
757
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000758 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return 0;
760
761 /* Are we at the trap at bp->instr[1] for some bp? */
762 bp = in_breakpoint_table(regs->nip, &offset);
763 if (bp != NULL && offset == 4) {
764 regs->nip = bp->address + 4;
765 atomic_dec(&bp->ref_count);
766 return 1;
767 }
768
769 /* Are we at a breakpoint? */
770 bp = at_breakpoint(regs->nip);
771 if (!bp)
772 return 0;
773
774 xmon_core(regs, 0);
775
776 return 1;
777}
778
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000779static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
781 if (user_mode(regs))
782 return 0;
783 xmon_core(regs, 0);
784 return 1;
785}
786
Michael Neuling9422de32012-12-20 14:06:44 +0000787static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000789 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000791 if (dabr.enabled == 0)
792 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 xmon_core(regs, 0);
794 return 1;
795}
796
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000797static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000799 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000801 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 return 0;
803 xmon_core(regs, 0);
804 return 1;
805}
806
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000807static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808{
809#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000810 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 xmon_core(regs, 1);
812#endif
813 return 0;
814}
815
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000816static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817{
818 struct bpt *bp;
819 unsigned long offset;
820
821 if (in_xmon && catch_memory_errors)
822 handle_fault(regs); /* doesn't return */
823
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000824 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 bp = in_breakpoint_table(regs->nip, &offset);
826 if (bp != NULL) {
827 regs->nip = bp->address + offset;
828 atomic_dec(&bp->ref_count);
829 }
830 }
831
832 return 0;
833}
834
Michal Suchanek7daf5932018-05-23 20:00:54 +0200835/* Force enable xmon if not already enabled */
836static inline void force_enable_xmon(void)
837{
838 /* Enable xmon hooks if needed */
839 if (!xmon_on) {
840 printf("xmon: Enabling debugger hooks\n");
841 xmon_on = 1;
842 }
843}
844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845static struct bpt *at_breakpoint(unsigned long pc)
846{
847 int i;
848 struct bpt *bp;
849
850 bp = bpts;
851 for (i = 0; i < NBPTS; ++i, ++bp)
852 if (bp->enabled && pc == bp->address)
853 return bp;
854 return NULL;
855}
856
857static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
858{
859 unsigned long off;
860
861 off = nip - (unsigned long) bpts;
862 if (off >= sizeof(bpts))
863 return NULL;
864 off %= sizeof(struct bpt);
865 if (off != offsetof(struct bpt, instr[0])
866 && off != offsetof(struct bpt, instr[1]))
867 return NULL;
868 *offp = off - offsetof(struct bpt, instr[0]);
869 return (struct bpt *) (nip - off);
870}
871
872static struct bpt *new_breakpoint(unsigned long a)
873{
874 struct bpt *bp;
875
876 a &= ~3UL;
877 bp = at_breakpoint(a);
878 if (bp)
879 return bp;
880
881 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
882 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
883 bp->address = a;
884 bp->instr[1] = bpinstr;
885 store_inst(&bp->instr[1]);
886 return bp;
887 }
888 }
889
890 printf("Sorry, no free breakpoints. Please clear one first.\n");
891 return NULL;
892}
893
894static void insert_bpts(void)
895{
896 int i;
897 struct bpt *bp;
898
899 bp = bpts;
900 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100901 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 continue;
903 if (mread(bp->address, &bp->instr[0], 4) != 4) {
904 printf("Couldn't read instruction at %lx, "
905 "disabling breakpoint there\n", bp->address);
906 bp->enabled = 0;
907 continue;
908 }
909 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
910 printf("Breakpoint at %lx is on an mtmsrd or rfid "
911 "instruction, disabling it\n", bp->address);
912 bp->enabled = 0;
913 continue;
914 }
915 store_inst(&bp->instr[0]);
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100916 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 continue;
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000918 if (patch_instruction((unsigned int *)bp->address,
919 bpinstr) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 printf("Couldn't write instruction at %lx, "
921 "disabling breakpoint there\n", bp->address);
922 bp->enabled &= ~BP_TRAP;
923 continue;
924 }
925 store_inst((void *)bp->address);
926 }
927}
928
929static void insert_cpu_bpts(void)
930{
Michael Neuling9422de32012-12-20 14:06:44 +0000931 struct arch_hw_breakpoint brk;
932
933 if (dabr.enabled) {
934 brk.address = dabr.address;
935 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
936 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400937 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000938 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530939
940 if (iabr)
941 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942}
943
944static void remove_bpts(void)
945{
946 int i;
947 struct bpt *bp;
948 unsigned instr;
949
950 bp = bpts;
951 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100952 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 continue;
954 if (mread(bp->address, &instr, 4) == 4
955 && instr == bpinstr
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000956 && patch_instruction(
957 (unsigned int *)bp->address, bp->instr[0]) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 printf("Couldn't remove breakpoint at %lx\n",
959 bp->address);
960 else
961 store_inst((void *)bp->address);
962 }
963}
964
965static void remove_cpu_bpts(void)
966{
Michael Neuling9422de32012-12-20 14:06:44 +0000967 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530968 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969}
970
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300971/* Based on uptime_proc_show(). */
972static void
973show_uptime(void)
974{
Arnd Bergmannf6bd74f2018-06-18 11:56:24 +0200975 struct timespec64 uptime;
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300976
977 if (setjmp(bus_error_jmp) == 0) {
978 catch_memory_errors = 1;
979 sync();
980
Arnd Bergmannf6bd74f2018-06-18 11:56:24 +0200981 ktime_get_coarse_boottime_ts64(&uptime);
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300982 printf("Uptime: %lu.%.2lu seconds\n", (unsigned long)uptime.tv_sec,
983 ((unsigned long)uptime.tv_nsec / (NSEC_PER_SEC/100)));
984
985 sync();
986 __delay(200); \
987 }
988 catch_memory_errors = 0;
989}
990
Sam bobroff958b7c82015-10-08 11:50:23 +1100991static void set_lpp_cmd(void)
992{
993 unsigned long lpp;
994
995 if (!scanhex(&lpp)) {
996 printf("Invalid number.\n");
997 lpp = 0;
998 }
999 xmon_set_pagination_lpp(lpp);
1000}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001/* Command interpreting routine */
1002static char *last_cmd;
1003
1004static int
1005cmds(struct pt_regs *excp)
1006{
1007 int cmd = 0;
1008
1009 last_cmd = NULL;
1010 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +02001011
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03001012 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
Olaf Hering26c8af52006-09-08 16:29:21 +02001013
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 for(;;) {
1015#ifdef CONFIG_SMP
1016 printf("%x:", smp_processor_id());
1017#endif /* CONFIG_SMP */
1018 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 flush_input();
1020 termch = 0;
1021 cmd = skipbl();
1022 if( cmd == '\n' ) {
1023 if (last_cmd == NULL)
1024 continue;
1025 take_input(last_cmd);
1026 last_cmd = NULL;
1027 cmd = inchar();
1028 }
1029 switch (cmd) {
1030 case 'm':
1031 cmd = inchar();
1032 switch (cmd) {
1033 case 'm':
1034 case 's':
1035 case 'd':
1036 memops(cmd);
1037 break;
1038 case 'l':
1039 memlocate();
1040 break;
1041 case 'z':
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05001042 if (xmon_is_ro) {
1043 printf(xmon_ro_msg);
1044 break;
1045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 memzcan();
1047 break;
1048 case 'i':
Michal Hocko9af744d2017-02-22 15:46:16 -08001049 show_mem(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 break;
1051 default:
1052 termch = cmd;
1053 memex();
1054 }
1055 break;
1056 case 'd':
1057 dump();
1058 break;
1059 case 'l':
1060 symbol_lookup();
1061 break;
1062 case 'r':
1063 prregs(excp); /* print regs */
1064 break;
1065 case 'e':
1066 excprint(excp);
1067 break;
1068 case 'S':
1069 super_regs();
1070 break;
1071 case 't':
1072 backtrace(excp);
1073 break;
1074 case 'f':
1075 cacheflush();
1076 break;
1077 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +02001078 if (do_spu_cmd() == 0)
1079 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if (do_step(excp))
1081 return cmd;
1082 break;
1083 case 'x':
1084 case 'X':
Breno Leitaoed49f7f2017-08-02 17:14:06 -03001085 if (tracing_enabled)
1086 tracing_on();
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001087 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001089 printf(" <no input ...>\n");
1090 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 return cmd;
1092 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +10001093 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 break;
Sam bobroff958b7c82015-10-08 11:50:23 +11001095 case '#':
1096 set_lpp_cmd();
1097 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 case 'b':
1099 bpt_cmds();
1100 break;
1101 case 'C':
1102 csum();
1103 break;
1104 case 'c':
1105 if (cpu_cmd())
1106 return 0;
1107 break;
1108 case 'z':
1109 bootcmds();
1110 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001111 case 'p':
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05001112 if (xmon_is_ro) {
1113 printf(xmon_ro_msg);
1114 break;
1115 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001116 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -06001118 case 'P':
1119 show_tasks();
1120 break;
Christophe Leroy5b3e84f2018-11-17 10:25:04 +00001121#ifdef CONFIG_PPC_BOOK3S
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 case 'u':
1123 dump_segments();
1124 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +11001125#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11001126 case 'u':
1127 dump_tlb_44x();
1128 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +00001129#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10001130 case 'u':
1131 dump_tlb_book3e();
1132 break;
1133#endif
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -03001134 case 'U':
1135 show_uptime();
1136 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 default:
1138 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +00001139 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 if (' ' < cmd && cmd <= '~')
1141 putchar(cmd);
1142 else
1143 printf("\\x%x", cmd);
1144 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +00001145 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 printf(" (type ? for help)\n");
1147 break;
1148 }
1149 }
1150}
1151
Josh Boyercdd39042009-10-05 04:46:05 +00001152#ifdef CONFIG_BOOKE
1153static int do_step(struct pt_regs *regs)
1154{
1155 regs->msr |= MSR_DE;
1156 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1157 return 1;
1158}
1159#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160/*
1161 * Step a single instruction.
1162 * Some instructions we emulate, others we execute with MSR_SE set.
1163 */
1164static int do_step(struct pt_regs *regs)
1165{
1166 unsigned int instr;
1167 int stepped;
1168
Michal Suchanek7daf5932018-05-23 20:00:54 +02001169 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001171 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 if (mread(regs->nip, &instr, 4) == 4) {
1173 stepped = emulate_step(regs, instr);
1174 if (stepped < 0) {
1175 printf("Couldn't single-step %s instruction\n",
1176 (IS_RFID(instr)? "rfid": "mtmsrd"));
1177 return 0;
1178 }
1179 if (stepped > 0) {
1180 regs->trap = 0xd00 | (regs->trap & 1);
1181 printf("stepped to ");
1182 xmon_print_symbol(regs->nip, " ", "\n");
1183 ppc_inst_dump(regs->nip, 1, 0);
1184 return 0;
1185 }
1186 }
1187 }
1188 regs->msr |= MSR_SE;
1189 return 1;
1190}
Josh Boyercdd39042009-10-05 04:46:05 +00001191#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
1193static void bootcmds(void)
1194{
1195 int cmd;
1196
1197 cmd = inchar();
1198 if (cmd == 'r')
1199 ppc_md.restart(NULL);
1200 else if (cmd == 'h')
1201 ppc_md.halt();
1202 else if (cmd == 'p')
Alexander Graf9178ba22014-10-13 16:01:09 +02001203 if (pm_power_off)
1204 pm_power_off();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205}
1206
1207static int cpu_cmd(void)
1208{
1209#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001210 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213 if (!scanhex(&cpu)) {
1214 /* print cpus waiting or in xmon */
1215 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001216 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001217 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001218 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001219 if (cpu == last_cpu + 1) {
1220 last_cpu = cpu;
1221 } else {
1222 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001223 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001224 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001225 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 }
1228 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001229 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001230 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 printf("\n");
1232 return 0;
1233 }
1234 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001235 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001236 printf("cpu 0x%lx isn't in xmon\n", cpu);
Michael Ellerman7b087292018-05-02 23:07:26 +10001237#ifdef CONFIG_PPC64
1238 printf("backtrace of paca[0x%lx].saved_r1 (possibly stale):\n", cpu);
1239 xmon_show_stack(paca_ptrs[cpu]->saved_r1, 0, 0);
1240#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 return 0;
1242 }
1243 xmon_taken = 0;
1244 mb();
1245 xmon_owner = cpu;
1246 timeout = 10000000;
1247 while (!xmon_taken) {
1248 if (--timeout == 0) {
1249 if (test_and_set_bit(0, &xmon_taken))
1250 break;
1251 /* take control back */
1252 mb();
1253 xmon_owner = smp_processor_id();
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001254 printf("cpu 0x%lx didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 return 0;
1256 }
1257 barrier();
1258 }
1259 return 1;
1260#else
1261 return 0;
1262#endif /* CONFIG_SMP */
1263}
1264
1265static unsigned short fcstab[256] = {
1266 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1267 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1268 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1269 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1270 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1271 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1272 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1273 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1274 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1275 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1276 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1277 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1278 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1279 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1280 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1281 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1282 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1283 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1284 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1285 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1286 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1287 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1288 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1289 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1290 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1291 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1292 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1293 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1294 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1295 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1296 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1297 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1298};
1299
1300#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1301
1302static void
1303csum(void)
1304{
1305 unsigned int i;
1306 unsigned short fcs;
1307 unsigned char v;
1308
1309 if (!scanhex(&adrs))
1310 return;
1311 if (!scanhex(&ncsum))
1312 return;
1313 fcs = 0xffff;
1314 for (i = 0; i < ncsum; ++i) {
1315 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001316 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 break;
1318 }
1319 fcs = FCS(fcs, v);
1320 }
1321 printf("%x\n", fcs);
1322}
1323
1324/*
1325 * Check if this is a suitable place to put a breakpoint.
1326 */
1327static long check_bp_loc(unsigned long addr)
1328{
1329 unsigned int instr;
1330
1331 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001332 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 printf("Breakpoints may only be placed at kernel addresses\n");
1334 return 0;
1335 }
1336 if (!mread(addr, &instr, sizeof(instr))) {
1337 printf("Can't read instruction at address %lx\n", addr);
1338 return 0;
1339 }
1340 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1341 printf("Breakpoints may not be placed on mtmsrd or rfid "
1342 "instructions\n");
1343 return 0;
1344 }
1345 return 1;
1346}
1347
Michael Ellermane3bc8042012-08-23 22:09:13 +00001348static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 "Breakpoint command usage:\n"
1350 "b show breakpoints\n"
1351 "b <addr> [cnt] set breakpoint at given instr addr\n"
1352 "bc clear all breakpoints\n"
1353 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301354 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 "bd <addr> [cnt] set hardware data breakpoint\n"
1356 "";
1357
1358static void
1359bpt_cmds(void)
1360{
1361 int cmd;
1362 unsigned long a;
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001363 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 struct bpt *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
1366 cmd = inchar();
Christopher M. Riedl96664de2019-09-07 01:11:23 -05001367
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 switch (cmd) {
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001369#ifndef CONFIG_PPC_8xx
1370 static const char badaddr[] = "Only kernel addresses are permitted for breakpoints\n";
1371 int mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 case 'd': /* bd - hardware data breakpoint */
Christopher M. Riedl96664de2019-09-07 01:11:23 -05001373 if (xmon_is_ro) {
1374 printf(xmon_ro_msg);
1375 break;
1376 }
Michael Neuling9bc2bd52018-03-27 15:37:19 +11001377 if (!ppc_breakpoint_available()) {
1378 printf("Hardware data breakpoint not supported on this cpu\n");
1379 break;
1380 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 mode = 7;
1382 cmd = inchar();
1383 if (cmd == 'r')
1384 mode = 5;
1385 else if (cmd == 'w')
1386 mode = 6;
1387 else
1388 termch = cmd;
1389 dabr.address = 0;
1390 dabr.enabled = 0;
1391 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001392 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 printf(badaddr);
1394 break;
1395 }
Michael Neuling9422de32012-12-20 14:06:44 +00001396 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 dabr.enabled = mode | BP_DABR;
1398 }
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301399
1400 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 break;
1402
1403 case 'i': /* bi - hardware instr breakpoint */
Christopher M. Riedl96664de2019-09-07 01:11:23 -05001404 if (xmon_is_ro) {
1405 printf(xmon_ro_msg);
1406 break;
1407 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301408 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 printf("Hardware instruction breakpoint "
1410 "not supported on this cpu\n");
1411 break;
1412 }
1413 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001414 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 iabr = NULL;
1416 }
1417 if (!scanhex(&a))
1418 break;
1419 if (!check_bp_loc(a))
1420 break;
1421 bp = new_breakpoint(a);
1422 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001423 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 iabr = bp;
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301425 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 }
1427 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001428#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
1430 case 'c':
1431 if (!scanhex(&a)) {
1432 /* clear all breakpoints */
1433 for (i = 0; i < NBPTS; ++i)
1434 bpts[i].enabled = 0;
1435 iabr = NULL;
1436 dabr.enabled = 0;
1437 printf("All breakpoints cleared\n");
1438 break;
1439 }
1440
1441 if (a <= NBPTS && a >= 1) {
1442 /* assume a breakpoint number */
1443 bp = &bpts[a-1]; /* bp nums are 1 based */
1444 } else {
1445 /* assume a breakpoint address */
1446 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001447 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001448 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 break;
1450 }
1451 }
1452
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001453 printf("Cleared breakpoint %tx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 xmon_print_symbol(bp->address, " ", ")\n");
1455 bp->enabled = 0;
1456 break;
1457
1458 default:
1459 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001460 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 if (cmd == '?') {
1462 printf(breakpoint_help_string);
1463 break;
1464 }
1465 termch = cmd;
Christopher M. Riedl96664de2019-09-07 01:11:23 -05001466
1467 if (xmon_is_ro || !scanhex(&a)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 /* print all breakpoints */
1469 printf(" type address\n");
1470 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001471 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 if (dabr.enabled & 1)
1473 printf("r");
1474 if (dabr.enabled & 2)
1475 printf("w");
1476 printf("]\n");
1477 }
1478 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1479 if (!bp->enabled)
1480 continue;
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001481 printf("%tx %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001482 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 xmon_print_symbol(bp->address, " ", "\n");
1484 }
1485 break;
1486 }
1487
1488 if (!check_bp_loc(a))
1489 break;
1490 bp = new_breakpoint(a);
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301491 if (bp != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 bp->enabled |= BP_TRAP;
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301493 force_enable_xmon();
1494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 break;
1496 }
1497}
1498
1499/* Very cheap human name for vector lookup. */
1500static
1501const char *getvecname(unsigned long vec)
1502{
1503 char *ret;
1504
1505 switch (vec) {
1506 case 0x100: ret = "(System Reset)"; break;
1507 case 0x200: ret = "(Machine Check)"; break;
1508 case 0x300: ret = "(Data Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001509 case 0x380:
1510 if (radix_enabled())
1511 ret = "(Data Access Out of Range)";
1512 else
1513 ret = "(Data SLB Access)";
1514 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 case 0x400: ret = "(Instruction Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001516 case 0x480:
1517 if (radix_enabled())
1518 ret = "(Instruction Access Out of Range)";
1519 else
1520 ret = "(Instruction SLB Access)";
1521 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 case 0x500: ret = "(Hardware Interrupt)"; break;
1523 case 0x600: ret = "(Alignment)"; break;
1524 case 0x700: ret = "(Program Check)"; break;
1525 case 0x800: ret = "(FPU Unavailable)"; break;
1526 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001527 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1528 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 case 0xc00: ret = "(System Call)"; break;
1530 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001531 case 0xe40: ret = "(Emulation Assist)"; break;
1532 case 0xe60: ret = "(HMI)"; break;
1533 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 case 0xf00: ret = "(Performance Monitor)"; break;
1535 case 0xf20: ret = "(Altivec Unavailable)"; break;
1536 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001537 case 0x1500: ret = "(Denormalisation)"; break;
1538 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 default: ret = "";
1540 }
1541 return ret;
1542}
1543
1544static void get_function_bounds(unsigned long pc, unsigned long *startp,
1545 unsigned long *endp)
1546{
1547 unsigned long size, offset;
1548 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
1550 *startp = *endp = 0;
1551 if (pc == 0)
1552 return;
1553 if (setjmp(bus_error_jmp) == 0) {
1554 catch_memory_errors = 1;
1555 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001556 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 if (name != NULL) {
1558 *startp = pc - offset;
1559 *endp = pc - offset + size;
1560 }
1561 sync();
1562 }
1563 catch_memory_errors = 0;
1564}
1565
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001566#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1567#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1568
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569static void xmon_show_stack(unsigned long sp, unsigned long lr,
1570 unsigned long pc)
1571{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001572 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 unsigned long ip;
1574 unsigned long newsp;
1575 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 struct pt_regs regs;
1577
Michael Ellerman0104cd62012-10-09 04:20:36 +00001578 while (max_to_print--) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301579 if (!is_kernel_addr(sp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 if (sp != 0)
1581 printf("SP (%lx) is in userspace\n", sp);
1582 break;
1583 }
1584
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001585 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 || !mread(sp, &newsp, sizeof(unsigned long))) {
1587 printf("Couldn't read stack frame at %lx\n", sp);
1588 break;
1589 }
1590
1591 /*
1592 * For the first stack frame, try to work out if
1593 * LR and/or the saved LR value in the bottommost
1594 * stack frame are valid.
1595 */
1596 if ((pc | lr) != 0) {
1597 unsigned long fnstart, fnend;
1598 unsigned long nextip;
1599 int printip = 1;
1600
1601 get_function_bounds(pc, &fnstart, &fnend);
1602 nextip = 0;
1603 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001604 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 sizeof(unsigned long));
1606 if (lr == ip) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301607 if (!is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 || (fnstart <= lr && lr < fnend))
1609 printip = 0;
1610 } else if (lr == nextip) {
1611 printip = 0;
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301612 } else if (is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 && !(fnstart <= lr && lr < fnend)) {
1614 printf("[link register ] ");
1615 xmon_print_symbol(lr, " ", "\n");
1616 }
1617 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001618 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 xmon_print_symbol(ip, " ", " (unreliable)\n");
1620 }
1621 pc = lr = 0;
1622
1623 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001624 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 xmon_print_symbol(ip, " ", "\n");
1626 }
1627
1628 /* Look for "regshere" marker to see if this is
1629 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001630 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001631 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001632 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 != sizeof(regs)) {
1634 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001635 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 break;
1637 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001638 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 getvecname(TRAP(&regs)));
1640 pc = regs.nip;
1641 lr = regs.link;
1642 xmon_print_symbol(pc, " ", "\n");
1643 }
1644
1645 if (newsp == 0)
1646 break;
1647
1648 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650}
1651
1652static void backtrace(struct pt_regs *excp)
1653{
1654 unsigned long sp;
1655
1656 if (scanhex(&sp))
1657 xmon_show_stack(sp, 0, 0);
1658 else
1659 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1660 scannl();
1661}
1662
1663static void print_bug_trap(struct pt_regs *regs)
1664{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001665#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001666 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 unsigned long addr;
1668
1669 if (regs->msr & MSR_PR)
1670 return; /* not in kernel */
1671 addr = regs->nip; /* address of trap instruction */
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301672 if (!is_kernel_addr(addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 return;
1674 bug = find_bug(regs->nip);
1675 if (bug == NULL)
1676 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001677 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 return;
1679
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001680#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001681 printf("kernel BUG at %s:%u!\n",
1682 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001683#else
Michael Ellermand8104182017-12-06 23:23:28 +11001684 printf("kernel BUG at %px!\n", (void *)bug->bug_addr);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001685#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001686#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687}
1688
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001689static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690{
1691 unsigned long trap;
1692
1693#ifdef CONFIG_SMP
1694 printf("cpu 0x%x: ", smp_processor_id());
1695#endif /* CONFIG_SMP */
1696
1697 trap = TRAP(fp);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001698 printf("Vector: %lx %s at [%px]\n", fp->trap, getvecname(trap), fp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 printf(" pc: ");
1700 xmon_print_symbol(fp->nip, ": ", "\n");
1701
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001702 printf(" lr: ");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 xmon_print_symbol(fp->link, ": ", "\n");
1704
1705 printf(" sp: %lx\n", fp->gpr[1]);
1706 printf(" msr: %lx\n", fp->msr);
1707
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001708 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 printf(" dar: %lx\n", fp->dar);
1710 if (trap != 0x380)
1711 printf(" dsisr: %lx\n", fp->dsisr);
1712 }
1713
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001714 printf(" current = 0x%px\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001715#ifdef CONFIG_PPC64
Nicholas Piggin3130a7b2018-05-10 11:04:24 +10001716 printf(" paca = 0x%px\t irqmask: 0x%02x\t irq_happened: 0x%02x\n",
Madhavan Srinivasan4e26bc42017-12-20 09:25:50 +05301717 local_paca, local_paca->irq_soft_mask, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001718#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 if (current) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001720 printf(" pid = %d, comm = %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 current->pid, current->comm);
1722 }
1723
1724 if (trap == 0x700)
1725 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001726
1727 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728}
1729
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001730static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001732 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 unsigned long base;
1734 struct pt_regs regs;
1735
1736 if (scanhex(&base)) {
1737 if (setjmp(bus_error_jmp) == 0) {
1738 catch_memory_errors = 1;
1739 sync();
1740 regs = *(struct pt_regs *)base;
1741 sync();
1742 __delay(200);
1743 } else {
1744 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001745 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 base);
1747 return;
1748 }
1749 catch_memory_errors = 0;
1750 fp = &regs;
1751 }
1752
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001753#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 if (FULL_REGS(fp)) {
1755 for (n = 0; n < 16; ++n)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001756 printf("R%.2d = "REG" R%.2d = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1758 } else {
1759 for (n = 0; n < 7; ++n)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001760 printf("R%.2d = "REG" R%.2d = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1762 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001763#else
1764 for (n = 0; n < 32; ++n) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001765 printf("R%.2d = %.8lx%s", n, fp->gpr[n],
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001766 (n & 3) == 3? "\n": " ");
1767 if (n == 12 && !FULL_REGS(fp)) {
1768 printf("\n");
1769 break;
1770 }
1771 }
1772#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 printf("pc = ");
1774 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001775 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1776 printf("cfar= ");
1777 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 printf("lr = ");
1780 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001781 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1782 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001784 trap = TRAP(fp);
1785 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1786 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787}
1788
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001789static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790{
1791 int cmd;
1792 unsigned long nflush;
1793
1794 cmd = inchar();
1795 if (cmd != 'i')
1796 termch = cmd;
1797 scanhex((void *)&adrs);
1798 if (termch != '\n')
1799 termch = 0;
1800 nflush = 1;
1801 scanhex(&nflush);
1802 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1803 if (setjmp(bus_error_jmp) == 0) {
1804 catch_memory_errors = 1;
1805 sync();
1806
1807 if (cmd != 'i') {
1808 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1809 cflush((void *) adrs);
1810 } else {
1811 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1812 cinval((void *) adrs);
1813 }
1814 sync();
1815 /* wait a little while to see if we get a machine check */
1816 __delay(200);
1817 }
1818 catch_memory_errors = 0;
1819}
1820
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001821extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1822extern void xmon_mtspr(int spr, unsigned long value);
1823
1824static int
1825read_spr(int n, unsigned long *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 unsigned long ret = -1UL;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001828 int ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
1830 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001831 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 sync();
1833
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001834 ret = xmon_mfspr(n, *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835
1836 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001837 *vp = ret;
1838 ok = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001840 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001842 return ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843}
1844
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001845static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846write_spr(int n, unsigned long val)
1847{
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05001848 if (xmon_is_ro) {
1849 printf(xmon_ro_msg);
1850 return;
1851 }
1852
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001854 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 sync();
1856
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001857 xmon_mtspr(n, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858
1859 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001860 } else {
1861 printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001863 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864}
1865
Michael Ellerman18461932016-07-07 22:54:29 +10001866static void dump_206_sprs(void)
1867{
1868#ifdef CONFIG_PPC64
1869 if (!cpu_has_feature(CPU_FTR_ARCH_206))
1870 return;
1871
1872 /* Actually some of these pre-date 2.06, but whatevs */
1873
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001874 printf("srr0 = %.16lx srr1 = %.16lx dsisr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001875 mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001876 printf("dscr = %.16lx ppr = %.16lx pir = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001877 mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001878 printf("amr = %.16lx uamor = %.16lx\n",
1879 mfspr(SPRN_AMR), mfspr(SPRN_UAMOR));
Michael Ellerman18461932016-07-07 22:54:29 +10001880
1881 if (!(mfmsr() & MSR_HV))
1882 return;
1883
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001884 printf("sdr1 = %.16lx hdar = %.16lx hdsisr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001885 mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001886 printf("hsrr0 = %.16lx hsrr1 = %.16lx hdec = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001887 mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001888 printf("lpcr = %.16lx pcr = %.16lx lpidr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001889 mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001890 printf("hsprg0 = %.16lx hsprg1 = %.16lx amor = %.16lx\n",
1891 mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1), mfspr(SPRN_AMOR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001892 printf("dabr = %.16lx dabrx = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10001893 mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
1894#endif
1895}
1896
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001897static void dump_207_sprs(void)
1898{
1899#ifdef CONFIG_PPC64
1900 unsigned long msr;
1901
1902 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
1903 return;
1904
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001905 printf("dpdes = %.16lx tir = %.16lx cir = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001906 mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
1907
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001908 printf("fscr = %.16lx tar = %.16lx pspb = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001909 mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
1910
1911 msr = mfmsr();
1912 if (msr & MSR_TM) {
1913 /* Only if TM has been enabled in the kernel */
Balbir Singhc47a9402017-08-29 17:22:36 +10001914 printf("tfhar = %.16lx tfiar = %.16lx texasr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001915 mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
1916 mfspr(SPRN_TEXASR));
1917 }
1918
Balbir Singhc47a9402017-08-29 17:22:36 +10001919 printf("mmcr0 = %.16lx mmcr1 = %.16lx mmcr2 = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001920 mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001921 printf("pmc1 = %.8lx pmc2 = %.8lx pmc3 = %.8lx pmc4 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001922 mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
1923 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001924 printf("mmcra = %.16lx siar = %.16lx pmc5 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001925 mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001926 printf("sdar = %.16lx sier = %.16lx pmc6 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001927 mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
Balbir Singhc47a9402017-08-29 17:22:36 +10001928 printf("ebbhr = %.16lx ebbrr = %.16lx bescr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001929 mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10001930 printf("iamr = %.16lx\n", mfspr(SPRN_IAMR));
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001931
1932 if (!(msr & MSR_HV))
1933 return;
1934
Balbir Singhc47a9402017-08-29 17:22:36 +10001935 printf("hfscr = %.16lx dhdes = %.16lx rpr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001936 mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
Balbir Singhc47a9402017-08-29 17:22:36 +10001937 printf("dawr = %.16lx dawrx = %.16lx ciabr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10001938 mfspr(SPRN_DAWR), mfspr(SPRN_DAWRX), mfspr(SPRN_CIABR));
1939#endif
1940}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941
Balbir Singhd1e1b352017-08-30 21:45:09 +10001942static void dump_300_sprs(void)
1943{
1944#ifdef CONFIG_PPC64
1945 bool hv = mfmsr() & MSR_HV;
1946
1947 if (!cpu_has_feature(CPU_FTR_ARCH_300))
1948 return;
1949
1950 printf("pidr = %.16lx tidr = %.16lx\n",
1951 mfspr(SPRN_PID), mfspr(SPRN_TIDR));
1952 printf("asdr = %.16lx psscr = %.16lx\n",
1953 mfspr(SPRN_ASDR), hv ? mfspr(SPRN_PSSCR)
1954 : mfspr(SPRN_PSSCR_PR));
1955
1956 if (!hv)
1957 return;
1958
1959 printf("ptcr = %.16lx\n",
1960 mfspr(SPRN_PTCR));
1961#endif
1962}
1963
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001964static void dump_one_spr(int spr, bool show_unimplemented)
1965{
1966 unsigned long val;
1967
1968 val = 0xdeadbeef;
1969 if (!read_spr(spr, &val)) {
1970 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1971 return;
1972 }
1973
1974 if (val == 0xdeadbeef) {
1975 /* Looks like read was a nop, confirm */
1976 val = 0x0badcafe;
1977 if (!read_spr(spr, &val)) {
1978 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
1979 return;
1980 }
1981
1982 if (val == 0x0badcafe) {
1983 if (show_unimplemented)
1984 printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
1985 return;
1986 }
1987 }
1988
1989 printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
1990}
1991
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001992static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993{
Michael Ellerman13629da2016-07-07 22:54:27 +10001994 static unsigned long regno;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 int cmd;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001996 int spr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997
1998 cmd = skipbl();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001999
2000 switch (cmd) {
2001 case '\n': {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002002 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 asm("mr %0,1" : "=r" (sp) :);
2004 asm("mr %0,2" : "=r" (toc) :);
2005
Michael Ellerman56346ad2016-07-07 22:54:28 +10002006 printf("msr = "REG" sprg0 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002007 mfmsr(), mfspr(SPRN_SPRG0));
Michael Ellerman56346ad2016-07-07 22:54:28 +10002008 printf("pvr = "REG" sprg1 = "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00002009 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Michael Ellerman56346ad2016-07-07 22:54:28 +10002010 printf("dec = "REG" sprg2 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002011 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
Michael Ellerman56346ad2016-07-07 22:54:28 +10002012 printf("sp = "REG" sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
2013 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
2014
Michael Ellerman18461932016-07-07 22:54:29 +10002015 dump_206_sprs();
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002016 dump_207_sprs();
Balbir Singhd1e1b352017-08-30 21:45:09 +10002017 dump_300_sprs();
Michael Ellerman18461932016-07-07 22:54:29 +10002018
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 return;
2020 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10002021 case 'w': {
2022 unsigned long val;
2023 scanhex(&regno);
2024 val = 0;
2025 read_spr(regno, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 scanhex(&val);
2027 write_spr(regno, val);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10002028 dump_one_spr(regno, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10002031 case 'r':
2032 scanhex(&regno);
2033 dump_one_spr(regno, true);
2034 break;
2035 case 'a':
2036 /* dump ALL SPRs */
2037 for (spr = 1; spr < 1024; ++spr)
2038 dump_one_spr(spr, false);
2039 break;
2040 }
2041
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 scannl();
2043}
2044
2045/*
2046 * Stuff for reading and writing memory safely
2047 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002048static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049mread(unsigned long adrs, void *buf, int size)
2050{
2051 volatile int n;
2052 char *p, *q;
2053
2054 n = 0;
2055 if (setjmp(bus_error_jmp) == 0) {
2056 catch_memory_errors = 1;
2057 sync();
2058 p = (char *)adrs;
2059 q = (char *)buf;
2060 switch (size) {
2061 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002062 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 break;
2064 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002065 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 break;
2067 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002068 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 break;
2070 default:
2071 for( ; n < size; ++n) {
2072 *q++ = *p++;
2073 sync();
2074 }
2075 }
2076 sync();
2077 /* wait a little while to see if we get a machine check */
2078 __delay(200);
2079 n = size;
2080 }
2081 catch_memory_errors = 0;
2082 return n;
2083}
2084
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002085static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086mwrite(unsigned long adrs, void *buf, int size)
2087{
2088 volatile int n;
2089 char *p, *q;
2090
2091 n = 0;
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05002092
2093 if (xmon_is_ro) {
2094 printf(xmon_ro_msg);
2095 return n;
2096 }
2097
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 if (setjmp(bus_error_jmp) == 0) {
2099 catch_memory_errors = 1;
2100 sync();
2101 p = (char *) adrs;
2102 q = (char *) buf;
2103 switch (size) {
2104 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002105 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 break;
2107 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002108 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 break;
2110 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002111 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 break;
2113 default:
2114 for ( ; n < size; ++n) {
2115 *p++ = *q++;
2116 sync();
2117 }
2118 }
2119 sync();
2120 /* wait a little while to see if we get a machine check */
2121 __delay(200);
2122 n = size;
2123 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10002124 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 }
2126 catch_memory_errors = 0;
2127 return n;
2128}
2129
2130static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002131static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132static char *fault_chars[] = { "--", "**", "##" };
2133
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002134static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002136 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 switch (TRAP(regs)) {
2138 case 0x200:
2139 fault_type = 0;
2140 break;
2141 case 0x300:
2142 case 0x380:
2143 fault_type = 1;
2144 break;
2145 default:
2146 fault_type = 2;
2147 }
2148
2149 longjmp(bus_error_jmp, 1);
2150
2151 return 0;
2152}
2153
2154#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
2155
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002156static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157byterev(unsigned char *val, int size)
2158{
2159 int t;
2160
2161 switch (size) {
2162 case 2:
2163 SWAP(val[0], val[1], t);
2164 break;
2165 case 4:
2166 SWAP(val[0], val[3], t);
2167 SWAP(val[1], val[2], t);
2168 break;
2169 case 8: /* is there really any use for this? */
2170 SWAP(val[0], val[7], t);
2171 SWAP(val[1], val[6], t);
2172 SWAP(val[2], val[5], t);
2173 SWAP(val[3], val[4], t);
2174 break;
2175 }
2176}
2177
2178static int brev;
2179static int mnoread;
2180
Michael Ellermane3bc8042012-08-23 22:09:13 +00002181static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 "Memory examine command usage:\n"
2183 "m [addr] [flags] examine/change memory\n"
2184 " addr is optional. will start where left off.\n"
2185 " flags may include chars from this set:\n"
2186 " b modify by bytes (default)\n"
2187 " w modify by words (2 byte)\n"
2188 " l modify by longs (4 byte)\n"
2189 " d modify by doubleword (8 byte)\n"
2190 " r toggle reverse byte order mode\n"
2191 " n do not read memory (for i/o spaces)\n"
2192 " . ok to read (default)\n"
2193 "NOTE: flags are saved as defaults\n"
2194 "";
2195
Michael Ellermane3bc8042012-08-23 22:09:13 +00002196static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 "Memory examine subcommands:\n"
2198 " hexval write this val to current location\n"
2199 " 'string' write chars from string to this location\n"
2200 " ' increment address\n"
2201 " ^ decrement address\n"
2202 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
2203 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
2204 " ` clear no-read flag\n"
2205 " ; stay at this addr\n"
2206 " v change to byte mode\n"
2207 " w change to word (2 byte) mode\n"
2208 " l change to long (4 byte) mode\n"
2209 " u change to doubleword (8 byte) mode\n"
2210 " m addr change current addr\n"
2211 " n toggle no-read flag\n"
2212 " r toggle byte reverse flag\n"
2213 " < count back up count bytes\n"
2214 " > count skip forward count bytes\n"
2215 " x exit this mode\n"
2216 "";
2217
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002218static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219memex(void)
2220{
2221 int cmd, inc, i, nslash;
2222 unsigned long n;
2223 unsigned char val[16];
2224
2225 scanhex((void *)&adrs);
2226 cmd = skipbl();
2227 if (cmd == '?') {
2228 printf(memex_help_string);
2229 return;
2230 } else {
2231 termch = cmd;
2232 }
2233 last_cmd = "m\n";
2234 while ((cmd = skipbl()) != '\n') {
2235 switch( cmd ){
2236 case 'b': size = 1; break;
2237 case 'w': size = 2; break;
2238 case 'l': size = 4; break;
2239 case 'd': size = 8; break;
2240 case 'r': brev = !brev; break;
2241 case 'n': mnoread = 1; break;
2242 case '.': mnoread = 0; break;
2243 }
2244 }
2245 if( size <= 0 )
2246 size = 1;
2247 else if( size > 8 )
2248 size = 8;
2249 for(;;){
2250 if (!mnoread)
2251 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002252 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 if (!mnoread) {
2254 if (brev)
2255 byterev(val, size);
2256 putchar(' ');
2257 for (i = 0; i < n; ++i)
2258 printf("%.2x", val[i]);
2259 for (; i < size; ++i)
2260 printf("%s", fault_chars[fault_type]);
2261 }
2262 putchar(' ');
2263 inc = size;
2264 nslash = 0;
2265 for(;;){
2266 if( scanhex(&n) ){
2267 for (i = 0; i < size; ++i)
2268 val[i] = n >> (i * 8);
2269 if (!brev)
2270 byterev(val, size);
2271 mwrite(adrs, val, size);
2272 inc = size;
2273 }
2274 cmd = skipbl();
2275 if (cmd == '\n')
2276 break;
2277 inc = 0;
2278 switch (cmd) {
2279 case '\'':
2280 for(;;){
2281 n = inchar();
2282 if( n == '\\' )
2283 n = bsesc();
2284 else if( n == '\'' )
2285 break;
2286 for (i = 0; i < size; ++i)
2287 val[i] = n >> (i * 8);
2288 if (!brev)
2289 byterev(val, size);
2290 mwrite(adrs, val, size);
2291 adrs += size;
2292 }
2293 adrs -= size;
2294 inc = size;
2295 break;
2296 case ',':
2297 adrs += size;
2298 break;
2299 case '.':
2300 mnoread = 0;
2301 break;
2302 case ';':
2303 break;
2304 case 'x':
2305 case EOF:
2306 scannl();
2307 return;
2308 case 'b':
2309 case 'v':
2310 size = 1;
2311 break;
2312 case 'w':
2313 size = 2;
2314 break;
2315 case 'l':
2316 size = 4;
2317 break;
2318 case 'u':
2319 size = 8;
2320 break;
2321 case '^':
2322 adrs -= size;
2323 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 case '/':
2325 if (nslash > 0)
2326 adrs -= 1 << nslash;
2327 else
2328 nslash = 0;
2329 nslash += 4;
2330 adrs += 1 << nslash;
2331 break;
2332 case '\\':
2333 if (nslash < 0)
2334 adrs += 1 << -nslash;
2335 else
2336 nslash = 0;
2337 nslash -= 4;
2338 adrs -= 1 << -nslash;
2339 break;
2340 case 'm':
2341 scanhex((void *)&adrs);
2342 break;
2343 case 'n':
2344 mnoread = 1;
2345 break;
2346 case 'r':
2347 brev = !brev;
2348 break;
2349 case '<':
2350 n = size;
2351 scanhex(&n);
2352 adrs -= n;
2353 break;
2354 case '>':
2355 n = size;
2356 scanhex(&n);
2357 adrs += n;
2358 break;
2359 case '?':
2360 printf(memex_subcmd_help_string);
2361 break;
2362 }
2363 }
2364 adrs += inc;
2365 }
2366}
2367
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002368static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369bsesc(void)
2370{
2371 int c;
2372
2373 c = inchar();
2374 switch( c ){
2375 case 'n': c = '\n'; break;
2376 case 'r': c = '\r'; break;
2377 case 'b': c = '\b'; break;
2378 case 't': c = '\t'; break;
2379 }
2380 return c;
2381}
2382
Olaf Hering7e5b5932006-03-08 20:40:28 +01002383static void xmon_rawdump (unsigned long adrs, long ndump)
2384{
2385 long n, m, r, nr;
2386 unsigned char temp[16];
2387
2388 for (n = ndump; n > 0;) {
2389 r = n < 16? n: 16;
2390 nr = mread(adrs, temp, r);
2391 adrs += nr;
2392 for (m = 0; m < r; ++m) {
2393 if (m < nr)
2394 printf("%.2x", temp[m]);
2395 else
2396 printf("%s", fault_chars[fault_type]);
2397 }
2398 n -= r;
2399 if (nr < r)
2400 break;
2401 }
2402 printf("\n");
2403}
2404
Breno Leitao4125d012017-08-02 17:14:05 -03002405static void dump_tracing(void)
2406{
2407 int c;
2408
2409 c = inchar();
2410 if (c == 'c')
2411 ftrace_dump(DUMP_ORIG);
2412 else
2413 ftrace_dump(DUMP_ALL);
Breno Leitao4125d012017-08-02 17:14:05 -03002414}
2415
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002416#ifdef CONFIG_PPC64
2417static void dump_one_paca(int cpu)
2418{
2419 struct paca_struct *p;
Michael Ellerman4e003742017-10-19 15:08:43 +11002420#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellermanad987fc2015-10-14 16:58:36 +11002421 int i = 0;
2422#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002423
2424 if (setjmp(bus_error_jmp) != 0) {
2425 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2426 return;
2427 }
2428
2429 catch_memory_errors = 1;
2430 sync();
2431
Nicholas Piggind2e60072018-02-14 01:08:12 +10002432 p = paca_ptrs[cpu];
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002433
Michael Ellermand8104182017-12-06 23:23:28 +11002434 printf("paca for cpu 0x%x @ %px:\n", cpu, p);
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002435
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002436 printf(" %-*s = %s\n", 25, "possible", cpu_possible(cpu) ? "yes" : "no");
2437 printf(" %-*s = %s\n", 25, "present", cpu_present(cpu) ? "yes" : "no");
2438 printf(" %-*s = %s\n", 25, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002439
Michael Ellerman66716832018-05-21 21:06:19 +10002440#define DUMP(paca, name, format) \
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002441 printf(" %-*s = "format"\t(0x%lx)\n", 25, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002442 offsetof(struct paca_struct, name));
2443
Michael Ellerman66716832018-05-21 21:06:19 +10002444 DUMP(p, lock_token, "%#-*x");
2445 DUMP(p, paca_index, "%#-*x");
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002446 DUMP(p, kernel_toc, "%#-*llx");
2447 DUMP(p, kernelbase, "%#-*llx");
2448 DUMP(p, kernel_msr, "%#-*llx");
Michael Ellerman66716832018-05-21 21:06:19 +10002449 DUMP(p, emergency_sp, "%-*px");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302450#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman66716832018-05-21 21:06:19 +10002451 DUMP(p, nmi_emergency_sp, "%-*px");
2452 DUMP(p, mc_emergency_sp, "%-*px");
2453 DUMP(p, in_nmi, "%#-*x");
2454 DUMP(p, in_mce, "%#-*x");
2455 DUMP(p, hmi_event_available, "%#-*x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302456#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002457 DUMP(p, data_offset, "%#-*llx");
Michael Ellerman66716832018-05-21 21:06:19 +10002458 DUMP(p, hw_cpu_id, "%#-*x");
2459 DUMP(p, cpu_start, "%#-*x");
2460 DUMP(p, kexec_state, "%#-*x");
Michael Ellerman4e003742017-10-19 15:08:43 +11002461#ifdef CONFIG_PPC_BOOK3S_64
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002462 if (!early_radix_enabled()) {
2463 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2464 u64 esid, vsid;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002465
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002466 if (!p->slb_shadow_ptr)
2467 continue;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002468
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002469 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2470 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
Michael Ellermanad987fc2015-10-14 16:58:36 +11002471
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002472 if (esid || vsid) {
2473 printf(" %-*s[%d] = 0x%016llx 0x%016llx\n",
2474 22, "slb_shadow", i, esid, vsid);
2475 }
Michael Ellermanad987fc2015-10-14 16:58:36 +11002476 }
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002477 DUMP(p, vmalloc_sllp, "%#-*x");
Nicholas Piggin126b11b2018-09-15 01:30:53 +10002478 DUMP(p, stab_rr, "%#-*x");
2479 DUMP(p, slb_used_bitmap, "%#-*x");
2480 DUMP(p, slb_kern_bitmap, "%#-*x");
Nicholas Piggin82d8f4c2018-09-15 01:30:50 +10002481
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002482 if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) {
2483 DUMP(p, slb_cache_ptr, "%#-*x");
2484 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2485 printf(" %-*s[%d] = 0x%016x\n",
2486 22, "slb_cache", i, p->slb_cache[i]);
2487 }
Nicholas Piggin82d8f4c2018-09-15 01:30:50 +10002488 }
Michael Ellerman274920a2018-01-10 23:49:12 +11002489
Michael Ellerman66716832018-05-21 21:06:19 +10002490 DUMP(p, rfi_flush_fallback_area, "%-*px");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002491#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002492 DUMP(p, dscr_default, "%#-*llx");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002493#ifdef CONFIG_PPC_BOOK3E
Michael Ellerman66716832018-05-21 21:06:19 +10002494 DUMP(p, pgd, "%-*px");
2495 DUMP(p, kernel_pgd, "%-*px");
2496 DUMP(p, tcd_ptr, "%-*px");
2497 DUMP(p, mc_kstack, "%-*px");
2498 DUMP(p, crit_kstack, "%-*px");
2499 DUMP(p, dbg_kstack, "%-*px");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002500#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002501 DUMP(p, __current, "%-*px");
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002502 DUMP(p, kstack, "%#-*llx");
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002503 printf(" %-*s = 0x%016llx\n", 25, "kstack_base", p->kstack & ~(THREAD_SIZE - 1));
Michael Ellerman50530f52018-10-12 13:58:52 +11002504#ifdef CONFIG_STACKPROTECTOR
2505 DUMP(p, canary, "%#-*lx");
2506#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002507 DUMP(p, saved_r1, "%#-*llx");
Nicholas Piggin0a882e22019-06-28 16:33:18 +10002508#ifdef CONFIG_PPC_BOOK3E
Michael Ellerman66716832018-05-21 21:06:19 +10002509 DUMP(p, trap_save, "%#-*x");
Nicholas Piggin0a882e22019-06-28 16:33:18 +10002510#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002511 DUMP(p, irq_soft_mask, "%#-*x");
2512 DUMP(p, irq_happened, "%#-*x");
Will Deacon420af152019-02-22 14:45:42 +00002513#ifdef CONFIG_MMIOWB
2514 DUMP(p, mmiowb_state.nesting_count, "%#-*x");
2515 DUMP(p, mmiowb_state.mmiowb_pending, "%#-*x");
2516#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002517 DUMP(p, irq_work_pending, "%#-*x");
Michael Ellerman66716832018-05-21 21:06:19 +10002518 DUMP(p, sprg_vdso, "%#-*llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002519
Michael Ellermanad987fc2015-10-14 16:58:36 +11002520#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
Michael Ellerman66716832018-05-21 21:06:19 +10002521 DUMP(p, tm_scratch, "%#-*llx");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002522#endif
2523
2524#ifdef CONFIG_PPC_POWERNV
Nicholas Piggin10d91612019-04-13 00:30:52 +10002525 DUMP(p, idle_state, "%#-*lx");
2526 if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) {
2527 DUMP(p, thread_idle_state, "%#-*x");
2528 DUMP(p, subcore_sibling_mask, "%#-*x");
2529 } else {
2530#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
2531 DUMP(p, requested_psscr, "%#-*llx");
2532 DUMP(p, dont_stop.counter, "%#-*x");
2533#endif
2534 }
Michael Ellermanad987fc2015-10-14 16:58:36 +11002535#endif
2536
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002537 DUMP(p, accounting.utime, "%#-*lx");
2538 DUMP(p, accounting.stime, "%#-*lx");
Christophe Leroyabcff862018-08-02 07:53:59 +00002539#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002540 DUMP(p, accounting.utime_scaled, "%#-*lx");
Christophe Leroyabcff862018-08-02 07:53:59 +00002541#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002542 DUMP(p, accounting.starttime, "%#-*lx");
2543 DUMP(p, accounting.starttime_user, "%#-*lx");
Christophe Leroyabcff862018-08-02 07:53:59 +00002544#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002545 DUMP(p, accounting.startspurr, "%#-*lx");
2546 DUMP(p, accounting.utime_sspurr, "%#-*lx");
Christophe Leroyabcff862018-08-02 07:53:59 +00002547#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002548 DUMP(p, accounting.steal_time, "%#-*lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002549#undef DUMP
2550
2551 catch_memory_errors = 0;
2552 sync();
2553}
2554
2555static void dump_all_pacas(void)
2556{
2557 int cpu;
2558
2559 if (num_possible_cpus() == 0) {
2560 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2561 return;
2562 }
2563
2564 for_each_possible_cpu(cpu)
2565 dump_one_paca(cpu);
2566}
2567
2568static void dump_pacas(void)
2569{
2570 unsigned long num;
2571 int c;
2572
2573 c = inchar();
2574 if (c == 'a') {
2575 dump_all_pacas();
2576 return;
2577 }
2578
2579 termch = c; /* Put c back, it wasn't 'a' */
2580
2581 if (scanhex(&num))
2582 dump_one_paca(num);
2583 else
2584 dump_one_paca(xmon_owner);
2585}
2586#endif
2587
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002588#ifdef CONFIG_PPC_POWERNV
2589static void dump_one_xive(int cpu)
2590{
2591 unsigned int hwid = get_hard_smp_processor_id(cpu);
Cédric Le Goaterc3e0dbd2019-08-14 17:47:52 +02002592 bool hv = cpu_has_feature(CPU_FTR_HVMODE);
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002593
Cédric Le Goaterc3e0dbd2019-08-14 17:47:52 +02002594 if (hv) {
2595 opal_xive_dump(XIVE_DUMP_TM_HYP, hwid);
2596 opal_xive_dump(XIVE_DUMP_TM_POOL, hwid);
2597 opal_xive_dump(XIVE_DUMP_TM_OS, hwid);
2598 opal_xive_dump(XIVE_DUMP_TM_USER, hwid);
2599 opal_xive_dump(XIVE_DUMP_VP, hwid);
2600 opal_xive_dump(XIVE_DUMP_EMU_STATE, hwid);
2601 }
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002602
2603 if (setjmp(bus_error_jmp) != 0) {
2604 catch_memory_errors = 0;
2605 printf("*** Error dumping xive on cpu %d\n", cpu);
2606 return;
2607 }
2608
2609 catch_memory_errors = 1;
2610 sync();
2611 xmon_xive_do_dump(cpu);
2612 sync();
2613 __delay(200);
2614 catch_memory_errors = 0;
2615}
2616
2617static void dump_all_xives(void)
2618{
2619 int cpu;
2620
2621 if (num_possible_cpus() == 0) {
2622 printf("No possible cpus, use 'dx #' to dump individual cpus\n");
2623 return;
2624 }
2625
2626 for_each_possible_cpu(cpu)
2627 dump_one_xive(cpu);
2628}
2629
Cédric Le Goater58961632019-09-10 10:18:49 +02002630static void dump_one_xive_irq(u32 num, struct irq_data *d)
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002631{
Cédric Le Goater58961632019-09-10 10:18:49 +02002632 xmon_xive_get_irq_config(num, d);
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002633}
2634
Cédric Le Goater39f14e72019-08-14 17:47:54 +02002635static void dump_all_xive_irq(void)
2636{
2637 unsigned int i;
2638 struct irq_desc *desc;
2639
2640 for_each_irq_desc(i, desc) {
2641 struct irq_data *d = irq_desc_get_irq_data(desc);
2642 unsigned int hwirq;
2643
2644 if (!d)
2645 continue;
2646
2647 hwirq = (unsigned int)irqd_to_hwirq(d);
2648 /* IPIs are special (HW number 0) */
2649 if (hwirq)
Cédric Le Goater58961632019-09-10 10:18:49 +02002650 dump_one_xive_irq(hwirq, d);
Cédric Le Goater39f14e72019-08-14 17:47:54 +02002651 }
2652}
2653
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002654static void dump_xives(void)
2655{
2656 unsigned long num;
2657 int c;
2658
Breno Leitao402e1722017-10-17 16:20:18 -02002659 if (!xive_enabled()) {
2660 printf("Xive disabled on this system\n");
2661 return;
2662 }
2663
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002664 c = inchar();
2665 if (c == 'a') {
2666 dump_all_xives();
2667 return;
2668 } else if (c == 'i') {
2669 if (scanhex(&num))
Cédric Le Goater58961632019-09-10 10:18:49 +02002670 dump_one_xive_irq(num, NULL);
Cédric Le Goater39f14e72019-08-14 17:47:54 +02002671 else
2672 dump_all_xive_irq();
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002673 return;
2674 }
2675
2676 termch = c; /* Put c back, it wasn't 'a' */
2677
2678 if (scanhex(&num))
2679 dump_one_xive(num);
2680 else
2681 dump_one_xive(xmon_owner);
2682}
2683#endif /* CONFIG_PPC_POWERNV */
2684
Douglas Miller5e48dc02017-02-07 07:40:44 -06002685static void dump_by_size(unsigned long addr, long count, int size)
2686{
2687 unsigned char temp[16];
2688 int i, j;
2689 u64 val;
2690
2691 count = ALIGN(count, 16);
2692
2693 for (i = 0; i < count; i += 16, addr += 16) {
2694 printf(REG, addr);
2695
2696 if (mread(addr, temp, 16) != 16) {
2697 printf("\nFaulted reading %d bytes from 0x"REG"\n", 16, addr);
2698 return;
2699 }
2700
2701 for (j = 0; j < 16; j += size) {
2702 putchar(' ');
2703 switch (size) {
2704 case 1: val = temp[j]; break;
2705 case 2: val = *(u16 *)&temp[j]; break;
2706 case 4: val = *(u32 *)&temp[j]; break;
2707 case 8: val = *(u64 *)&temp[j]; break;
2708 default: val = 0;
2709 }
2710
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002711 printf("%0*llx", size * 2, val);
Douglas Miller5e48dc02017-02-07 07:40:44 -06002712 }
2713 printf("\n");
2714 }
2715}
2716
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002717static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718dump(void)
2719{
Douglas Miller5e48dc02017-02-07 07:40:44 -06002720 static char last[] = { "d?\n" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 int c;
2722
2723 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002724
2725#ifdef CONFIG_PPC64
2726 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002727 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002728 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002729 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002730 return;
2731 }
2732#endif
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002733#ifdef CONFIG_PPC_POWERNV
2734 if (c == 'x') {
2735 xmon_start_pagination();
2736 dump_xives();
2737 xmon_end_pagination();
2738 return;
2739 }
2740#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002741
Breno Leitao4125d012017-08-02 17:14:05 -03002742 if (c == 't') {
2743 dump_tracing();
2744 return;
2745 }
2746
Douglas Miller5e48dc02017-02-07 07:40:44 -06002747 if (c == '\n')
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 termch = c;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002749
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 scanhex((void *)&adrs);
2751 if (termch != '\n')
2752 termch = 0;
2753 if (c == 'i') {
2754 scanhex(&nidump);
2755 if (nidump == 0)
2756 nidump = 16;
2757 else if (nidump > MAX_DUMP)
2758 nidump = MAX_DUMP;
2759 adrs += ppc_inst_dump(adrs, nidump, 1);
2760 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002761 } else if (c == 'l') {
2762 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002763 } else if (c == 'o') {
2764 dump_opal_msglog();
Balbir Singh80eff6c2017-10-30 22:01:12 +11002765 } else if (c == 'v') {
2766 /* dump virtual to physical translation */
2767 show_pte(adrs);
Olaf Hering7e5b5932006-03-08 20:40:28 +01002768 } else if (c == 'r') {
2769 scanhex(&ndump);
2770 if (ndump == 0)
2771 ndump = 64;
2772 xmon_rawdump(adrs, ndump);
2773 adrs += ndump;
2774 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 } else {
2776 scanhex(&ndump);
2777 if (ndump == 0)
2778 ndump = 64;
2779 else if (ndump > MAX_DUMP)
2780 ndump = MAX_DUMP;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002781
2782 switch (c) {
2783 case '8':
2784 case '4':
2785 case '2':
2786 case '1':
2787 ndump = ALIGN(ndump, 16);
2788 dump_by_size(adrs, ndump, c - '0');
2789 last[1] = c;
2790 last_cmd = last;
2791 break;
2792 default:
2793 prdump(adrs, ndump);
2794 last_cmd = "d\n";
2795 }
2796
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 adrs += ndump;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 }
2799}
2800
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002801static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802prdump(unsigned long adrs, long ndump)
2803{
2804 long n, m, c, r, nr;
2805 unsigned char temp[16];
2806
2807 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002808 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 putchar(' ');
2810 r = n < 16? n: 16;
2811 nr = mread(adrs, temp, r);
2812 adrs += nr;
2813 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002814 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002815 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 if (m < nr)
2817 printf("%.2x", temp[m]);
2818 else
2819 printf("%s", fault_chars[fault_type]);
2820 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002821 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002822 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002823 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002825 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 printf(" |");
2827 for (m = 0; m < r; ++m) {
2828 if (m < nr) {
2829 c = temp[m];
2830 putchar(' ' <= c && c <= '~'? c: '.');
2831 } else
2832 putchar(' ');
2833 }
2834 n -= r;
2835 for (; m < 16; ++m)
2836 putchar(' ');
2837 printf("|\n");
2838 if (nr < r)
2839 break;
2840 }
2841}
2842
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002843typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2844
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002845static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002846generic_inst_dump(unsigned long adr, long count, int praddr,
2847 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848{
2849 int nr, dotted;
2850 unsigned long first_adr;
Michael Ellerman941d8102018-07-16 23:52:14 +10002851 unsigned int inst, last_inst = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 unsigned char val[4];
2853
2854 dotted = 0;
2855 for (first_adr = adr; count > 0; --count, adr += 4) {
2856 nr = mread(adr, val, 4);
2857 if (nr == 0) {
2858 if (praddr) {
2859 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002860 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 }
2862 break;
2863 }
2864 inst = GETWORD(val);
2865 if (adr > first_adr && inst == last_inst) {
2866 if (!dotted) {
2867 printf(" ...\n");
2868 dotted = 1;
2869 }
2870 continue;
2871 }
2872 dotted = 0;
2873 last_inst = inst;
2874 if (praddr)
Michael Ellerman941d8102018-07-16 23:52:14 +10002875 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002877 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 printf("\n");
2879 }
2880 return adr - first_adr;
2881}
2882
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002883static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002884ppc_inst_dump(unsigned long adr, long count, int praddr)
2885{
2886 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2887}
2888
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889void
2890print_address(unsigned long addr)
2891{
2892 xmon_print_symbol(addr, "\t# ", "");
2893}
2894
Breno Leitaoe3a83792018-10-22 11:54:16 -03002895static void
Vinay Sridharf312deb2009-05-14 23:13:07 +00002896dump_log_buf(void)
2897{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002898 struct kmsg_dumper dumper = { .active = 1 };
2899 unsigned char buf[128];
2900 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002901
Michael Ellermane3bc8042012-08-23 22:09:13 +00002902 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002903 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002904 return;
2905 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002906
Michael Ellermane3bc8042012-08-23 22:09:13 +00002907 catch_memory_errors = 1;
2908 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002909
Michael Ellermanca5dd392012-08-23 22:09:12 +00002910 kmsg_dump_rewind_nolock(&dumper);
Sam bobroff0c23a882015-10-08 11:50:24 +11002911 xmon_start_pagination();
Michael Ellermanca5dd392012-08-23 22:09:12 +00002912 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2913 buf[len] = '\0';
2914 printf("%s", buf);
2915 }
Sam bobroff0c23a882015-10-08 11:50:24 +11002916 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002917
Michael Ellermane3bc8042012-08-23 22:09:13 +00002918 sync();
2919 /* wait a little while to see if we get a machine check */
2920 __delay(200);
2921 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002922}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002924#ifdef CONFIG_PPC_POWERNV
2925static void dump_opal_msglog(void)
2926{
2927 unsigned char buf[128];
2928 ssize_t res;
2929 loff_t pos = 0;
2930
2931 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
2932 printf("Machine is not running OPAL firmware.\n");
2933 return;
2934 }
2935
2936 if (setjmp(bus_error_jmp) != 0) {
2937 printf("Error dumping OPAL msglog!\n");
2938 return;
2939 }
2940
2941 catch_memory_errors = 1;
2942 sync();
2943
2944 xmon_start_pagination();
2945 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
2946 if (res < 0) {
2947 printf("Error dumping OPAL msglog! Error: %zd\n", res);
2948 break;
2949 }
2950 buf[res] = '\0';
2951 printf("%s", buf);
2952 pos += res;
2953 }
2954 xmon_end_pagination();
2955
2956 sync();
2957 /* wait a little while to see if we get a machine check */
2958 __delay(200);
2959 catch_memory_errors = 0;
2960}
2961#endif
2962
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963/*
2964 * Memory operations - move, set, print differences
2965 */
2966static unsigned long mdest; /* destination address */
2967static unsigned long msrc; /* source address */
2968static unsigned long mval; /* byte value to set memory to */
2969static unsigned long mcount; /* # bytes to affect */
2970static unsigned long mdiffs; /* max # differences to print */
2971
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002972static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973memops(int cmd)
2974{
2975 scanhex((void *)&mdest);
2976 if( termch != '\n' )
2977 termch = 0;
2978 scanhex((void *)(cmd == 's'? &mval: &msrc));
2979 if( termch != '\n' )
2980 termch = 0;
2981 scanhex((void *)&mcount);
2982 switch( cmd ){
2983 case 'm':
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05002984 if (xmon_is_ro) {
2985 printf(xmon_ro_msg);
2986 break;
2987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 memmove((void *)mdest, (void *)msrc, mcount);
2989 break;
2990 case 's':
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05002991 if (xmon_is_ro) {
2992 printf(xmon_ro_msg);
2993 break;
2994 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 memset((void *)mdest, mval, mcount);
2996 break;
2997 case 'd':
2998 if( termch != '\n' )
2999 termch = 0;
3000 scanhex((void *)&mdiffs);
3001 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
3002 break;
3003 }
3004}
3005
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003006static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
3008{
3009 unsigned n, prt;
3010
3011 prt = 0;
3012 for( n = nb; n > 0; --n )
3013 if( *p1++ != *p2++ )
3014 if( ++prt <= maxpr )
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003015 printf("%px %.2x # %px %.2x\n", p1 - 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 p1[-1], p2 - 1, p2[-1]);
3017 if( prt > maxpr )
3018 printf("Total of %d differences\n", prt);
3019}
3020
3021static unsigned mend;
3022static unsigned mask;
3023
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003024static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025memlocate(void)
3026{
3027 unsigned a, n;
3028 unsigned char val[4];
3029
3030 last_cmd = "ml";
3031 scanhex((void *)&mdest);
3032 if (termch != '\n') {
3033 termch = 0;
3034 scanhex((void *)&mend);
3035 if (termch != '\n') {
3036 termch = 0;
3037 scanhex((void *)&mval);
3038 mask = ~0;
3039 if (termch != '\n') termch = 0;
3040 scanhex((void *)&mask);
3041 }
3042 }
3043 n = 0;
3044 for (a = mdest; a < mend; a += 4) {
3045 if (mread(a, val, 4) == 4
3046 && ((GETWORD(val) ^ mval) & mask) == 0) {
3047 printf("%.16x: %.16x\n", a, GETWORD(val));
3048 if (++n >= 10)
3049 break;
3050 }
3051 }
3052}
3053
3054static unsigned long mskip = 0x1000;
3055static unsigned long mlim = 0xffffffff;
3056
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003057static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058memzcan(void)
3059{
3060 unsigned char v;
3061 unsigned a;
3062 int ok, ook;
3063
3064 scanhex(&mdest);
3065 if (termch != '\n') termch = 0;
3066 scanhex(&mskip);
3067 if (termch != '\n') termch = 0;
3068 scanhex(&mlim);
3069 ook = 0;
3070 for (a = mdest; a < mlim; a += mskip) {
3071 ok = mread(a, &v, 1);
3072 if (ok && !ook) {
3073 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 } else if (!ok && ook)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003075 printf("%.8lx\n", a - mskip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 ook = ok;
3077 if (a + mskip < a)
3078 break;
3079 }
3080 if (ook)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003081 printf("%.8lx\n", a - mskip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082}
3083
Douglas Miller6dfb5402015-11-23 09:01:15 -06003084static void show_task(struct task_struct *tsk)
3085{
3086 char state;
3087
3088 /*
3089 * Cloned from kdb_task_state_char(), which is not entirely
3090 * appropriate for calling from xmon. This could be moved
3091 * to a common, generic, routine used by both.
3092 */
3093 state = (tsk->state == 0) ? 'R' :
3094 (tsk->state < 0) ? 'U' :
3095 (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
3096 (tsk->state & TASK_STOPPED) ? 'T' :
3097 (tsk->state & TASK_TRACED) ? 'C' :
3098 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
3099 (tsk->exit_state & EXIT_DEAD) ? 'E' :
3100 (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
3101
Michael Ellermand8104182017-12-06 23:23:28 +11003102 printf("%px %016lx %6d %6d %c %2d %s\n", tsk,
Douglas Miller6dfb5402015-11-23 09:01:15 -06003103 tsk->thread.ksp,
Breno Leitaoe3a83792018-10-22 11:54:16 -03003104 tsk->pid, rcu_dereference(tsk->parent)->pid,
Christophe Leroy05486082019-01-31 10:08:50 +00003105 state, task_cpu(tsk),
Douglas Miller6dfb5402015-11-23 09:01:15 -06003106 tsk->comm);
3107}
3108
Balbir Singh80eff6c2017-10-30 22:01:12 +11003109#ifdef CONFIG_PPC_BOOK3S_64
Breno Leitaoe3a83792018-10-22 11:54:16 -03003110static void format_pte(void *ptep, unsigned long pte)
Balbir Singh80eff6c2017-10-30 22:01:12 +11003111{
Christophe Leroy26973fa2018-10-09 13:51:56 +00003112 pte_t entry = __pte(pte);
3113
Balbir Singh80eff6c2017-10-30 22:01:12 +11003114 printf("ptep @ 0x%016lx = 0x%016lx\n", (unsigned long)ptep, pte);
3115 printf("Maps physical address = 0x%016lx\n", pte & PTE_RPN_MASK);
3116
3117 printf("Flags = %s%s%s%s%s\n",
Christophe Leroy26973fa2018-10-09 13:51:56 +00003118 pte_young(entry) ? "Accessed " : "",
3119 pte_dirty(entry) ? "Dirty " : "",
3120 pte_read(entry) ? "Read " : "",
3121 pte_write(entry) ? "Write " : "",
3122 pte_exec(entry) ? "Exec " : "");
Balbir Singh80eff6c2017-10-30 22:01:12 +11003123}
3124
3125static void show_pte(unsigned long addr)
3126{
3127 unsigned long tskv = 0;
3128 struct task_struct *tsk = NULL;
3129 struct mm_struct *mm;
3130 pgd_t *pgdp, *pgdir;
3131 pud_t *pudp;
3132 pmd_t *pmdp;
3133 pte_t *ptep;
3134
3135 if (!scanhex(&tskv))
3136 mm = &init_mm;
3137 else
3138 tsk = (struct task_struct *)tskv;
3139
3140 if (tsk == NULL)
3141 mm = &init_mm;
3142 else
3143 mm = tsk->active_mm;
3144
3145 if (setjmp(bus_error_jmp) != 0) {
3146 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11003147 printf("*** Error dumping pte for task %px\n", tsk);
Balbir Singh80eff6c2017-10-30 22:01:12 +11003148 return;
3149 }
3150
3151 catch_memory_errors = 1;
3152 sync();
3153
3154 if (mm == &init_mm) {
3155 pgdp = pgd_offset_k(addr);
3156 pgdir = pgd_offset_k(0);
3157 } else {
3158 pgdp = pgd_offset(mm, addr);
3159 pgdir = pgd_offset(mm, 0);
3160 }
3161
3162 if (pgd_none(*pgdp)) {
3163 printf("no linux page table for address\n");
3164 return;
3165 }
3166
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003167 printf("pgd @ 0x%px\n", pgdir);
Balbir Singh80eff6c2017-10-30 22:01:12 +11003168
Aneesh Kumar K.Vd6eaced2019-05-14 11:33:00 +05303169 if (pgd_is_leaf(*pgdp)) {
Balbir Singh80eff6c2017-10-30 22:01:12 +11003170 format_pte(pgdp, pgd_val(*pgdp));
3171 return;
3172 }
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003173 printf("pgdp @ 0x%px = 0x%016lx\n", pgdp, pgd_val(*pgdp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003174
3175 pudp = pud_offset(pgdp, addr);
3176
3177 if (pud_none(*pudp)) {
3178 printf("No valid PUD\n");
3179 return;
3180 }
3181
Aneesh Kumar K.Vd6eaced2019-05-14 11:33:00 +05303182 if (pud_is_leaf(*pudp)) {
Balbir Singh80eff6c2017-10-30 22:01:12 +11003183 format_pte(pudp, pud_val(*pudp));
3184 return;
3185 }
3186
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003187 printf("pudp @ 0x%px = 0x%016lx\n", pudp, pud_val(*pudp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003188
3189 pmdp = pmd_offset(pudp, addr);
3190
3191 if (pmd_none(*pmdp)) {
3192 printf("No valid PMD\n");
3193 return;
3194 }
3195
Aneesh Kumar K.Vd6eaced2019-05-14 11:33:00 +05303196 if (pmd_is_leaf(*pmdp)) {
Balbir Singh80eff6c2017-10-30 22:01:12 +11003197 format_pte(pmdp, pmd_val(*pmdp));
3198 return;
3199 }
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003200 printf("pmdp @ 0x%px = 0x%016lx\n", pmdp, pmd_val(*pmdp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003201
3202 ptep = pte_offset_map(pmdp, addr);
3203 if (pte_none(*ptep)) {
3204 printf("no valid PTE\n");
3205 return;
3206 }
3207
3208 format_pte(ptep, pte_val(*ptep));
3209
3210 sync();
3211 __delay(200);
3212 catch_memory_errors = 0;
3213}
3214#else
3215static void show_pte(unsigned long addr)
3216{
3217 printf("show_pte not yet implemented\n");
3218}
3219#endif /* CONFIG_PPC_BOOK3S_64 */
3220
Douglas Miller6dfb5402015-11-23 09:01:15 -06003221static void show_tasks(void)
3222{
3223 unsigned long tskv;
3224 struct task_struct *tsk = NULL;
3225
3226 printf(" task_struct ->thread.ksp PID PPID S P CMD\n");
3227
3228 if (scanhex(&tskv))
3229 tsk = (struct task_struct *)tskv;
3230
3231 if (setjmp(bus_error_jmp) != 0) {
3232 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11003233 printf("*** Error dumping task %px\n", tsk);
Douglas Miller6dfb5402015-11-23 09:01:15 -06003234 return;
3235 }
3236
3237 catch_memory_errors = 1;
3238 sync();
3239
3240 if (tsk)
3241 show_task(tsk);
3242 else
3243 for_each_process(tsk)
3244 show_task(tsk);
3245
3246 sync();
3247 __delay(200);
3248 catch_memory_errors = 0;
3249}
3250
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003251static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003252{
3253 unsigned long args[8];
3254 unsigned long ret;
3255 int i;
3256 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
3257 unsigned long, unsigned long, unsigned long,
3258 unsigned long, unsigned long, unsigned long);
3259 callfunc_t func;
3260
3261 if (!scanhex(&adrs))
3262 return;
3263 if (termch != '\n')
3264 termch = 0;
3265 for (i = 0; i < 8; ++i)
3266 args[i] = 0;
3267 for (i = 0; i < 8; ++i) {
3268 if (!scanhex(&args[i]) || termch == '\n')
3269 break;
3270 termch = 0;
3271 }
3272 func = (callfunc_t) adrs;
3273 ret = 0;
3274 if (setjmp(bus_error_jmp) == 0) {
3275 catch_memory_errors = 1;
3276 sync();
3277 ret = func(args[0], args[1], args[2], args[3],
3278 args[4], args[5], args[6], args[7]);
3279 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10003280 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003281 } else {
3282 printf("*** %x exception occurred\n", fault_except);
3283 }
3284 catch_memory_errors = 0;
3285}
3286
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287/* Input scanning routines */
3288int
3289skipbl(void)
3290{
3291 int c;
3292
3293 if( termch != 0 ){
3294 c = termch;
3295 termch = 0;
3296 } else
3297 c = inchar();
3298 while( c == ' ' || c == '\t' )
3299 c = inchar();
3300 return c;
3301}
3302
3303#define N_PTREGS 44
Yisheng Xie0abbf2b2018-05-31 19:11:25 +08003304static const char *regnames[N_PTREGS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
3306 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
3307 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
3308 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003309 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
3310#ifdef CONFIG_PPC64
3311 "softe",
3312#else
3313 "mq",
3314#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 "trap", "dar", "dsisr", "res"
3316};
3317
3318int
3319scanhex(unsigned long *vp)
3320{
3321 int c, d;
3322 unsigned long v;
3323
3324 c = skipbl();
3325 if (c == '%') {
3326 /* parse register name */
3327 char regname[8];
3328 int i;
3329
3330 for (i = 0; i < sizeof(regname) - 1; ++i) {
3331 c = inchar();
3332 if (!isalnum(c)) {
3333 termch = c;
3334 break;
3335 }
3336 regname[i] = c;
3337 }
3338 regname[i] = 0;
Yisheng Xie0abbf2b2018-05-31 19:11:25 +08003339 i = match_string(regnames, N_PTREGS, regname);
3340 if (i < 0) {
3341 printf("invalid register name '%%%s'\n", regname);
3342 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 }
Yisheng Xie0abbf2b2018-05-31 19:11:25 +08003344 if (xmon_regs == NULL) {
3345 printf("regs not available\n");
3346 return 0;
3347 }
3348 *vp = ((unsigned long *)xmon_regs)[i];
3349 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 }
3351
3352 /* skip leading "0x" if any */
3353
3354 if (c == '0') {
3355 c = inchar();
3356 if (c == 'x') {
3357 c = inchar();
3358 } else {
3359 d = hexdigit(c);
3360 if (d == EOF) {
3361 termch = c;
3362 *vp = 0;
3363 return 1;
3364 }
3365 }
3366 } else if (c == '$') {
3367 int i;
3368 for (i=0; i<63; i++) {
3369 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02003370 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 termch = c;
3372 break;
3373 }
3374 tmpstr[i] = c;
3375 }
3376 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07003377 *vp = 0;
3378 if (setjmp(bus_error_jmp) == 0) {
3379 catch_memory_errors = 1;
3380 sync();
3381 *vp = kallsyms_lookup_name(tmpstr);
3382 sync();
3383 }
3384 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 if (!(*vp)) {
3386 printf("unknown symbol '%s'\n", tmpstr);
3387 return 0;
3388 }
3389 return 1;
3390 }
3391
3392 d = hexdigit(c);
3393 if (d == EOF) {
3394 termch = c;
3395 return 0;
3396 }
3397 v = 0;
3398 do {
3399 v = (v << 4) + d;
3400 c = inchar();
3401 d = hexdigit(c);
3402 } while (d != EOF);
3403 termch = c;
3404 *vp = v;
3405 return 1;
3406}
3407
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003408static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409scannl(void)
3410{
3411 int c;
3412
3413 c = termch;
3414 termch = 0;
3415 while( c != '\n' )
3416 c = inchar();
3417}
3418
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003419static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420{
3421 if( '0' <= c && c <= '9' )
3422 return c - '0';
3423 if( 'A' <= c && c <= 'F' )
3424 return c - ('A' - 10);
3425 if( 'a' <= c && c <= 'f' )
3426 return c - ('a' - 10);
3427 return EOF;
3428}
3429
3430void
3431getstring(char *s, int size)
3432{
3433 int c;
3434
3435 c = skipbl();
3436 do {
3437 if( size > 1 ){
3438 *s++ = c;
3439 --size;
3440 }
3441 c = inchar();
3442 } while( c != ' ' && c != '\t' && c != '\n' );
3443 termch = c;
3444 *s = 0;
3445}
3446
3447static char line[256];
3448static char *lineptr;
3449
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003450static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451flush_input(void)
3452{
3453 lineptr = NULL;
3454}
3455
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003456static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457inchar(void)
3458{
3459 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003460 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 lineptr = NULL;
3462 return EOF;
3463 }
3464 lineptr = line;
3465 }
3466 return *lineptr++;
3467}
3468
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003469static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470take_input(char *str)
3471{
3472 lineptr = str;
3473}
3474
3475
3476static void
3477symbol_lookup(void)
3478{
3479 int type = inchar();
Boqun Feng302c7b02016-11-22 17:20:09 +08003480 unsigned long addr, cpu;
3481 void __percpu *ptr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 static char tmp[64];
3483
3484 switch (type) {
3485 case 'a':
3486 if (scanhex(&addr))
3487 xmon_print_symbol(addr, ": ", "\n");
3488 termch = 0;
3489 break;
3490 case 's':
3491 getstring(tmp, 64);
3492 if (setjmp(bus_error_jmp) == 0) {
3493 catch_memory_errors = 1;
3494 sync();
3495 addr = kallsyms_lookup_name(tmp);
3496 if (addr)
3497 printf("%s: %lx\n", tmp, addr);
3498 else
3499 printf("Symbol '%s' not found.\n", tmp);
3500 sync();
3501 }
3502 catch_memory_errors = 0;
3503 termch = 0;
3504 break;
Boqun Feng302c7b02016-11-22 17:20:09 +08003505 case 'p':
3506 getstring(tmp, 64);
3507 if (setjmp(bus_error_jmp) == 0) {
3508 catch_memory_errors = 1;
3509 sync();
3510 ptr = (void __percpu *)kallsyms_lookup_name(tmp);
3511 sync();
3512 }
3513
3514 if (ptr &&
3515 ptr >= (void __percpu *)__per_cpu_start &&
3516 ptr < (void __percpu *)__per_cpu_end)
3517 {
3518 if (scanhex(&cpu) && cpu < num_possible_cpus()) {
3519 addr = (unsigned long)per_cpu_ptr(ptr, cpu);
3520 } else {
3521 cpu = raw_smp_processor_id();
3522 addr = (unsigned long)this_cpu_ptr(ptr);
3523 }
3524
3525 printf("%s for cpu 0x%lx: %lx\n", tmp, cpu, addr);
3526 } else {
3527 printf("Percpu symbol '%s' not found.\n", tmp);
3528 }
3529
3530 catch_memory_errors = 0;
3531 termch = 0;
3532 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 }
3534}
3535
3536
3537/* Print an address in numeric and symbolic form (if possible) */
3538static void xmon_print_symbol(unsigned long address, const char *mid,
3539 const char *after)
3540{
3541 char *modname;
3542 const char *name = NULL;
3543 unsigned long offset, size;
3544
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003545 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 if (setjmp(bus_error_jmp) == 0) {
3547 catch_memory_errors = 1;
3548 sync();
3549 name = kallsyms_lookup(address, &size, &offset, &modname,
3550 tmpstr);
3551 sync();
3552 /* wait a little while to see if we get a machine check */
3553 __delay(200);
3554 }
3555
3556 catch_memory_errors = 0;
3557
3558 if (name) {
3559 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
3560 if (modname)
3561 printf(" [%s]", modname);
3562 }
3563 printf("%s", after);
3564}
3565
Michael Ellerman4e003742017-10-19 15:08:43 +11003566#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10003567void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568{
3569 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05303570 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11003571 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572
Michael Ellerman736256e2014-05-26 21:02:14 +10003573 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574
Michael Neuling584f8b72007-12-06 17:24:48 +11003575 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11003576 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
3577 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Michael Ellerman85673642017-04-24 10:35:14 +10003578
3579 if (!esid && !vsid)
3580 continue;
3581
3582 printf("%02d %016lx %016lx", i, esid, vsid);
3583
3584 if (!(esid & SLB_ESID_V)) {
3585 printf("\n");
3586 continue;
3587 }
3588
3589 llp = vsid & SLB_VSID_LLP;
3590 if (vsid & SLB_VSID_B_1T) {
3591 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
3592 GET_ESID_1T(esid),
3593 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
3594 llp);
3595 } else {
3596 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
3597 GET_ESID(esid),
3598 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
3599 llp);
will schmidtb3b95952007-12-07 08:22:23 +11003600 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 }
3602}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003603#endif
3604
Christophe Leroy68289ae2018-11-17 10:25:02 +00003605#ifdef CONFIG_PPC_BOOK3S_32
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003606void dump_segments(void)
3607{
3608 int i;
3609
3610 printf("sr0-15 =");
3611 for (i = 0; i < 16; ++i)
Christophe Leroy32c8c4c2018-11-16 17:31:08 +00003612 printf(" %x", mfsrin(i << 28));
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003613 printf("\n");
3614}
3615#endif
3616
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003617#ifdef CONFIG_44x
3618static void dump_tlb_44x(void)
3619{
3620 int i;
3621
3622 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
3623 unsigned long w0,w1,w2;
3624 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
3625 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
3626 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003627 printf("[%02x] %08lx %08lx %08lx ", i, w0, w1, w2);
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003628 if (w0 & PPC44x_TLB_VALID) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003629 printf("V %08lx -> %01lx%08lx %c%c%c%c%c",
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003630 w0 & PPC44x_TLB_EPN_MASK,
3631 w1 & PPC44x_TLB_ERPN_MASK,
3632 w1 & PPC44x_TLB_RPN_MASK,
3633 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
3634 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
3635 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
3636 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
3637 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
3638 }
3639 printf("\n");
3640 }
3641}
3642#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003643
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10003644#ifdef CONFIG_PPC_BOOK3E
3645static void dump_tlb_book3e(void)
3646{
3647 u32 mmucfg, pidmask, lpidmask;
3648 u64 ramask;
3649 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3650 int mmu_version;
3651 static const char *pgsz_names[] = {
3652 " 1K",
3653 " 2K",
3654 " 4K",
3655 " 8K",
3656 " 16K",
3657 " 32K",
3658 " 64K",
3659 "128K",
3660 "256K",
3661 "512K",
3662 " 1M",
3663 " 2M",
3664 " 4M",
3665 " 8M",
3666 " 16M",
3667 " 32M",
3668 " 64M",
3669 "128M",
3670 "256M",
3671 "512M",
3672 " 1G",
3673 " 2G",
3674 " 4G",
3675 " 8G",
3676 " 16G",
3677 " 32G",
3678 " 64G",
3679 "128G",
3680 "256G",
3681 "512G",
3682 " 1T",
3683 " 2T",
3684 };
3685
3686 /* Gather some infos about the MMU */
3687 mmucfg = mfspr(SPRN_MMUCFG);
3688 mmu_version = (mmucfg & 3) + 1;
3689 ntlbs = ((mmucfg >> 2) & 3) + 1;
3690 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3691 lpidsz = (mmucfg >> 24) & 0xf;
3692 rasz = (mmucfg >> 16) & 0x7f;
3693 if ((mmu_version > 1) && (mmucfg & 0x10000))
3694 lrat = 1;
3695 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3696 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3697 pidmask = (1ul << pidsz) - 1;
3698 lpidmask = (1ul << lpidsz) - 1;
3699 ramask = (1ull << rasz) - 1;
3700
3701 for (tlb = 0; tlb < ntlbs; tlb++) {
3702 u32 tlbcfg;
3703 int nent, assoc, new_cc = 1;
3704 printf("TLB %d:\n------\n", tlb);
3705 switch(tlb) {
3706 case 0:
3707 tlbcfg = mfspr(SPRN_TLB0CFG);
3708 break;
3709 case 1:
3710 tlbcfg = mfspr(SPRN_TLB1CFG);
3711 break;
3712 case 2:
3713 tlbcfg = mfspr(SPRN_TLB2CFG);
3714 break;
3715 case 3:
3716 tlbcfg = mfspr(SPRN_TLB3CFG);
3717 break;
3718 default:
3719 printf("Unsupported TLB number !\n");
3720 continue;
3721 }
3722 nent = tlbcfg & 0xfff;
3723 assoc = (tlbcfg >> 24) & 0xff;
3724 for (i = 0; i < nent; i++) {
3725 u32 mas0 = MAS0_TLBSEL(tlb);
3726 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3727 u64 mas2 = 0;
3728 u64 mas7_mas3;
3729 int esel = i, cc = i;
3730
3731 if (assoc != 0) {
3732 cc = i / assoc;
3733 esel = i % assoc;
3734 mas2 = cc * 0x1000;
3735 }
3736
3737 mas0 |= MAS0_ESEL(esel);
3738 mtspr(SPRN_MAS0, mas0);
3739 mtspr(SPRN_MAS1, mas1);
3740 mtspr(SPRN_MAS2, mas2);
3741 asm volatile("tlbre 0,0,0" : : : "memory");
3742 mas1 = mfspr(SPRN_MAS1);
3743 mas2 = mfspr(SPRN_MAS2);
3744 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3745 if (assoc && (i % assoc) == 0)
3746 new_cc = 1;
3747 if (!(mas1 & MAS1_VALID))
3748 continue;
3749 if (assoc == 0)
3750 printf("%04x- ", i);
3751 else if (new_cc)
3752 printf("%04x-%c", cc, 'A' + esel);
3753 else
3754 printf(" |%c", 'A' + esel);
3755 new_cc = 0;
3756 printf(" %016llx %04x %s %c%c AS%c",
3757 mas2 & ~0x3ffull,
3758 (mas1 >> 16) & 0x3fff,
3759 pgsz_names[(mas1 >> 7) & 0x1f],
3760 mas1 & MAS1_IND ? 'I' : ' ',
3761 mas1 & MAS1_IPROT ? 'P' : ' ',
3762 mas1 & MAS1_TS ? '1' : '0');
3763 printf(" %c%c%c%c%c%c%c",
3764 mas2 & MAS2_X0 ? 'a' : ' ',
3765 mas2 & MAS2_X1 ? 'v' : ' ',
3766 mas2 & MAS2_W ? 'w' : ' ',
3767 mas2 & MAS2_I ? 'i' : ' ',
3768 mas2 & MAS2_M ? 'm' : ' ',
3769 mas2 & MAS2_G ? 'g' : ' ',
3770 mas2 & MAS2_E ? 'e' : ' ');
3771 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3772 if (mas1 & MAS1_IND)
3773 printf(" %s\n",
3774 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3775 else
3776 printf(" U%c%c%c S%c%c%c\n",
3777 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3778 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3779 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3780 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3781 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3782 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3783 }
3784 }
3785}
3786#endif /* CONFIG_PPC_BOOK3E */
3787
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003788static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003790 if (enable) {
3791 __debugger = xmon;
3792 __debugger_ipi = xmon_ipi;
3793 __debugger_bpt = xmon_bpt;
3794 __debugger_sstep = xmon_sstep;
3795 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003796 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003797 __debugger_fault_handler = xmon_fault_handler;
Breno Leitao8d4a8622018-11-08 15:12:42 -02003798
3799#ifdef CONFIG_PPC_PSERIES
3800 /*
3801 * Get the token here to avoid trying to get a lock
3802 * during the crash, causing a deadlock.
3803 */
3804 set_indicator_token = rtas_token("set-indicator");
3805#endif
Olaf Heringb13cfd172005-08-04 19:26:42 +02003806 } else {
3807 __debugger = NULL;
3808 __debugger_ipi = NULL;
3809 __debugger_bpt = NULL;
3810 __debugger_sstep = NULL;
3811 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003812 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003813 __debugger_fault_handler = NULL;
3814 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003816
3817#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003818static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003819{
Christopher M. Riedl69393cb2019-09-07 01:11:24 -05003820 if (xmon_is_locked_down()) {
3821 clear_all_bpt();
3822 xmon_init(0);
3823 return;
3824 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003825 /* ensure xmon is enabled */
3826 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01003827 debugger(get_irq_regs());
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003828 if (!xmon_on)
3829 xmon_init(0);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003830}
3831
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003832static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003833 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07003834 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003835 .action_msg = "Entering xmon",
3836};
3837
3838static int __init setup_xmon_sysrq(void)
3839{
3840 register_sysrq_key('x', &sysrq_xmon_op);
3841 return 0;
3842}
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003843device_initcall(setup_xmon_sysrq);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003844#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10003845
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05303846static void clear_all_bpt(void)
3847{
3848 int i;
3849
3850 /* clear/unpatch all breakpoints */
3851 remove_bpts();
3852 remove_cpu_bpts();
3853
3854 /* Disable all breakpoints */
3855 for (i = 0; i < NBPTS; ++i)
3856 bpts[i].enabled = 0;
3857
3858 /* Clear any data or iabr breakpoints */
3859 if (iabr || dabr.enabled) {
3860 iabr = NULL;
3861 dabr.enabled = 0;
3862 }
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05303863}
3864
Christopher M. Riedl69393cb2019-09-07 01:11:24 -05003865#ifdef CONFIG_DEBUG_FS
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003866static int xmon_dbgfs_set(void *data, u64 val)
3867{
3868 xmon_on = !!val;
3869 xmon_init(xmon_on);
3870
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05303871 /* make sure all breakpoints removed when disabling */
Christopher M. Riedl69393cb2019-09-07 01:11:24 -05003872 if (!xmon_on) {
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05303873 clear_all_bpt();
Christopher M. Riedl69393cb2019-09-07 01:11:24 -05003874 get_output_lock();
3875 printf("xmon: All breakpoints cleared\n");
3876 release_output_lock();
3877 }
3878
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03003879 return 0;
3880}
3881
3882static int xmon_dbgfs_get(void *data, u64 *val)
3883{
3884 *val = xmon_on;
3885 return 0;
3886}
3887
3888DEFINE_SIMPLE_ATTRIBUTE(xmon_dbgfs_ops, xmon_dbgfs_get,
3889 xmon_dbgfs_set, "%llu\n");
3890
3891static int __init setup_xmon_dbgfs(void)
3892{
3893 debugfs_create_file("xmon", 0600, powerpc_debugfs_root, NULL,
3894 &xmon_dbgfs_ops);
3895 return 0;
3896}
3897device_initcall(setup_xmon_dbgfs);
3898#endif /* CONFIG_DEBUG_FS */
3899
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03003900static int xmon_early __initdata;
Michael Ellerman476792832006-10-03 14:12:08 +10003901
3902static int __init early_parse_xmon(char *p)
3903{
Christopher M. Riedl69393cb2019-09-07 01:11:24 -05003904 if (xmon_is_locked_down()) {
3905 xmon_init(0);
3906 xmon_early = 0;
3907 xmon_on = 0;
3908 } else if (!p || strncmp(p, "early", 5) == 0) {
Michael Ellerman476792832006-10-03 14:12:08 +10003909 /* just "xmon" is equivalent to "xmon=early" */
3910 xmon_init(1);
3911 xmon_early = 1;
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003912 xmon_on = 1;
3913 } else if (strncmp(p, "on", 2) == 0) {
Michael Ellerman476792832006-10-03 14:12:08 +10003914 xmon_init(1);
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003915 xmon_on = 1;
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05003916 } else if (strncmp(p, "rw", 2) == 0) {
3917 xmon_init(1);
3918 xmon_on = 1;
3919 xmon_is_ro = false;
3920 } else if (strncmp(p, "ro", 2) == 0) {
3921 xmon_init(1);
3922 xmon_on = 1;
3923 xmon_is_ro = true;
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003924 } else if (strncmp(p, "off", 3) == 0)
3925 xmon_on = 0;
Michael Ellerman476792832006-10-03 14:12:08 +10003926 else
3927 return 1;
3928
3929 return 0;
3930}
3931early_param("xmon", early_parse_xmon);
3932
3933void __init xmon_setup(void)
3934{
Pan Xinhui3b5bf422017-03-22 16:27:49 -03003935 if (xmon_on)
Michael Ellerman476792832006-10-03 14:12:08 +10003936 xmon_init(1);
Michael Ellerman476792832006-10-03 14:12:08 +10003937 if (xmon_early)
3938 debugger(NULL);
3939}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003940
Arnd Bergmanne0555952006-11-27 19:18:55 +01003941#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003942
3943struct spu_info {
3944 struct spu *spu;
3945 u64 saved_mfc_sr1_RW;
3946 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003947 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003948 u8 stopped_ok;
3949};
3950
3951#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3952
3953static struct spu_info spu_info[XMON_NUM_SPUS];
3954
3955void xmon_register_spus(struct list_head *list)
3956{
3957 struct spu *spu;
3958
3959 list_for_each_entry(spu, list, full_list) {
3960 if (spu->number >= XMON_NUM_SPUS) {
3961 WARN_ON(1);
3962 continue;
3963 }
3964
3965 spu_info[spu->number].spu = spu;
3966 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003967 spu_info[spu->number].dump_addr = (unsigned long)
3968 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003969 }
3970}
3971
3972static void stop_spus(void)
3973{
3974 struct spu *spu;
3975 int i;
3976 u64 tmp;
3977
3978 for (i = 0; i < XMON_NUM_SPUS; i++) {
3979 if (!spu_info[i].spu)
3980 continue;
3981
3982 if (setjmp(bus_error_jmp) == 0) {
3983 catch_memory_errors = 1;
3984 sync();
3985
3986 spu = spu_info[i].spu;
3987
3988 spu_info[i].saved_spu_runcntl_RW =
3989 in_be32(&spu->problem->spu_runcntl_RW);
3990
3991 tmp = spu_mfc_sr1_get(spu);
3992 spu_info[i].saved_mfc_sr1_RW = tmp;
3993
3994 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3995 spu_mfc_sr1_set(spu, tmp);
3996
3997 sync();
3998 __delay(200);
3999
4000 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01004001
4002 printf("Stopped spu %.2d (was %s)\n", i,
4003 spu_info[i].saved_spu_runcntl_RW ?
4004 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004005 } else {
4006 catch_memory_errors = 0;
4007 printf("*** Error stopping spu %.2d\n", i);
4008 }
4009 catch_memory_errors = 0;
4010 }
4011}
4012
4013static void restart_spus(void)
4014{
4015 struct spu *spu;
4016 int i;
4017
4018 for (i = 0; i < XMON_NUM_SPUS; i++) {
4019 if (!spu_info[i].spu)
4020 continue;
4021
4022 if (!spu_info[i].stopped_ok) {
4023 printf("*** Error, spu %d was not successfully stopped"
4024 ", not restarting\n", i);
4025 continue;
4026 }
4027
4028 if (setjmp(bus_error_jmp) == 0) {
4029 catch_memory_errors = 1;
4030 sync();
4031
4032 spu = spu_info[i].spu;
4033 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
4034 out_be32(&spu->problem->spu_runcntl_RW,
4035 spu_info[i].saved_spu_runcntl_RW);
4036
4037 sync();
4038 __delay(200);
4039
4040 printf("Restarted spu %.2d\n", i);
4041 } else {
4042 catch_memory_errors = 0;
4043 printf("*** Error restarting spu %.2d\n", i);
4044 }
4045 catch_memory_errors = 0;
4046 }
4047}
4048
Michael Ellermana8984972006-10-24 18:31:28 +02004049#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01004050#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02004051do { \
4052 if (setjmp(bus_error_jmp) == 0) { \
4053 catch_memory_errors = 1; \
4054 sync(); \
4055 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01004056 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02004057 sync(); \
4058 __delay(200); \
4059 } else { \
4060 catch_memory_errors = 0; \
4061 printf(" %-*s = *** Error reading field.\n", \
4062 DUMP_WIDTH, #field); \
4063 } \
4064 catch_memory_errors = 0; \
4065} while (0)
4066
Michael Ellerman437a0702006-11-23 00:46:39 +01004067#define DUMP_FIELD(obj, format, field) \
4068 DUMP_VALUE(format, field, obj->field)
4069
Michael Ellermana8984972006-10-24 18:31:28 +02004070static void dump_spu_fields(struct spu *spu)
4071{
4072 printf("Dumping spu fields at address %p:\n", spu);
4073
4074 DUMP_FIELD(spu, "0x%x", number);
4075 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02004076 DUMP_FIELD(spu, "0x%lx", local_store_phys);
4077 DUMP_FIELD(spu, "0x%p", local_store);
4078 DUMP_FIELD(spu, "0x%lx", ls_size);
4079 DUMP_FIELD(spu, "0x%x", node);
4080 DUMP_FIELD(spu, "0x%lx", flags);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02004081 DUMP_FIELD(spu, "%llu", class_0_pending);
4082 DUMP_FIELD(spu, "0x%llx", class_0_dar);
4083 DUMP_FIELD(spu, "0x%llx", class_1_dar);
4084 DUMP_FIELD(spu, "0x%llx", class_1_dsisr);
4085 DUMP_FIELD(spu, "0x%x", irqs[0]);
4086 DUMP_FIELD(spu, "0x%x", irqs[1]);
4087 DUMP_FIELD(spu, "0x%x", irqs[2]);
Michael Ellermana8984972006-10-24 18:31:28 +02004088 DUMP_FIELD(spu, "0x%x", slb_replace);
4089 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02004090 DUMP_FIELD(spu, "0x%p", mm);
4091 DUMP_FIELD(spu, "0x%p", ctx);
4092 DUMP_FIELD(spu, "0x%p", rq);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02004093 DUMP_FIELD(spu, "0x%llx", timestamp);
Michael Ellermana8984972006-10-24 18:31:28 +02004094 DUMP_FIELD(spu, "0x%lx", problem_phys);
4095 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01004096 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
4097 in_be32(&spu->problem->spu_runcntl_RW));
4098 DUMP_VALUE("0x%x", problem->spu_status_R,
4099 in_be32(&spu->problem->spu_status_R));
4100 DUMP_VALUE("0x%x", problem->spu_npc_RW,
4101 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02004102 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01004103 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02004104}
4105
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004106int
4107spu_inst_dump(unsigned long adr, long count, int praddr)
4108{
4109 return generic_inst_dump(adr, count, praddr, print_insn_spu);
4110}
4111
4112static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01004113{
4114 unsigned long offset, addr, ls_addr;
4115
4116 if (setjmp(bus_error_jmp) == 0) {
4117 catch_memory_errors = 1;
4118 sync();
4119 ls_addr = (unsigned long)spu_info[num].spu->local_store;
4120 sync();
4121 __delay(200);
4122 } else {
4123 catch_memory_errors = 0;
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02004124 printf("*** Error: accessing spu info for spu %ld\n", num);
Michael Ellerman24a24c82006-11-23 00:46:41 +01004125 return;
4126 }
4127 catch_memory_errors = 0;
4128
4129 if (scanhex(&offset))
4130 addr = ls_addr + offset;
4131 else
4132 addr = spu_info[num].dump_addr;
4133
4134 if (addr >= ls_addr + LS_SIZE) {
4135 printf("*** Error: address outside of local store\n");
4136 return;
4137 }
4138
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004139 switch (subcmd) {
4140 case 'i':
4141 addr += spu_inst_dump(addr, 16, 1);
4142 last_cmd = "sdi\n";
4143 break;
4144 default:
4145 prdump(addr, 64);
4146 addr += 64;
4147 last_cmd = "sd\n";
4148 break;
4149 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01004150
4151 spu_info[num].dump_addr = addr;
4152}
4153
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004154static int do_spu_cmd(void)
4155{
Michael Ellerman24a24c82006-11-23 00:46:41 +01004156 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004157 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004158
4159 cmd = inchar();
4160 switch (cmd) {
4161 case 's':
4162 stop_spus();
4163 break;
4164 case 'r':
4165 restart_spus();
4166 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01004167 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004168 subcmd = inchar();
4169 if (isxdigit(subcmd) || subcmd == '\n')
4170 termch = subcmd;
Stephen Rothwell8ad94022018-11-29 09:28:30 +11004171 /* fall through */
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004172 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01004173 scanhex(&num);
4174 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02004175 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01004176 return 0;
4177 }
4178
4179 switch (cmd) {
4180 case 'f':
4181 dump_spu_fields(spu_info[num].spu);
4182 break;
4183 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004184 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01004185 break;
4186 }
4187
Michael Ellermana8984972006-10-24 18:31:28 +02004188 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004189 default:
4190 return -1;
4191 }
4192
4193 return 0;
4194}
Arnd Bergmanne0555952006-11-27 19:18:55 +01004195#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004196static int do_spu_cmd(void)
4197{
4198 return -1;
4199}
4200#endif