blob: 8b28ff9d98d16b43ead8112f15ffe24d8d9a6940 [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>
Aneesh Kumar K.Vdbf77fed2021-08-12 18:58:31 +053029#include <linux/debugfs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <asm/mmu.h>
39#include <asm/mmu_context.h>
Michael Ellermanab83dc72018-03-08 13:54:42 +110040#include <asm/plpar_wrappers.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <asm/cputable.h>
42#include <asm/rtas.h>
43#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100044#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020045#include <asm/spu.h>
46#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110047#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000048#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010049#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000050#include <asm/hw_breakpoint.h>
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +100051#include <asm/xive.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110052#include <asm/opal.h>
53#include <asm/firmware.h>
Balbir Singhefe4fbb2017-06-27 17:48:58 +100054#include <asm/code-patching.h>
Boqun Feng302c7b02016-11-22 17:20:09 +080055#include <asm/sections.h>
Jordan Niethe75346252020-05-06 13:40:26 +100056#include <asm/inst.h>
Xiongwei Song7153d4b2021-04-14 19:00:33 +080057#include <asm/interrupt.h>
Andrew Donnellanfde93a02016-02-09 18:17:49 +110058
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100059#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100061#include <asm/paca.h>
62#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010065#include "dis-asm.h"
Jordan Niethe4eff2b4f2020-05-06 13:40:23 +100066#include "xmon_bpts.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100069static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static unsigned long xmon_taken = 1;
71static int xmon_owner;
72static int xmon_gate;
Naveen N. Raob8ee3e62021-06-01 13:18:01 +053073static int xmon_batch;
74static unsigned long xmon_batch_start_cpu;
75static cpumask_t xmon_batch_cpus = CPU_MASK_NONE;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000076#else
77#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070078#endif /* CONFIG_SMP */
79
Breno Leitao8d4a8622018-11-08 15:12:42 -020080#ifdef CONFIG_PPC_PSERIES
81static int set_indicator_token = RTAS_UNKNOWN_SERVICE;
82#endif
Anton Blanchard5be34922010-01-12 00:50:14 +000083static unsigned long in_xmon __read_mostly = 0;
Pan Xinhui3b5bf422017-03-22 16:27:49 -030084static int xmon_on = IS_ENABLED(CONFIG_XMON_DEFAULT);
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -050085static bool xmon_is_ro = IS_ENABLED(CONFIG_XMON_DEFAULT_RO_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
87static unsigned long adrs;
88static int size = 1;
Michael Ellermand64c7db2020-02-19 22:00:07 +110089#define MAX_DUMP (64 * 1024)
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static unsigned long ndump = 64;
Michael Ellermand64c7db2020-02-19 22:00:07 +110091#define MAX_IDUMP (MAX_DUMP >> 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070092static unsigned long nidump = 16;
93static unsigned long ncsum = 4096;
94static int termch;
95static char tmpstr[128];
Breno Leitaoed49f7f2017-08-02 17:14:06 -030096static int tracing_enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static long bus_error_jmp[JMP_BUF_LEN];
99static int catch_memory_errors;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000100static int catch_spr_faults;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
103/* Breakpoint stuff */
104struct bpt {
105 unsigned long address;
Christophe Leroy69d4d6e2021-05-20 13:50:45 +0000106 u32 *instr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 atomic_t ref_count;
108 int enabled;
109 unsigned long pad;
110};
111
112/* Bits in bpt.enabled */
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100113#define BP_CIABR 1
114#define BP_TRAP 2
115#define BP_DABR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117static struct bpt bpts[NBPTS];
Ravi Bangoria30df74d2020-05-14 16:47:41 +0530118static struct bpt dabr[HBP_NUM_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119static struct bpt *iabr;
120static unsigned bpinstr = 0x7fe00008; /* trap */
121
122#define BP_NUM(bp) ((bp) - bpts + 1)
123
124/* Prototypes */
125static int cmds(struct pt_regs *);
126static int mread(unsigned long, void *, int);
127static int mwrite(unsigned long, void *, int);
Jordan Niethe6c7a4f02020-05-06 13:40:38 +1000128static int mread_instr(unsigned long, struct ppc_inst *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129static int handle_fault(struct pt_regs *);
130static void byterev(unsigned char *, int);
131static void memex(void);
132static int bsesc(void);
133static void dump(void);
Balbir Singh80eff6c2017-10-30 22:01:12 +1100134static void show_pte(unsigned long);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135static void prdump(unsigned long, long);
136static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000137static void dump_log_buf(void);
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100138
Naveen N. Raob8ee3e62021-06-01 13:18:01 +0530139#ifdef CONFIG_SMP
140static int xmon_switch_cpu(unsigned long);
141static int xmon_batch_next_cpu(void);
142static int batch_cmds(struct pt_regs *);
143#endif
144
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100145#ifdef CONFIG_PPC_POWERNV
146static void dump_opal_msglog(void);
147#else
148static inline void dump_opal_msglog(void)
149{
150 printf("Machine is not running OPAL firmware.\n");
151}
152#endif
153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154static void backtrace(struct pt_regs *);
155static void excprint(struct pt_regs *);
156static void prregs(struct pt_regs *);
157static void memops(int);
158static void memlocate(void);
159static void memzcan(void);
160static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
161int skipbl(void);
162int scanhex(unsigned long *valp);
163static void scannl(void);
164static int hexdigit(int);
165void getstring(char *, int);
166static void flush_input(void);
167static int inchar(void);
168static void take_input(char *);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000169static int read_spr(int, unsigned long *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170static void write_spr(int, unsigned long);
171static void super_regs(void);
172static void remove_bpts(void);
173static void insert_bpts(void);
174static void remove_cpu_bpts(void);
175static void insert_cpu_bpts(void);
176static struct bpt *at_breakpoint(unsigned long pc);
177static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
178static int do_step(struct pt_regs *);
179static void bpt_cmds(void);
180static void cacheflush(void);
181static int cpu_cmd(void);
182static void csum(void);
183static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000184static void proccall(void);
Douglas Miller6dfb5402015-11-23 09:01:15 -0600185static void show_tasks(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186void dump_segments(void);
187static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200188static void xmon_show_stack(unsigned long sp, unsigned long lr,
189 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static void xmon_print_symbol(unsigned long address, const char *mid,
191 const char *after);
192static const char *getvecname(unsigned long vec);
193
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200194static int do_spu_cmd(void);
195
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100196#ifdef CONFIG_44x
197static void dump_tlb_44x(void);
198#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000199#ifdef CONFIG_PPC_BOOK3E
200static void dump_tlb_book3e(void);
201#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100202
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500203static void clear_all_bpt(void);
204
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000205#ifdef CONFIG_PPC64
206#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000207#else
208#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000209#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100211#ifdef __LITTLE_ENDIAN__
212#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
213#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100215#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -0500217static const char *xmon_ro_msg = "Operation disabled: xmon in read-only mode\n";
218
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219static char *help_string = "\
220Commands:\n\
221 b show breakpoints\n\
222 bd set data breakpoint\n\
223 bi set instruction breakpoint\n\
224 bc clear breakpoint\n"
225#ifdef CONFIG_SMP
226 "\
227 c print cpus stopped in xmon\n\
Naveen N. Raob8ee3e62021-06-01 13:18:01 +0530228 c# try to switch to cpu number h (in hex)\n\
229 c# $ run command '$' (one of 'r','S' or 't') on all cpus in xmon\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230#endif
231 "\
232 C checksum\n\
233 d dump bytes\n\
Douglas Miller5e48dc02017-02-07 07:40:44 -0600234 d1 dump 1 byte values\n\
235 d2 dump 2 byte values\n\
236 d4 dump 4 byte values\n\
237 d8 dump 8 byte values\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 di dump instructions\n\
239 df dump float values\n\
240 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000241 dl dump the kernel log buffer\n"
Andrew Donnellanfde93a02016-02-09 18:17:49 +1100242#ifdef CONFIG_PPC_POWERNV
243 "\
244 do dump the OPAL message log\n"
245#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000246#ifdef CONFIG_PPC64
247 "\
248 dp[#] dump paca for current cpu, or cpu #\n\
249 dpa dump paca for all possible cpus\n"
250#endif
251 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100252 dr dump stream of raw bytes\n\
Balbir Singh80eff6c2017-10-30 22:01:12 +1100253 dv dump virtual address translation \n\
Michael Ellerman56144ec2015-11-06 13:21:17 +1100254 dt dump the tracing buffers (uses printk)\n\
Breno Leitao4125d012017-08-02 17:14:05 -0300255 dtc dump the tracing buffers for current CPU (uses printk)\n\
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +1000256"
257#ifdef CONFIG_PPC_POWERNV
258" dx# dump xive on CPU #\n\
259 dxi# dump xive irq state #\n\
260 dxa dump xive on all CPUs\n"
261#endif
262" e print exception information\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 f flush cache\n\
264 la lookup symbol+offset of specified address\n\
265 ls lookup address of specified symbol\n\
Boqun Feng302c7b02016-11-22 17:20:09 +0800266 lp s [#] lookup address of percpu symbol s for current cpu, or cpu #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 m examine/change memory\n\
268 mm move a block of memory\n\
269 ms set a block of memory\n\
270 md compare two blocks of memory\n\
271 ml locate a block of memory\n\
272 mz zero a block of memory\n\
273 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000274 p call a procedure\n\
Douglas Miller6dfb5402015-11-23 09:01:15 -0600275 P list processes/tasks\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200277 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100278#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200279" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200280 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100281 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900282 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100283 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200284#endif
285" S print special registers\n\
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000286 Sa print all SPRs\n\
287 Sr # read SPR #\n\
288 Sw #v write v to SPR #\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 x exit monitor and recover\n\
Andrew Donnellan2e340572016-01-27 11:29:44 +1100291 X exit monitor and don't recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000292#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000293" u dump segment table or SLB\n"
Christophe Leroy68289ae2018-11-17 10:25:02 +0000294#elif defined(CONFIG_PPC_BOOK3S_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000295" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000296#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100297" u dump TLB\n"
298#endif
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -0300299" U show uptime information\n"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000300" ? help\n"
Sam bobroff0c23a882015-10-08 11:50:24 +1100301" # n limit output to n lines per page (for dp, dpa, dl)\n"
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500302" zr reboot\n"
303" zh halt\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304;
305
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500306#ifdef CONFIG_SECURITY
307static bool xmon_is_locked_down(void)
308{
309 static bool lockdown;
310
311 if (!lockdown) {
312 lockdown = !!security_locked_down(LOCKDOWN_XMON_RW);
313 if (lockdown) {
314 printf("xmon: Disabled due to kernel lockdown\n");
315 xmon_is_ro = true;
316 }
317 }
318
319 if (!xmon_is_ro) {
320 xmon_is_ro = !!security_locked_down(LOCKDOWN_XMON_WR);
321 if (xmon_is_ro)
322 printf("xmon: Read-only due to kernel lockdown\n");
323 }
324
325 return lockdown;
326}
327#else /* CONFIG_SECURITY */
328static inline bool xmon_is_locked_down(void)
329{
330 return false;
331}
332#endif
333
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334static struct pt_regs *xmon_regs;
335
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000336static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
338 asm volatile("sync; isync");
339}
340
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000341static inline void cflush(void *p)
342{
343 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
344}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000346static inline void cinval(void *p)
347{
348 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
349}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530351/**
352 * write_ciabr() - write the CIABR SPR
353 * @ciabr: The value to write.
354 *
355 * This function writes a value to the CIARB register either directly
356 * through mtspr instruction if the kernel is in HV privilege mode or
357 * call a hypervisor function to achieve the same in case the kernel
358 * is in supervisor privilege mode.
359 */
360static void write_ciabr(unsigned long ciabr)
361{
362 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
363 return;
364
365 if (cpu_has_feature(CPU_FTR_HVMODE)) {
366 mtspr(SPRN_CIABR, ciabr);
367 return;
368 }
Michael Ellerman7c09c182018-03-08 13:54:41 +1100369 plpar_set_ciabr(ciabr);
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530370}
371
372/**
373 * set_ciabr() - set the CIABR
374 * @addr: The value to set.
375 *
376 * This function sets the correct privilege value into the the HW
377 * breakpoint address before writing it up in the CIABR register.
378 */
379static void set_ciabr(unsigned long addr)
380{
381 addr &= ~CIABR_PRIV;
382
383 if (cpu_has_feature(CPU_FTR_HVMODE))
384 addr |= CIABR_PRIV_HYPER;
385 else
386 addr |= CIABR_PRIV_SUPER;
387 write_ciabr(addr);
388}
389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390/*
391 * Disable surveillance (the service processor watchdog function)
392 * while we are in xmon.
393 * XXX we should re-enable it when we leave. :)
394 */
395#define SURVEILLANCE_TOKEN 9000
396
397static inline void disable_surveillance(void)
398{
399#ifdef CONFIG_PPC_PSERIES
400 /* Since this can't be a module, args should end up below 4GB. */
401 static struct rtas_args args;
402
403 /*
404 * At this point we have got all the cpus we can into
405 * xmon, so there is hopefully no other cpu calling RTAS
406 * at the moment, even though we don't take rtas.lock.
407 * If we did try to take rtas.lock there would be a
408 * real possibility of deadlock.
409 */
Breno Leitao8d4a8622018-11-08 15:12:42 -0200410 if (set_indicator_token == RTAS_UNKNOWN_SERVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 return;
Michael Ellerman08eb1052015-11-24 22:26:09 +1100412
Breno Leitao8d4a8622018-11-08 15:12:42 -0200413 rtas_call_unlocked(&args, set_indicator_token, 3, 1, NULL,
414 SURVEILLANCE_TOKEN, 0, 0);
Michael Ellerman08eb1052015-11-24 22:26:09 +1100415
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416#endif /* CONFIG_PPC_PSERIES */
417}
418
419#ifdef CONFIG_SMP
420static int xmon_speaker;
421
422static void get_output_lock(void)
423{
424 int me = smp_processor_id() + 0x100;
425 int last_speaker = 0, prev;
426 long timeout;
427
428 if (xmon_speaker == me)
429 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100430
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100432 last_speaker = cmpxchg(&xmon_speaker, 0, me);
433 if (last_speaker == 0)
434 return;
435
Michael Ellerman15075892013-12-23 23:46:05 +1100436 /*
437 * Wait a full second for the lock, we might be on a slow
438 * console, but check every 100us.
439 */
440 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100442 if (--timeout > 0) {
443 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100445 }
446
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 /* hostile takeover */
448 prev = cmpxchg(&xmon_speaker, last_speaker, me);
449 if (prev == last_speaker)
450 return;
451 break;
452 }
453 }
454}
455
456static void release_output_lock(void)
457{
458 xmon_speaker = 0;
459}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000460
461int cpus_are_in_xmon(void)
462{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000463 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000464}
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000465
466static bool wait_for_other_cpus(int ncpus)
467{
468 unsigned long timeout;
469
470 /* We wait for 2s, which is a metric "little while" */
471 for (timeout = 20000; timeout != 0; --timeout) {
472 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
473 return true;
474 udelay(100);
475 barrier();
476 }
477
478 return false;
479}
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500480#else /* CONFIG_SMP */
481static inline void get_output_lock(void) {}
482static inline void release_output_lock(void) {}
483#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
Anton Blanchard5c699392020-06-30 10:02:18 +1000485static void xmon_touch_watchdogs(void)
486{
487 touch_softlockup_watchdog_sync();
488 rcu_cpu_stall_reset();
489 touch_nmi_watchdog();
490}
491
Arnd Bergmanna2305e32021-04-29 10:06:38 +0200492static int xmon_core(struct pt_regs *regs, volatile int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493{
Arnd Bergmanna2305e32021-04-29 10:06:38 +0200494 volatile int cmd = 0;
495 struct bpt *volatile bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 long recurse_jmp[JMP_BUF_LEN];
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500497 bool locked_down;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100499 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500#ifdef CONFIG_SMP
501 int cpu;
502 int secondary;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503#endif
504
Anton Blanchardf13659e2007-03-21 01:48:34 +1100505 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000506 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500508 locked_down = xmon_is_locked_down();
509
Naveen N. Raoaaf06662019-06-27 15:29:40 +0530510 if (!fromipi) {
511 tracing_enabled = tracing_is_on();
512 tracing_off();
513 }
Breno Leitaoed49f7f2017-08-02 17:14:06 -0300514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 bp = in_breakpoint_table(regs->nip, &offset);
516 if (bp != NULL) {
Nicholas Piggin59dc5bf2021-06-18 01:51:03 +1000517 regs_set_return_ip(regs, bp->address + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 atomic_dec(&bp->ref_count);
519 }
520
521 remove_cpu_bpts();
522
523#ifdef CONFIG_SMP
524 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000525 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +1000526 /*
527 * We catch SPR read/write faults here because the 0x700, 0xf60
528 * etc. handlers don't call debugger_fault_handler().
529 */
530 if (catch_spr_faults)
531 longjmp(bus_error_jmp, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 get_output_lock();
533 excprint(regs);
534 printf("cpu 0x%x: Exception %lx %s in xmon, "
535 "returning to main loop\n",
536 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000537 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 longjmp(xmon_fault_jmp[cpu], 1);
539 }
540
541 if (setjmp(recurse_jmp) != 0) {
542 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000543 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 printf("xmon: WARNING: bad recursive fault "
545 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000546 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 goto waiting;
548 }
549 secondary = !(xmon_taken && cpu == xmon_owner);
550 goto cmdloop;
551 }
552
553 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000556 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 bp = at_breakpoint(regs->nip);
Christophe Leroy806c0e62021-08-23 08:24:21 +0000558 if (bp || regs_is_unrecoverable(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 fromipi = 0;
560
561 if (!fromipi) {
562 get_output_lock();
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500563 if (!locked_down)
564 excprint(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 if (bp) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +0200566 printf("cpu 0x%x stopped at breakpoint 0x%tx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 cpu, BP_NUM(bp));
568 xmon_print_symbol(regs->nip, " ", ")\n");
569 }
Christophe Leroy806c0e62021-08-23 08:24:21 +0000570 if (regs_is_unrecoverable(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 printf("WARNING: exception is not recoverable, "
572 "can't continue\n");
573 release_output_lock();
574 }
575
Michael Ellermand2b496e2013-12-23 23:46:06 +1100576 cpumask_set_cpu(cpu, &cpus_in_xmon);
577
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 waiting:
579 secondary = 1;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000580 spin_begin();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 while (secondary && !xmon_gate) {
582 if (in_xmon == 0) {
Nicholas Piggin064996d2017-09-29 13:29:40 +1000583 if (fromipi) {
584 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 goto leave;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 secondary = test_and_set_bit(0, &in_xmon);
588 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000589 spin_cpu_relax();
590 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000592 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
594 if (!secondary && !xmon_gate) {
595 /* we are the first cpu to come in */
596 /* interrupt other cpu(s) */
597 int ncpus = num_online_cpus();
598
599 xmon_owner = cpu;
600 mb();
601 if (ncpus > 1) {
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000602 /*
603 * A system reset (trap == 0x100) can be triggered on
604 * all CPUs, so when we come in via 0x100 try waiting
605 * for the other CPUs to come in before we send the
606 * debugger break (IPI). This is similar to
607 * crash_kexec_secondary().
608 */
Xiongwei Song7153d4b2021-04-14 19:00:33 +0800609 if (TRAP(regs) != INTERRUPT_SYSTEM_RESET || !wait_for_other_cpus(ncpus))
Nicholas Piggin1cd6ed72016-12-20 04:30:11 +1000610 smp_send_debugger_break();
611
612 wait_for_other_cpus(ncpus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 }
614 remove_bpts();
615 disable_surveillance();
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500616
617 if (!locked_down) {
618 /* for breakpoint or single step, print curr insn */
Xiongwei Song7153d4b2021-04-14 19:00:33 +0800619 if (bp || TRAP(regs) == INTERRUPT_TRACE)
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500620 ppc_inst_dump(regs->nip, 1, 0);
621 printf("enter ? for help\n");
622 }
623
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 mb();
625 xmon_gate = 1;
626 barrier();
Nicholas Piggin064996d2017-09-29 13:29:40 +1000627 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 }
629
630 cmdloop:
631 while (in_xmon) {
632 if (secondary) {
Nicholas Piggin064996d2017-09-29 13:29:40 +1000633 spin_begin();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 if (cpu == xmon_owner) {
635 if (!test_and_set_bit(0, &xmon_taken)) {
636 secondary = 0;
Nicholas Piggin064996d2017-09-29 13:29:40 +1000637 spin_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 continue;
639 }
640 /* missed it */
641 while (cpu == xmon_owner)
Nicholas Piggin064996d2017-09-29 13:29:40 +1000642 spin_cpu_relax();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 }
Nicholas Piggin064996d2017-09-29 13:29:40 +1000644 spin_cpu_relax();
645 touch_nmi_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 } else {
Naveen N. Raob8ee3e62021-06-01 13:18:01 +0530647 cmd = 1;
648#ifdef CONFIG_SMP
649 if (xmon_batch)
650 cmd = batch_cmds(regs);
651#endif
652 if (!locked_down && cmd)
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500653 cmd = cmds(regs);
654 if (locked_down || cmd != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 /* exiting xmon */
656 insert_bpts();
657 xmon_gate = 0;
658 wmb();
659 in_xmon = 0;
660 break;
661 }
662 /* have switched to some other cpu */
663 secondary = 1;
664 }
665 }
666 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000667 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669#else
670 /* UP is simple... */
671 if (in_xmon) {
672 printf("Exception %lx %s in xmon, returning to main loop\n",
673 regs->trap, getvecname(TRAP(regs)));
674 longjmp(xmon_fault_jmp[0], 1);
675 }
676 if (setjmp(recurse_jmp) == 0) {
677 xmon_fault_jmp[0] = recurse_jmp;
678 in_xmon = 1;
679
680 excprint(regs);
681 bp = at_breakpoint(regs->nip);
682 if (bp) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +0200683 printf("Stopped at breakpoint %tx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 xmon_print_symbol(regs->nip, " ", ")\n");
685 }
Christophe Leroy806c0e62021-08-23 08:24:21 +0000686 if (regs_is_unrecoverable(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 printf("WARNING: exception is not recoverable, "
688 "can't continue\n");
689 remove_bpts();
690 disable_surveillance();
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500691 if (!locked_down) {
692 /* for breakpoint or single step, print current insn */
Xiongwei Song7153d4b2021-04-14 19:00:33 +0800693 if (bp || TRAP(regs) == INTERRUPT_TRACE)
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500694 ppc_inst_dump(regs->nip, 1, 0);
695 printf("enter ? for help\n");
696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 }
698
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500699 if (!locked_down)
700 cmd = cmds(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 insert_bpts();
703 in_xmon = 0;
704#endif
705
Josh Boyercdd39042009-10-05 04:46:05 +0000706#ifdef CONFIG_BOOKE
707 if (regs->msr & MSR_DE) {
708 bp = at_breakpoint(regs->nip);
709 if (bp != NULL) {
Nicholas Piggin59dc5bf2021-06-18 01:51:03 +1000710 regs_set_return_ip(regs, (unsigned long) &bp->instr[0]);
Josh Boyercdd39042009-10-05 04:46:05 +0000711 atomic_inc(&bp->ref_count);
712 }
713 }
714#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000715 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 bp = at_breakpoint(regs->nip);
717 if (bp != NULL) {
Jordan Niethef8faaff2020-05-06 13:40:32 +1000718 int stepped = emulate_step(regs, ppc_inst_read(bp->instr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 if (stepped == 0) {
Nicholas Piggin59dc5bf2021-06-18 01:51:03 +1000720 regs_set_return_ip(regs, (unsigned long) &bp->instr[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 atomic_inc(&bp->ref_count);
722 } else if (stepped < 0) {
723 printf("Couldn't single-step %s instruction\n",
Jordan Niethef8faaff2020-05-06 13:40:32 +1000724 IS_RFID(ppc_inst_read(bp->instr))? "rfid": "mtmsrd");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 }
726 }
727 }
Josh Boyercdd39042009-10-05 04:46:05 +0000728#endif
Christopher M. Riedl69393cb2019-09-07 01:11:24 -0500729 if (locked_down)
730 clear_all_bpt();
731 else
732 insert_cpu_bpts();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
Anton Blanchard5c699392020-06-30 10:02:18 +1000734 xmon_touch_watchdogs();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100735 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000737 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738}
739
740int xmon(struct pt_regs *excp)
741{
742 struct pt_regs regs;
743
744 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000745 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 excp = &regs;
747 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 return xmon_core(excp, 0);
750}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000751EXPORT_SYMBOL(xmon);
752
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000753irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000754{
755 unsigned long flags;
756 local_irq_save(flags);
757 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000758 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000759 local_irq_restore(flags);
760 return IRQ_HANDLED;
761}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000763static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764{
765 struct bpt *bp;
766 unsigned long offset;
767
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000768 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 return 0;
770
771 /* Are we at the trap at bp->instr[1] for some bp? */
772 bp = in_breakpoint_table(regs->nip, &offset);
Jordan Niethe650b55b2020-05-15 12:12:55 +1000773 if (bp != NULL && (offset == 4 || offset == 8)) {
Nicholas Piggin59dc5bf2021-06-18 01:51:03 +1000774 regs_set_return_ip(regs, bp->address + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 atomic_dec(&bp->ref_count);
776 return 1;
777 }
778
779 /* Are we at a breakpoint? */
780 bp = at_breakpoint(regs->nip);
781 if (!bp)
782 return 0;
783
784 xmon_core(regs, 0);
785
786 return 1;
787}
788
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000789static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
791 if (user_mode(regs))
792 return 0;
793 xmon_core(regs, 0);
794 return 1;
795}
796
Michael Neuling9422de32012-12-20 14:06:44 +0000797static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798{
Ravi Bangoria30df74d2020-05-14 16:47:41 +0530799 int i;
800
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000801 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 return 0;
Ravi Bangoria30df74d2020-05-14 16:47:41 +0530803 for (i = 0; i < nr_wp_slots(); i++) {
804 if (dabr[i].enabled)
805 goto found;
806 }
807 return 0;
808
809found:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 xmon_core(regs, 0);
811 return 1;
812}
813
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000814static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000816 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000818 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 return 0;
820 xmon_core(regs, 0);
821 return 1;
822}
823
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000824static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825{
826#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000827 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 xmon_core(regs, 1);
829#endif
830 return 0;
831}
832
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000833static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
835 struct bpt *bp;
836 unsigned long offset;
837
838 if (in_xmon && catch_memory_errors)
839 handle_fault(regs); /* doesn't return */
840
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000841 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 bp = in_breakpoint_table(regs->nip, &offset);
843 if (bp != NULL) {
Nicholas Piggin59dc5bf2021-06-18 01:51:03 +1000844 regs_set_return_ip(regs, bp->address + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 atomic_dec(&bp->ref_count);
846 }
847 }
848
849 return 0;
850}
851
Michal Suchanek7daf5932018-05-23 20:00:54 +0200852/* Force enable xmon if not already enabled */
853static inline void force_enable_xmon(void)
854{
855 /* Enable xmon hooks if needed */
856 if (!xmon_on) {
857 printf("xmon: Enabling debugger hooks\n");
858 xmon_on = 1;
859 }
860}
861
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862static struct bpt *at_breakpoint(unsigned long pc)
863{
864 int i;
Arnd Bergmanna2305e32021-04-29 10:06:38 +0200865 struct bpt *volatile bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
867 bp = bpts;
868 for (i = 0; i < NBPTS; ++i, ++bp)
869 if (bp->enabled && pc == bp->address)
870 return bp;
871 return NULL;
872}
873
874static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
875{
876 unsigned long off;
877
Jordan Niethe51c9ba12020-05-06 13:40:22 +1000878 off = nip - (unsigned long)bpt_table;
879 if (off >= sizeof(bpt_table))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 return NULL;
Jordan Niethe5a7fdca2020-05-06 13:40:24 +1000881 *offp = off & (BPT_SIZE - 1);
882 if (off & 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 return NULL;
Jordan Niethe51c9ba12020-05-06 13:40:22 +1000884 return bpts + (off / BPT_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885}
886
887static struct bpt *new_breakpoint(unsigned long a)
888{
889 struct bpt *bp;
890
891 a &= ~3UL;
892 bp = at_breakpoint(a);
893 if (bp)
894 return bp;
895
896 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
897 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
898 bp->address = a;
Jordan Niethe94afd062020-05-06 13:40:31 +1000899 bp->instr = (void *)(bpt_table + ((bp - bpts) * BPT_WORDS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 return bp;
901 }
902 }
903
904 printf("Sorry, no free breakpoints. Please clear one first.\n");
905 return NULL;
906}
907
908static void insert_bpts(void)
909{
910 int i;
Jordan Niethec9c831a2020-05-06 13:40:46 +1000911 struct ppc_inst instr, instr2;
912 struct bpt *bp, *bp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914 bp = bpts;
915 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100916 if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 continue;
Jordan Niethe6c7a4f02020-05-06 13:40:38 +1000918 if (!mread_instr(bp->address, &instr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 printf("Couldn't read instruction at %lx, "
920 "disabling breakpoint there\n", bp->address);
921 bp->enabled = 0;
922 continue;
923 }
Jordan Niethe802268f2020-05-06 13:40:21 +1000924 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 printf("Breakpoint at %lx is on an mtmsrd or rfid "
926 "instruction, disabling it\n", bp->address);
927 bp->enabled = 0;
928 continue;
929 }
Jordan Niethec9c831a2020-05-06 13:40:46 +1000930 /*
931 * Check the address is not a suffix by looking for a prefix in
932 * front of it.
933 */
934 if (mread_instr(bp->address - 4, &instr2) == 8) {
935 printf("Breakpoint at %lx is on the second word of a prefixed instruction, disabling it\n",
936 bp->address);
937 bp->enabled = 0;
938 continue;
939 }
940 /*
941 * We might still be a suffix - if the prefix has already been
942 * replaced by a breakpoint we won't catch it with the above
943 * test.
944 */
945 bp2 = at_breakpoint(bp->address - 4);
946 if (bp2 && ppc_inst_prefixed(ppc_inst_read(bp2->instr))) {
947 printf("Breakpoint at %lx is on the second word of a prefixed instruction, disabling it\n",
948 bp->address);
949 bp->enabled = 0;
950 continue;
951 }
952
Jordan Niethe802268f2020-05-06 13:40:21 +1000953 patch_instruction(bp->instr, instr);
Christophe Leroy69d4d6e2021-05-20 13:50:45 +0000954 patch_instruction(ppc_inst_next(bp->instr, bp->instr),
Jordan Niethe7fccfcf2020-05-06 13:40:39 +1000955 ppc_inst(bpinstr));
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100956 if (bp->enabled & BP_CIABR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 continue;
Christophe Leroy69d4d6e2021-05-20 13:50:45 +0000958 if (patch_instruction((u32 *)bp->address,
Jordan Niethe94afd062020-05-06 13:40:31 +1000959 ppc_inst(bpinstr)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 printf("Couldn't write instruction at %lx, "
961 "disabling breakpoint there\n", bp->address);
962 bp->enabled &= ~BP_TRAP;
963 continue;
964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 }
966}
967
968static void insert_cpu_bpts(void)
969{
Ravi Bangoria30df74d2020-05-14 16:47:41 +0530970 int i;
Michael Neuling9422de32012-12-20 14:06:44 +0000971 struct arch_hw_breakpoint brk;
972
Ravi Bangoria30df74d2020-05-14 16:47:41 +0530973 for (i = 0; i < nr_wp_slots(); i++) {
974 if (dabr[i].enabled) {
975 brk.address = dabr[i].address;
976 brk.type = (dabr[i].enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
977 brk.len = 8;
Ravi Bangoria58da5982020-09-02 09:59:43 +0530978 brk.hw_len = 8;
Ravi Bangoria30df74d2020-05-14 16:47:41 +0530979 __set_breakpoint(i, &brk);
980 }
Michael Neuling9422de32012-12-20 14:06:44 +0000981 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +0530982
983 if (iabr)
984 set_ciabr(iabr->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985}
986
987static void remove_bpts(void)
988{
989 int i;
990 struct bpt *bp;
Jordan Niethe94afd062020-05-06 13:40:31 +1000991 struct ppc_inst instr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 bp = bpts;
994 for (i = 0; i < NBPTS; ++i, ++bp) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +1100995 if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 continue;
Jordan Niethe6c7a4f02020-05-06 13:40:38 +1000997 if (mread_instr(bp->address, &instr)
Jordan Niethe217862d2020-05-06 13:40:30 +1000998 && ppc_inst_equal(instr, ppc_inst(bpinstr))
Balbir Singhefe4fbb2017-06-27 17:48:58 +1000999 && patch_instruction(
Christophe Leroy69d4d6e2021-05-20 13:50:45 +00001000 (u32 *)bp->address, ppc_inst_read(bp->instr)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 printf("Couldn't remove breakpoint at %lx\n",
1002 bp->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 }
1004}
1005
1006static void remove_cpu_bpts(void)
1007{
Michael Neuling9422de32012-12-20 14:06:44 +00001008 hw_breakpoint_disable();
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301009 write_ciabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010}
1011
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -03001012/* Based on uptime_proc_show(). */
1013static void
1014show_uptime(void)
1015{
Arnd Bergmannf6bd74f2018-06-18 11:56:24 +02001016 struct timespec64 uptime;
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -03001017
1018 if (setjmp(bus_error_jmp) == 0) {
1019 catch_memory_errors = 1;
1020 sync();
1021
Arnd Bergmannf6bd74f2018-06-18 11:56:24 +02001022 ktime_get_coarse_boottime_ts64(&uptime);
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -03001023 printf("Uptime: %lu.%.2lu seconds\n", (unsigned long)uptime.tv_sec,
1024 ((unsigned long)uptime.tv_nsec / (NSEC_PER_SEC/100)));
1025
1026 sync();
1027 __delay(200); \
1028 }
1029 catch_memory_errors = 0;
1030}
1031
Sam bobroff958b7c82015-10-08 11:50:23 +11001032static void set_lpp_cmd(void)
1033{
1034 unsigned long lpp;
1035
1036 if (!scanhex(&lpp)) {
1037 printf("Invalid number.\n");
1038 lpp = 0;
1039 }
1040 xmon_set_pagination_lpp(lpp);
1041}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042/* Command interpreting routine */
1043static char *last_cmd;
1044
1045static int
1046cmds(struct pt_regs *excp)
1047{
1048 int cmd = 0;
1049
1050 last_cmd = NULL;
1051 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +02001052
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03001053 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
Olaf Hering26c8af52006-09-08 16:29:21 +02001054
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 for(;;) {
1056#ifdef CONFIG_SMP
1057 printf("%x:", smp_processor_id());
1058#endif /* CONFIG_SMP */
1059 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 flush_input();
1061 termch = 0;
1062 cmd = skipbl();
1063 if( cmd == '\n' ) {
1064 if (last_cmd == NULL)
1065 continue;
1066 take_input(last_cmd);
1067 last_cmd = NULL;
1068 cmd = inchar();
1069 }
1070 switch (cmd) {
1071 case 'm':
1072 cmd = inchar();
1073 switch (cmd) {
1074 case 'm':
1075 case 's':
1076 case 'd':
1077 memops(cmd);
1078 break;
1079 case 'l':
1080 memlocate();
1081 break;
1082 case 'z':
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05001083 if (xmon_is_ro) {
1084 printf(xmon_ro_msg);
1085 break;
1086 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 memzcan();
1088 break;
1089 case 'i':
Michal Hocko9af744d2017-02-22 15:46:16 -08001090 show_mem(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 break;
1092 default:
1093 termch = cmd;
1094 memex();
1095 }
1096 break;
1097 case 'd':
1098 dump();
1099 break;
1100 case 'l':
1101 symbol_lookup();
1102 break;
1103 case 'r':
1104 prregs(excp); /* print regs */
1105 break;
1106 case 'e':
1107 excprint(excp);
1108 break;
1109 case 'S':
1110 super_regs();
1111 break;
1112 case 't':
1113 backtrace(excp);
1114 break;
1115 case 'f':
1116 cacheflush();
1117 break;
1118 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +02001119 if (do_spu_cmd() == 0)
1120 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 if (do_step(excp))
1122 return cmd;
1123 break;
1124 case 'x':
1125 case 'X':
Breno Leitaoed49f7f2017-08-02 17:14:06 -03001126 if (tracing_enabled)
1127 tracing_on();
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001128 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +11001130 printf(" <no input ...>\n");
1131 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 return cmd;
1133 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +10001134 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 break;
Sam bobroff958b7c82015-10-08 11:50:23 +11001136 case '#':
1137 set_lpp_cmd();
1138 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 case 'b':
1140 bpt_cmds();
1141 break;
1142 case 'C':
1143 csum();
1144 break;
1145 case 'c':
1146 if (cpu_cmd())
1147 return 0;
1148 break;
1149 case 'z':
1150 bootcmds();
1151 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001152 case 'p':
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05001153 if (xmon_is_ro) {
1154 printf(xmon_ro_msg);
1155 break;
1156 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001157 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 break;
Douglas Miller6dfb5402015-11-23 09:01:15 -06001159 case 'P':
1160 show_tasks();
1161 break;
Christophe Leroy5b3e84f2018-11-17 10:25:04 +00001162#ifdef CONFIG_PPC_BOOK3S
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 case 'u':
1164 dump_segments();
1165 break;
Michael Ellermand8ee6f32014-11-12 16:54:54 +11001166#elif defined(CONFIG_44x)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11001167 case 'u':
1168 dump_tlb_44x();
1169 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +00001170#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10001171 case 'u':
1172 dump_tlb_book3e();
1173 break;
1174#endif
Guilherme G. Piccoli59d33912017-09-18 11:16:58 -03001175 case 'U':
1176 show_uptime();
1177 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 default:
1179 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +00001180 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 if (' ' < cmd && cmd <= '~')
1182 putchar(cmd);
1183 else
1184 printf("\\x%x", cmd);
1185 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +00001186 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 printf(" (type ? for help)\n");
1188 break;
1189 }
1190 }
1191}
1192
Josh Boyercdd39042009-10-05 04:46:05 +00001193#ifdef CONFIG_BOOKE
1194static int do_step(struct pt_regs *regs)
1195{
Nicholas Piggin59dc5bf2021-06-18 01:51:03 +10001196 regs_set_return_msr(regs, regs->msr | MSR_DE);
Josh Boyercdd39042009-10-05 04:46:05 +00001197 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1198 return 1;
1199}
1200#else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201/*
1202 * Step a single instruction.
1203 * Some instructions we emulate, others we execute with MSR_SE set.
1204 */
1205static int do_step(struct pt_regs *regs)
1206{
Jordan Niethe94afd062020-05-06 13:40:31 +10001207 struct ppc_inst instr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 int stepped;
1209
Michal Suchanek7daf5932018-05-23 20:00:54 +02001210 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +00001212 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Jordan Niethe6c7a4f02020-05-06 13:40:38 +10001213 if (mread_instr(regs->nip, &instr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 stepped = emulate_step(regs, instr);
1215 if (stepped < 0) {
1216 printf("Couldn't single-step %s instruction\n",
1217 (IS_RFID(instr)? "rfid": "mtmsrd"));
1218 return 0;
1219 }
1220 if (stepped > 0) {
Nicholas Piggindb301442020-05-07 22:13:30 +10001221 set_trap(regs, 0xd00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 printf("stepped to ");
1223 xmon_print_symbol(regs->nip, " ", "\n");
1224 ppc_inst_dump(regs->nip, 1, 0);
1225 return 0;
1226 }
1227 }
1228 }
Nicholas Piggin59dc5bf2021-06-18 01:51:03 +10001229 regs_set_return_msr(regs, regs->msr | MSR_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 return 1;
1231}
Josh Boyercdd39042009-10-05 04:46:05 +00001232#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
1234static void bootcmds(void)
1235{
Oliver O'Halloran2d9b3322019-11-01 19:55:21 +11001236 char tmp[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 int cmd;
1238
1239 cmd = inchar();
Oliver O'Halloran2d9b3322019-11-01 19:55:21 +11001240 if (cmd == 'r') {
1241 getstring(tmp, 64);
1242 ppc_md.restart(tmp);
1243 } else if (cmd == 'h') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 ppc_md.halt();
Oliver O'Halloran2d9b3322019-11-01 19:55:21 +11001245 } else if (cmd == 'p') {
Alexander Graf9178ba22014-10-13 16:01:09 +02001246 if (pm_power_off)
1247 pm_power_off();
Oliver O'Halloran2d9b3322019-11-01 19:55:21 +11001248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249}
1250
Naveen N. Raob8ee3e62021-06-01 13:18:01 +05301251#ifdef CONFIG_SMP
1252static int xmon_switch_cpu(unsigned long cpu)
1253{
1254 int timeout;
1255
1256 xmon_taken = 0;
1257 mb();
1258 xmon_owner = cpu;
1259 timeout = 10000000;
1260 while (!xmon_taken) {
1261 if (--timeout == 0) {
1262 if (test_and_set_bit(0, &xmon_taken))
1263 break;
1264 /* take control back */
1265 mb();
1266 xmon_owner = smp_processor_id();
1267 printf("cpu 0x%lx didn't take control\n", cpu);
1268 return 0;
1269 }
1270 barrier();
1271 }
1272 return 1;
1273}
1274
1275static int xmon_batch_next_cpu(void)
1276{
1277 unsigned long cpu;
1278
1279 while (!cpumask_empty(&xmon_batch_cpus)) {
1280 cpu = cpumask_next_wrap(smp_processor_id(), &xmon_batch_cpus,
1281 xmon_batch_start_cpu, true);
1282 if (cpu == nr_cpumask_bits)
1283 break;
1284 if (xmon_batch_start_cpu == -1)
1285 xmon_batch_start_cpu = cpu;
1286 if (xmon_switch_cpu(cpu))
1287 return 0;
1288 cpumask_clear_cpu(cpu, &xmon_batch_cpus);
1289 }
1290
1291 xmon_batch = 0;
1292 printf("%x:mon> \n", smp_processor_id());
1293 return 1;
1294}
1295
1296static int batch_cmds(struct pt_regs *excp)
1297{
1298 int cmd;
1299
1300 /* simulate command entry */
1301 cmd = xmon_batch;
1302 termch = '\n';
1303
1304 last_cmd = NULL;
1305 xmon_regs = excp;
1306
1307 printf("%x:", smp_processor_id());
1308 printf("mon> ");
1309 printf("%c\n", (char)cmd);
1310
1311 switch (cmd) {
1312 case 'r':
1313 prregs(excp); /* print regs */
1314 break;
1315 case 'S':
1316 super_regs();
1317 break;
1318 case 't':
1319 backtrace(excp);
1320 break;
1321 }
1322
1323 cpumask_clear_cpu(smp_processor_id(), &xmon_batch_cpus);
1324
1325 return xmon_batch_next_cpu();
1326}
1327
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328static int cpu_cmd(void)
1329{
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001330 unsigned long cpu, first_cpu, last_cpu;
Naveen N. Raob8ee3e62021-06-01 13:18:01 +05301331
1332 cpu = skipbl();
1333 if (cpu == '#') {
1334 xmon_batch = skipbl();
1335 if (xmon_batch) {
1336 switch (xmon_batch) {
1337 case 'r':
1338 case 'S':
1339 case 't':
1340 cpumask_copy(&xmon_batch_cpus, &cpus_in_xmon);
1341 if (cpumask_weight(&xmon_batch_cpus) <= 1) {
1342 printf("There are no other cpus in xmon\n");
1343 break;
1344 }
1345 xmon_batch_start_cpu = -1;
1346 if (!xmon_batch_next_cpu())
1347 return 1;
1348 break;
1349 default:
1350 printf("c# only supports 'r', 'S' and 't' commands\n");
1351 }
1352 xmon_batch = 0;
1353 return 0;
1354 }
1355 }
1356 termch = cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
1358 if (!scanhex(&cpu)) {
1359 /* print cpus waiting or in xmon */
1360 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001361 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +00001362 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001363 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001364 if (cpu == last_cpu + 1) {
1365 last_cpu = cpu;
1366 } else {
1367 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001368 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001369 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001370 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 }
1373 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001374 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001375 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 printf("\n");
1377 return 0;
1378 }
1379 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001380 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001381 printf("cpu 0x%lx isn't in xmon\n", cpu);
Michael Ellerman7b087292018-05-02 23:07:26 +10001382#ifdef CONFIG_PPC64
1383 printf("backtrace of paca[0x%lx].saved_r1 (possibly stale):\n", cpu);
1384 xmon_show_stack(paca_ptrs[cpu]->saved_r1, 0, 0);
1385#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 return 0;
1387 }
Naveen N. Raob8ee3e62021-06-01 13:18:01 +05301388
1389 return xmon_switch_cpu(cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390}
Naveen N. Raob8ee3e62021-06-01 13:18:01 +05301391#else
1392static int cpu_cmd(void)
1393{
1394 return 0;
1395}
1396#endif /* CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
1398static unsigned short fcstab[256] = {
1399 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1400 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1401 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1402 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1403 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1404 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1405 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1406 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1407 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1408 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1409 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1410 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1411 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1412 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1413 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1414 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1415 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1416 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1417 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1418 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1419 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1420 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1421 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1422 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1423 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1424 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1425 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1426 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1427 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1428 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1429 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1430 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1431};
1432
1433#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1434
1435static void
1436csum(void)
1437{
1438 unsigned int i;
1439 unsigned short fcs;
1440 unsigned char v;
1441
1442 if (!scanhex(&adrs))
1443 return;
1444 if (!scanhex(&ncsum))
1445 return;
1446 fcs = 0xffff;
1447 for (i = 0; i < ncsum; ++i) {
1448 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001449 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 break;
1451 }
1452 fcs = FCS(fcs, v);
1453 }
1454 printf("%x\n", fcs);
1455}
1456
1457/*
1458 * Check if this is a suitable place to put a breakpoint.
1459 */
1460static long check_bp_loc(unsigned long addr)
1461{
Jordan Niethe94afd062020-05-06 13:40:31 +10001462 struct ppc_inst instr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463
1464 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001465 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 printf("Breakpoints may only be placed at kernel addresses\n");
1467 return 0;
1468 }
Jordan Niethe6c7a4f02020-05-06 13:40:38 +10001469 if (!mread_instr(addr, &instr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 printf("Can't read instruction at address %lx\n", addr);
1471 return 0;
1472 }
1473 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1474 printf("Breakpoints may not be placed on mtmsrd or rfid "
1475 "instructions\n");
1476 return 0;
1477 }
1478 return 1;
1479}
1480
Ravi Bangoria30df74d2020-05-14 16:47:41 +05301481static int find_free_data_bpt(void)
1482{
1483 int i;
1484
1485 for (i = 0; i < nr_wp_slots(); i++) {
1486 if (!dabr[i].enabled)
1487 return i;
1488 }
1489 printf("Couldn't find free breakpoint register\n");
1490 return -1;
1491}
1492
1493static void print_data_bpts(void)
1494{
1495 int i;
1496
1497 for (i = 0; i < nr_wp_slots(); i++) {
1498 if (!dabr[i].enabled)
1499 continue;
1500
1501 printf(" data "REG" [", dabr[i].address);
1502 if (dabr[i].enabled & 1)
1503 printf("r");
1504 if (dabr[i].enabled & 2)
1505 printf("w");
1506 printf("]\n");
1507 }
1508}
1509
Michael Ellermane3bc8042012-08-23 22:09:13 +00001510static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 "Breakpoint command usage:\n"
1512 "b show breakpoints\n"
1513 "b <addr> [cnt] set breakpoint at given instr addr\n"
1514 "bc clear all breakpoints\n"
1515 "bc <n/addr> clear breakpoint number n or at addr\n"
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301516 "bi <addr> [cnt] set hardware instr breakpoint (POWER8 only)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 "bd <addr> [cnt] set hardware data breakpoint\n"
1518 "";
1519
1520static void
1521bpt_cmds(void)
1522{
1523 int cmd;
1524 unsigned long a;
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001525 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 struct bpt *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
1528 cmd = inchar();
Christopher M. Riedl96664de2019-09-07 01:11:23 -05001529
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 switch (cmd) {
Nicholas Piggin09b6c112017-05-12 10:47:07 +10001531 static const char badaddr[] = "Only kernel addresses are permitted for breakpoints\n";
1532 int mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 case 'd': /* bd - hardware data breakpoint */
Christopher M. Riedl96664de2019-09-07 01:11:23 -05001534 if (xmon_is_ro) {
1535 printf(xmon_ro_msg);
1536 break;
1537 }
Michael Neuling9bc2bd52018-03-27 15:37:19 +11001538 if (!ppc_breakpoint_available()) {
1539 printf("Hardware data breakpoint not supported on this cpu\n");
1540 break;
1541 }
Ravi Bangoria30df74d2020-05-14 16:47:41 +05301542 i = find_free_data_bpt();
1543 if (i < 0)
Ravi Bangoria514db912020-05-14 16:47:40 +05301544 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 mode = 7;
1546 cmd = inchar();
1547 if (cmd == 'r')
1548 mode = 5;
1549 else if (cmd == 'w')
1550 mode = 6;
1551 else
1552 termch = cmd;
Ravi Bangoria30df74d2020-05-14 16:47:41 +05301553 dabr[i].address = 0;
1554 dabr[i].enabled = 0;
1555 if (scanhex(&dabr[i].address)) {
1556 if (!is_kernel_addr(dabr[i].address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 printf(badaddr);
1558 break;
1559 }
Ravi Bangoria30df74d2020-05-14 16:47:41 +05301560 dabr[i].address &= ~HW_BRK_TYPE_DABR;
1561 dabr[i].enabled = mode | BP_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 }
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301563
1564 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 break;
1566
1567 case 'i': /* bi - hardware instr breakpoint */
Christopher M. Riedl96664de2019-09-07 01:11:23 -05001568 if (xmon_is_ro) {
1569 printf(xmon_ro_msg);
1570 break;
1571 }
Anshuman Khandual1ad7d702014-11-28 10:06:42 +05301572 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 printf("Hardware instruction breakpoint "
1574 "not supported on this cpu\n");
1575 break;
1576 }
1577 if (iabr) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001578 iabr->enabled &= ~BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 iabr = NULL;
1580 }
1581 if (!scanhex(&a))
1582 break;
1583 if (!check_bp_loc(a))
1584 break;
1585 bp = new_breakpoint(a);
1586 if (bp != NULL) {
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001587 bp->enabled |= BP_CIABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 iabr = bp;
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301589 force_enable_xmon();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 }
1591 break;
1592
1593 case 'c':
1594 if (!scanhex(&a)) {
1595 /* clear all breakpoints */
1596 for (i = 0; i < NBPTS; ++i)
1597 bpts[i].enabled = 0;
1598 iabr = NULL;
Ravi Bangoria30df74d2020-05-14 16:47:41 +05301599 for (i = 0; i < nr_wp_slots(); i++)
1600 dabr[i].enabled = 0;
1601
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 printf("All breakpoints cleared\n");
1603 break;
1604 }
1605
1606 if (a <= NBPTS && a >= 1) {
1607 /* assume a breakpoint number */
1608 bp = &bpts[a-1]; /* bp nums are 1 based */
1609 } else {
1610 /* assume a breakpoint address */
1611 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001612 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001613 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 break;
1615 }
1616 }
1617
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001618 printf("Cleared breakpoint %tx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 xmon_print_symbol(bp->address, " ", ")\n");
1620 bp->enabled = 0;
1621 break;
1622
1623 default:
1624 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001625 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 if (cmd == '?') {
1627 printf(breakpoint_help_string);
1628 break;
1629 }
1630 termch = cmd;
Christopher M. Riedl96664de2019-09-07 01:11:23 -05001631
1632 if (xmon_is_ro || !scanhex(&a)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 /* print all breakpoints */
1634 printf(" type address\n");
Ravi Bangoria30df74d2020-05-14 16:47:41 +05301635 print_data_bpts();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1637 if (!bp->enabled)
1638 continue;
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001639 printf("%tx %s ", BP_NUM(bp),
Michael Ellermanabb90ee2014-12-01 16:54:13 +11001640 (bp->enabled & BP_CIABR) ? "inst": "trap");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 xmon_print_symbol(bp->address, " ", "\n");
1642 }
1643 break;
1644 }
1645
1646 if (!check_bp_loc(a))
1647 break;
1648 bp = new_breakpoint(a);
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301649 if (bp != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 bp->enabled |= BP_TRAP;
Vaibhav Jaine1368d02018-03-04 23:00:25 +05301651 force_enable_xmon();
1652 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 break;
1654 }
1655}
1656
1657/* Very cheap human name for vector lookup. */
1658static
1659const char *getvecname(unsigned long vec)
1660{
1661 char *ret;
1662
1663 switch (vec) {
1664 case 0x100: ret = "(System Reset)"; break;
1665 case 0x200: ret = "(Machine Check)"; break;
1666 case 0x300: ret = "(Data Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001667 case 0x380:
1668 if (radix_enabled())
1669 ret = "(Data Access Out of Range)";
1670 else
1671 ret = "(Data SLB Access)";
1672 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 case 0x400: ret = "(Instruction Access)"; break;
Michael Neuling8915bcd2017-03-16 14:04:40 +11001674 case 0x480:
1675 if (radix_enabled())
1676 ret = "(Instruction Access Out of Range)";
1677 else
1678 ret = "(Instruction SLB Access)";
1679 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 case 0x500: ret = "(Hardware Interrupt)"; break;
1681 case 0x600: ret = "(Alignment)"; break;
1682 case 0x700: ret = "(Program Check)"; break;
1683 case 0x800: ret = "(FPU Unavailable)"; break;
1684 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001685 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1686 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 case 0xc00: ret = "(System Call)"; break;
1688 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001689 case 0xe40: ret = "(Emulation Assist)"; break;
1690 case 0xe60: ret = "(HMI)"; break;
1691 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 case 0xf00: ret = "(Performance Monitor)"; break;
1693 case 0xf20: ret = "(Altivec Unavailable)"; break;
1694 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001695 case 0x1500: ret = "(Denormalisation)"; break;
1696 case 0x1700: ret = "(Altivec Assist)"; break;
Nicholas Piggin7fa95f92020-06-11 18:12:03 +10001697 case 0x3000: ret = "(System Call Vectored)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 default: ret = "";
1699 }
1700 return ret;
1701}
1702
1703static void get_function_bounds(unsigned long pc, unsigned long *startp,
1704 unsigned long *endp)
1705{
1706 unsigned long size, offset;
1707 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
1709 *startp = *endp = 0;
1710 if (pc == 0)
1711 return;
1712 if (setjmp(bus_error_jmp) == 0) {
1713 catch_memory_errors = 1;
1714 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001715 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 if (name != NULL) {
1717 *startp = pc - offset;
1718 *endp = pc - offset + size;
1719 }
1720 sync();
1721 }
1722 catch_memory_errors = 0;
1723}
1724
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001725#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1726#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1727
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728static void xmon_show_stack(unsigned long sp, unsigned long lr,
1729 unsigned long pc)
1730{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001731 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 unsigned long ip;
1733 unsigned long newsp;
1734 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 struct pt_regs regs;
1736
Michael Ellerman0104cd62012-10-09 04:20:36 +00001737 while (max_to_print--) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301738 if (!is_kernel_addr(sp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 if (sp != 0)
1740 printf("SP (%lx) is in userspace\n", sp);
1741 break;
1742 }
1743
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001744 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 || !mread(sp, &newsp, sizeof(unsigned long))) {
1746 printf("Couldn't read stack frame at %lx\n", sp);
1747 break;
1748 }
1749
1750 /*
1751 * For the first stack frame, try to work out if
1752 * LR and/or the saved LR value in the bottommost
1753 * stack frame are valid.
1754 */
1755 if ((pc | lr) != 0) {
1756 unsigned long fnstart, fnend;
1757 unsigned long nextip;
1758 int printip = 1;
1759
1760 get_function_bounds(pc, &fnstart, &fnend);
1761 nextip = 0;
1762 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001763 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 sizeof(unsigned long));
1765 if (lr == ip) {
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301766 if (!is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 || (fnstart <= lr && lr < fnend))
1768 printip = 0;
1769 } else if (lr == nextip) {
1770 printip = 0;
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301771 } else if (is_kernel_addr(lr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 && !(fnstart <= lr && lr < fnend)) {
1773 printf("[link register ] ");
1774 xmon_print_symbol(lr, " ", "\n");
1775 }
1776 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001777 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 xmon_print_symbol(ip, " ", " (unreliable)\n");
1779 }
1780 pc = lr = 0;
1781
1782 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001783 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 xmon_print_symbol(ip, " ", "\n");
1785 }
1786
1787 /* Look for "regshere" marker to see if this is
1788 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001789 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001790 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001791 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 != sizeof(regs)) {
1793 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001794 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 break;
1796 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001797 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 getvecname(TRAP(&regs)));
1799 pc = regs.nip;
1800 lr = regs.link;
1801 xmon_print_symbol(pc, " ", "\n");
1802 }
1803
1804 if (newsp == 0)
1805 break;
1806
1807 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001808 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809}
1810
1811static void backtrace(struct pt_regs *excp)
1812{
1813 unsigned long sp;
1814
1815 if (scanhex(&sp))
1816 xmon_show_stack(sp, 0, 0);
1817 else
1818 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1819 scannl();
1820}
1821
1822static void print_bug_trap(struct pt_regs *regs)
1823{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001824#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001825 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 unsigned long addr;
1827
1828 if (regs->msr & MSR_PR)
1829 return; /* not in kernel */
1830 addr = regs->nip; /* address of trap instruction */
Madhavan Srinivasane71ff892017-01-05 16:38:15 +05301831 if (!is_kernel_addr(addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 return;
1833 bug = find_bug(regs->nip);
1834 if (bug == NULL)
1835 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001836 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 return;
1838
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001839#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001840 printf("kernel BUG at %s:%u!\n",
Jordan Niethe1baa1f72020-12-01 11:52:03 +11001841 (char *)bug + bug->file_disp, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001842#else
Jordan Niethe1baa1f72020-12-01 11:52:03 +11001843 printf("kernel BUG at %px!\n", (void *)bug + bug->bug_addr_disp);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001844#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001845#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846}
1847
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001848static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849{
1850 unsigned long trap;
1851
1852#ifdef CONFIG_SMP
1853 printf("cpu 0x%x: ", smp_processor_id());
1854#endif /* CONFIG_SMP */
1855
1856 trap = TRAP(fp);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001857 printf("Vector: %lx %s at [%px]\n", fp->trap, getvecname(trap), fp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 printf(" pc: ");
1859 xmon_print_symbol(fp->nip, ": ", "\n");
1860
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001861 printf(" lr: ");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 xmon_print_symbol(fp->link, ": ", "\n");
1863
1864 printf(" sp: %lx\n", fp->gpr[1]);
1865 printf(" msr: %lx\n", fp->msr);
1866
Xiongwei Song7153d4b2021-04-14 19:00:33 +08001867 if (trap == INTERRUPT_DATA_STORAGE ||
1868 trap == INTERRUPT_DATA_SEGMENT ||
1869 trap == INTERRUPT_ALIGNMENT ||
1870 trap == INTERRUPT_MACHINE_CHECK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 printf(" dar: %lx\n", fp->dar);
Xiongwei Song7153d4b2021-04-14 19:00:33 +08001872 if (trap != INTERRUPT_DATA_SEGMENT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 printf(" dsisr: %lx\n", fp->dsisr);
1874 }
1875
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001876 printf(" current = 0x%px\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001877#ifdef CONFIG_PPC64
Nicholas Piggin3130a7b2018-05-10 11:04:24 +10001878 printf(" paca = 0x%px\t irqmask: 0x%02x\t irq_happened: 0x%02x\n",
Madhavan Srinivasan4e26bc42017-12-20 09:25:50 +05301879 local_paca, local_paca->irq_soft_mask, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001880#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 if (current) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02001882 printf(" pid = %d, comm = %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 current->pid, current->comm);
1884 }
1885
Xiongwei Song7153d4b2021-04-14 19:00:33 +08001886 if (trap == INTERRUPT_PROGRAM)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 print_bug_trap(fp);
Rashmica Guptaeb925d62015-11-25 13:46:25 +11001888
1889 printf(linux_banner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890}
1891
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001892static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001894 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 unsigned long base;
1896 struct pt_regs regs;
1897
1898 if (scanhex(&base)) {
1899 if (setjmp(bus_error_jmp) == 0) {
1900 catch_memory_errors = 1;
1901 sync();
1902 regs = *(struct pt_regs *)base;
1903 sync();
1904 __delay(200);
1905 } else {
1906 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001907 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 base);
1909 return;
1910 }
1911 catch_memory_errors = 0;
1912 fp = &regs;
1913 }
1914
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001915#ifdef CONFIG_PPC64
Nicholas Piggin8dc7f022021-03-16 20:42:04 +10001916#define R_PER_LINE 2
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001917#else
Nicholas Piggin8dc7f022021-03-16 20:42:04 +10001918#define R_PER_LINE 4
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001919#endif
Nicholas Piggin8dc7f022021-03-16 20:42:04 +10001920
1921 for (n = 0; n < 32; ++n) {
1922 printf("R%.2d = "REG"%s", n, fp->gpr[n],
1923 (n % R_PER_LINE) == R_PER_LINE - 1 ? "\n" : " ");
1924 }
1925
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 printf("pc = ");
1927 xmon_print_symbol(fp->nip, " ", "\n");
Nicholas Piggin912237e2020-05-07 22:13:31 +10001928 if (!trap_is_syscall(fp) && cpu_has_feature(CPU_FTR_CFAR)) {
Paul Mackerras48404f22011-05-01 19:48:20 +00001929 printf("cfar= ");
1930 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 printf("lr = ");
1933 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001934 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1935 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001937 trap = TRAP(fp);
Xiongwei Song7153d4b2021-04-14 19:00:33 +08001938 if (trap == INTERRUPT_DATA_STORAGE ||
1939 trap == INTERRUPT_DATA_SEGMENT ||
1940 trap == INTERRUPT_ALIGNMENT)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001941 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942}
1943
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001944static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945{
1946 int cmd;
1947 unsigned long nflush;
1948
1949 cmd = inchar();
1950 if (cmd != 'i')
1951 termch = cmd;
1952 scanhex((void *)&adrs);
1953 if (termch != '\n')
1954 termch = 0;
1955 nflush = 1;
1956 scanhex(&nflush);
1957 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1958 if (setjmp(bus_error_jmp) == 0) {
1959 catch_memory_errors = 1;
1960 sync();
1961
Balamuruhan S81a41322020-03-30 13:29:54 +05301962 if (cmd != 'i' || IS_ENABLED(CONFIG_PPC_BOOK3S_64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1964 cflush((void *) adrs);
1965 } else {
1966 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1967 cinval((void *) adrs);
1968 }
1969 sync();
1970 /* wait a little while to see if we get a machine check */
1971 __delay(200);
1972 }
1973 catch_memory_errors = 0;
1974}
1975
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001976extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1977extern void xmon_mtspr(int spr, unsigned long value);
1978
1979static int
1980read_spr(int n, unsigned long *vp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 unsigned long ret = -1UL;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001983 int ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
1985 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001986 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 sync();
1988
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001989 ret = xmon_mfspr(n, *vp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990
1991 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001992 *vp = ret;
1993 ok = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001995 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10001997 return ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998}
1999
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002000static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001write_spr(int n, unsigned long val)
2002{
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05002003 if (xmon_is_ro) {
2004 printf(xmon_ro_msg);
2005 return;
2006 }
2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 if (setjmp(bus_error_jmp) == 0) {
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10002009 catch_spr_faults = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 sync();
2011
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10002012 xmon_mtspr(n, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
2014 sync();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10002015 } else {
2016 printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10002018 catch_spr_faults = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019}
2020
Michael Ellerman18461932016-07-07 22:54:29 +10002021static void dump_206_sprs(void)
2022{
2023#ifdef CONFIG_PPC64
2024 if (!cpu_has_feature(CPU_FTR_ARCH_206))
2025 return;
2026
2027 /* Actually some of these pre-date 2.06, but whatevs */
2028
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002029 printf("srr0 = %.16lx srr1 = %.16lx dsisr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10002030 mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002031 printf("dscr = %.16lx ppr = %.16lx pir = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10002032 mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10002033 printf("amr = %.16lx uamor = %.16lx\n",
2034 mfspr(SPRN_AMR), mfspr(SPRN_UAMOR));
Michael Ellerman18461932016-07-07 22:54:29 +10002035
2036 if (!(mfmsr() & MSR_HV))
2037 return;
2038
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002039 printf("sdr1 = %.16lx hdar = %.16lx hdsisr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10002040 mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10002041 printf("hsrr0 = %.16lx hsrr1 = %.16lx hdec = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10002042 mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002043 printf("lpcr = %.16lx pcr = %.16lx lpidr = %.8lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10002044 mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
Balbir Singh64d66aa2017-08-30 21:43:34 +10002045 printf("hsprg0 = %.16lx hsprg1 = %.16lx amor = %.16lx\n",
2046 mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1), mfspr(SPRN_AMOR));
Balbir Singhc47a9402017-08-29 17:22:36 +10002047 printf("dabr = %.16lx dabrx = %.16lx\n",
Michael Ellerman18461932016-07-07 22:54:29 +10002048 mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
2049#endif
2050}
2051
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002052static void dump_207_sprs(void)
2053{
2054#ifdef CONFIG_PPC64
2055 unsigned long msr;
2056
2057 if (!cpu_has_feature(CPU_FTR_ARCH_207S))
2058 return;
2059
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002060 printf("dpdes = %.16lx tir = %.16lx cir = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002061 mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
2062
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002063 printf("fscr = %.16lx tar = %.16lx pspb = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002064 mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
2065
2066 msr = mfmsr();
2067 if (msr & MSR_TM) {
2068 /* Only if TM has been enabled in the kernel */
Balbir Singhc47a9402017-08-29 17:22:36 +10002069 printf("tfhar = %.16lx tfiar = %.16lx texasr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002070 mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
2071 mfspr(SPRN_TEXASR));
2072 }
2073
Balbir Singhc47a9402017-08-29 17:22:36 +10002074 printf("mmcr0 = %.16lx mmcr1 = %.16lx mmcr2 = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002075 mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002076 printf("pmc1 = %.8lx pmc2 = %.8lx pmc3 = %.8lx pmc4 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002077 mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
2078 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002079 printf("mmcra = %.16lx siar = %.16lx pmc5 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002080 mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002081 printf("sdar = %.16lx sier = %.16lx pmc6 = %.8lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002082 mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
Balbir Singhc47a9402017-08-29 17:22:36 +10002083 printf("ebbhr = %.16lx ebbrr = %.16lx bescr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002084 mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
Balbir Singh64d66aa2017-08-30 21:43:34 +10002085 printf("iamr = %.16lx\n", mfspr(SPRN_IAMR));
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002086
2087 if (!(msr & MSR_HV))
2088 return;
2089
Balbir Singhc47a9402017-08-29 17:22:36 +10002090 printf("hfscr = %.16lx dhdes = %.16lx rpr = %.16lx\n",
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002091 mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
Ravi Bangoria30df74d2020-05-14 16:47:41 +05302092 printf("dawr0 = %.16lx dawrx0 = %.16lx\n",
2093 mfspr(SPRN_DAWR0), mfspr(SPRN_DAWRX0));
2094 if (nr_wp_slots() > 1) {
2095 printf("dawr1 = %.16lx dawrx1 = %.16lx\n",
2096 mfspr(SPRN_DAWR1), mfspr(SPRN_DAWRX1));
2097 }
2098 printf("ciabr = %.16lx\n", mfspr(SPRN_CIABR));
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002099#endif
2100}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
Balbir Singhd1e1b352017-08-30 21:45:09 +10002102static void dump_300_sprs(void)
2103{
2104#ifdef CONFIG_PPC64
2105 bool hv = mfmsr() & MSR_HV;
2106
2107 if (!cpu_has_feature(CPU_FTR_ARCH_300))
2108 return;
2109
2110 printf("pidr = %.16lx tidr = %.16lx\n",
2111 mfspr(SPRN_PID), mfspr(SPRN_TIDR));
Sukadev Bhattiproluc2a20712020-01-06 13:50:02 -06002112 printf("psscr = %.16lx\n",
2113 hv ? mfspr(SPRN_PSSCR) : mfspr(SPRN_PSSCR_PR));
Balbir Singhd1e1b352017-08-30 21:45:09 +10002114
2115 if (!hv)
2116 return;
2117
Sukadev Bhattiproluc2a20712020-01-06 13:50:02 -06002118 printf("ptcr = %.16lx asdr = %.16lx\n",
2119 mfspr(SPRN_PTCR), mfspr(SPRN_ASDR));
Balbir Singhd1e1b352017-08-30 21:45:09 +10002120#endif
2121}
2122
Madhavan Srinivasan1979ae82020-07-17 10:38:18 -04002123static void dump_310_sprs(void)
2124{
2125#ifdef CONFIG_PPC64
2126 if (!cpu_has_feature(CPU_FTR_ARCH_31))
2127 return;
2128
2129 printf("mmcr3 = %.16lx, sier2 = %.16lx, sier3 = %.16lx\n",
2130 mfspr(SPRN_MMCR3), mfspr(SPRN_SIER2), mfspr(SPRN_SIER3));
2131
2132#endif
2133}
2134
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10002135static void dump_one_spr(int spr, bool show_unimplemented)
2136{
2137 unsigned long val;
2138
2139 val = 0xdeadbeef;
2140 if (!read_spr(spr, &val)) {
2141 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
2142 return;
2143 }
2144
2145 if (val == 0xdeadbeef) {
2146 /* Looks like read was a nop, confirm */
2147 val = 0x0badcafe;
2148 if (!read_spr(spr, &val)) {
2149 printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
2150 return;
2151 }
2152
2153 if (val == 0x0badcafe) {
2154 if (show_unimplemented)
2155 printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
2156 return;
2157 }
2158 }
2159
2160 printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
2161}
2162
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002163static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164{
Michael Ellerman13629da2016-07-07 22:54:27 +10002165 static unsigned long regno;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 int cmd;
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10002167 int spr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
2169 cmd = skipbl();
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10002170
2171 switch (cmd) {
2172 case '\n': {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002173 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 asm("mr %0,1" : "=r" (sp) :);
2175 asm("mr %0,2" : "=r" (toc) :);
2176
Michael Ellerman56346ad2016-07-07 22:54:28 +10002177 printf("msr = "REG" sprg0 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002178 mfmsr(), mfspr(SPRN_SPRG0));
Michael Ellerman56346ad2016-07-07 22:54:28 +10002179 printf("pvr = "REG" sprg1 = "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00002180 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Michael Ellerman56346ad2016-07-07 22:54:28 +10002181 printf("dec = "REG" sprg2 = "REG"\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002182 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
Michael Ellerman56346ad2016-07-07 22:54:28 +10002183 printf("sp = "REG" sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
2184 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
2185
Michael Ellerman18461932016-07-07 22:54:29 +10002186 dump_206_sprs();
Michael Ellermane0ddf7a2016-07-07 22:54:30 +10002187 dump_207_sprs();
Balbir Singhd1e1b352017-08-30 21:45:09 +10002188 dump_300_sprs();
Madhavan Srinivasan1979ae82020-07-17 10:38:18 -04002189 dump_310_sprs();
Michael Ellerman18461932016-07-07 22:54:29 +10002190
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 return;
2192 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10002193 case 'w': {
2194 unsigned long val;
2195 scanhex(&regno);
2196 val = 0;
2197 read_spr(regno, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 scanhex(&val);
2199 write_spr(regno, val);
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10002200 dump_one_spr(regno, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 }
Paul Mackerras31cdd0c2016-04-13 21:31:24 +10002203 case 'r':
2204 scanhex(&regno);
2205 dump_one_spr(regno, true);
2206 break;
2207 case 'a':
2208 /* dump ALL SPRs */
2209 for (spr = 1; spr < 1024; ++spr)
2210 dump_one_spr(spr, false);
2211 break;
2212 }
2213
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 scannl();
2215}
2216
2217/*
2218 * Stuff for reading and writing memory safely
2219 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002220static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221mread(unsigned long adrs, void *buf, int size)
2222{
2223 volatile int n;
2224 char *p, *q;
2225
2226 n = 0;
2227 if (setjmp(bus_error_jmp) == 0) {
2228 catch_memory_errors = 1;
2229 sync();
2230 p = (char *)adrs;
2231 q = (char *)buf;
2232 switch (size) {
2233 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002234 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 break;
2236 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002237 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 break;
2239 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002240 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 break;
2242 default:
2243 for( ; n < size; ++n) {
2244 *q++ = *p++;
2245 sync();
2246 }
2247 }
2248 sync();
2249 /* wait a little while to see if we get a machine check */
2250 __delay(200);
2251 n = size;
2252 }
2253 catch_memory_errors = 0;
2254 return n;
2255}
2256
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002257static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258mwrite(unsigned long adrs, void *buf, int size)
2259{
2260 volatile int n;
2261 char *p, *q;
2262
2263 n = 0;
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05002264
2265 if (xmon_is_ro) {
2266 printf(xmon_ro_msg);
2267 return n;
2268 }
2269
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 if (setjmp(bus_error_jmp) == 0) {
2271 catch_memory_errors = 1;
2272 sync();
2273 p = (char *) adrs;
2274 q = (char *) buf;
2275 switch (size) {
2276 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002277 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 break;
2279 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002280 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 break;
2282 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002283 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 break;
2285 default:
2286 for ( ; n < size; ++n) {
2287 *p++ = *q++;
2288 sync();
2289 }
2290 }
2291 sync();
2292 /* wait a little while to see if we get a machine check */
2293 __delay(200);
2294 n = size;
2295 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10002296 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 }
2298 catch_memory_errors = 0;
2299 return n;
2300}
2301
Jordan Niethe6c7a4f02020-05-06 13:40:38 +10002302static int
2303mread_instr(unsigned long adrs, struct ppc_inst *instr)
2304{
2305 volatile int n;
2306
2307 n = 0;
2308 if (setjmp(bus_error_jmp) == 0) {
2309 catch_memory_errors = 1;
2310 sync();
Christophe Leroy69d4d6e2021-05-20 13:50:45 +00002311 *instr = ppc_inst_read((u32 *)adrs);
Jordan Niethe6c7a4f02020-05-06 13:40:38 +10002312 sync();
2313 /* wait a little while to see if we get a machine check */
2314 __delay(200);
2315 n = ppc_inst_len(*instr);
2316 }
2317 catch_memory_errors = 0;
2318 return n;
2319}
2320
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002322static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323static char *fault_chars[] = { "--", "**", "##" };
2324
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002325static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002327 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 switch (TRAP(regs)) {
2329 case 0x200:
2330 fault_type = 0;
2331 break;
2332 case 0x300:
2333 case 0x380:
2334 fault_type = 1;
2335 break;
2336 default:
2337 fault_type = 2;
2338 }
2339
2340 longjmp(bus_error_jmp, 1);
2341
2342 return 0;
2343}
2344
2345#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
2346
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002347static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348byterev(unsigned char *val, int size)
2349{
2350 int t;
2351
2352 switch (size) {
2353 case 2:
2354 SWAP(val[0], val[1], t);
2355 break;
2356 case 4:
2357 SWAP(val[0], val[3], t);
2358 SWAP(val[1], val[2], t);
2359 break;
2360 case 8: /* is there really any use for this? */
2361 SWAP(val[0], val[7], t);
2362 SWAP(val[1], val[6], t);
2363 SWAP(val[2], val[5], t);
2364 SWAP(val[3], val[4], t);
2365 break;
2366 }
2367}
2368
2369static int brev;
2370static int mnoread;
2371
Michael Ellermane3bc8042012-08-23 22:09:13 +00002372static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 "Memory examine command usage:\n"
2374 "m [addr] [flags] examine/change memory\n"
2375 " addr is optional. will start where left off.\n"
2376 " flags may include chars from this set:\n"
2377 " b modify by bytes (default)\n"
2378 " w modify by words (2 byte)\n"
2379 " l modify by longs (4 byte)\n"
2380 " d modify by doubleword (8 byte)\n"
2381 " r toggle reverse byte order mode\n"
2382 " n do not read memory (for i/o spaces)\n"
2383 " . ok to read (default)\n"
2384 "NOTE: flags are saved as defaults\n"
2385 "";
2386
Michael Ellermane3bc8042012-08-23 22:09:13 +00002387static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 "Memory examine subcommands:\n"
2389 " hexval write this val to current location\n"
2390 " 'string' write chars from string to this location\n"
2391 " ' increment address\n"
2392 " ^ decrement address\n"
2393 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
2394 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
2395 " ` clear no-read flag\n"
2396 " ; stay at this addr\n"
2397 " v change to byte mode\n"
2398 " w change to word (2 byte) mode\n"
2399 " l change to long (4 byte) mode\n"
2400 " u change to doubleword (8 byte) mode\n"
2401 " m addr change current addr\n"
2402 " n toggle no-read flag\n"
2403 " r toggle byte reverse flag\n"
2404 " < count back up count bytes\n"
2405 " > count skip forward count bytes\n"
2406 " x exit this mode\n"
2407 "";
2408
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002409static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410memex(void)
2411{
2412 int cmd, inc, i, nslash;
2413 unsigned long n;
2414 unsigned char val[16];
2415
2416 scanhex((void *)&adrs);
2417 cmd = skipbl();
2418 if (cmd == '?') {
2419 printf(memex_help_string);
2420 return;
2421 } else {
2422 termch = cmd;
2423 }
2424 last_cmd = "m\n";
2425 while ((cmd = skipbl()) != '\n') {
2426 switch( cmd ){
2427 case 'b': size = 1; break;
2428 case 'w': size = 2; break;
2429 case 'l': size = 4; break;
2430 case 'd': size = 8; break;
2431 case 'r': brev = !brev; break;
2432 case 'n': mnoread = 1; break;
2433 case '.': mnoread = 0; break;
2434 }
2435 }
2436 if( size <= 0 )
2437 size = 1;
2438 else if( size > 8 )
2439 size = 8;
2440 for(;;){
2441 if (!mnoread)
2442 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002443 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 if (!mnoread) {
2445 if (brev)
2446 byterev(val, size);
2447 putchar(' ');
2448 for (i = 0; i < n; ++i)
2449 printf("%.2x", val[i]);
2450 for (; i < size; ++i)
2451 printf("%s", fault_chars[fault_type]);
2452 }
2453 putchar(' ');
2454 inc = size;
2455 nslash = 0;
2456 for(;;){
2457 if( scanhex(&n) ){
2458 for (i = 0; i < size; ++i)
2459 val[i] = n >> (i * 8);
2460 if (!brev)
2461 byterev(val, size);
2462 mwrite(adrs, val, size);
2463 inc = size;
2464 }
2465 cmd = skipbl();
2466 if (cmd == '\n')
2467 break;
2468 inc = 0;
2469 switch (cmd) {
2470 case '\'':
2471 for(;;){
2472 n = inchar();
2473 if( n == '\\' )
2474 n = bsesc();
2475 else if( n == '\'' )
2476 break;
2477 for (i = 0; i < size; ++i)
2478 val[i] = n >> (i * 8);
2479 if (!brev)
2480 byterev(val, size);
2481 mwrite(adrs, val, size);
2482 adrs += size;
2483 }
2484 adrs -= size;
2485 inc = size;
2486 break;
2487 case ',':
2488 adrs += size;
2489 break;
2490 case '.':
2491 mnoread = 0;
2492 break;
2493 case ';':
2494 break;
2495 case 'x':
2496 case EOF:
2497 scannl();
2498 return;
2499 case 'b':
2500 case 'v':
2501 size = 1;
2502 break;
2503 case 'w':
2504 size = 2;
2505 break;
2506 case 'l':
2507 size = 4;
2508 break;
2509 case 'u':
2510 size = 8;
2511 break;
2512 case '^':
2513 adrs -= size;
2514 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 case '/':
2516 if (nslash > 0)
2517 adrs -= 1 << nslash;
2518 else
2519 nslash = 0;
2520 nslash += 4;
2521 adrs += 1 << nslash;
2522 break;
2523 case '\\':
2524 if (nslash < 0)
2525 adrs += 1 << -nslash;
2526 else
2527 nslash = 0;
2528 nslash -= 4;
2529 adrs -= 1 << -nslash;
2530 break;
2531 case 'm':
2532 scanhex((void *)&adrs);
2533 break;
2534 case 'n':
2535 mnoread = 1;
2536 break;
2537 case 'r':
2538 brev = !brev;
2539 break;
2540 case '<':
2541 n = size;
2542 scanhex(&n);
2543 adrs -= n;
2544 break;
2545 case '>':
2546 n = size;
2547 scanhex(&n);
2548 adrs += n;
2549 break;
2550 case '?':
2551 printf(memex_subcmd_help_string);
2552 break;
2553 }
2554 }
2555 adrs += inc;
2556 }
2557}
2558
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002559static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560bsesc(void)
2561{
2562 int c;
2563
2564 c = inchar();
2565 switch( c ){
2566 case 'n': c = '\n'; break;
2567 case 'r': c = '\r'; break;
2568 case 'b': c = '\b'; break;
2569 case 't': c = '\t'; break;
2570 }
2571 return c;
2572}
2573
Olaf Hering7e5b5932006-03-08 20:40:28 +01002574static void xmon_rawdump (unsigned long adrs, long ndump)
2575{
2576 long n, m, r, nr;
2577 unsigned char temp[16];
2578
2579 for (n = ndump; n > 0;) {
2580 r = n < 16? n: 16;
2581 nr = mread(adrs, temp, r);
2582 adrs += nr;
2583 for (m = 0; m < r; ++m) {
2584 if (m < nr)
2585 printf("%.2x", temp[m]);
2586 else
2587 printf("%s", fault_chars[fault_type]);
2588 }
2589 n -= r;
2590 if (nr < r)
2591 break;
2592 }
2593 printf("\n");
2594}
2595
Breno Leitao4125d012017-08-02 17:14:05 -03002596static void dump_tracing(void)
2597{
2598 int c;
2599
2600 c = inchar();
2601 if (c == 'c')
2602 ftrace_dump(DUMP_ORIG);
2603 else
2604 ftrace_dump(DUMP_ALL);
Breno Leitao4125d012017-08-02 17:14:05 -03002605}
2606
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002607#ifdef CONFIG_PPC64
2608static void dump_one_paca(int cpu)
2609{
2610 struct paca_struct *p;
Michael Ellerman4e003742017-10-19 15:08:43 +11002611#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellermanad987fc2015-10-14 16:58:36 +11002612 int i = 0;
2613#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002614
2615 if (setjmp(bus_error_jmp) != 0) {
2616 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2617 return;
2618 }
2619
2620 catch_memory_errors = 1;
2621 sync();
2622
Nicholas Piggind2e60072018-02-14 01:08:12 +10002623 p = paca_ptrs[cpu];
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002624
Michael Ellermand8104182017-12-06 23:23:28 +11002625 printf("paca for cpu 0x%x @ %px:\n", cpu, p);
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002626
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002627 printf(" %-*s = %s\n", 25, "possible", cpu_possible(cpu) ? "yes" : "no");
2628 printf(" %-*s = %s\n", 25, "present", cpu_present(cpu) ? "yes" : "no");
2629 printf(" %-*s = %s\n", 25, "online", cpu_online(cpu) ? "yes" : "no");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002630
Michael Ellerman66716832018-05-21 21:06:19 +10002631#define DUMP(paca, name, format) \
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002632 printf(" %-*s = "format"\t(0x%lx)\n", 25, #name, 18, paca->name, \
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002633 offsetof(struct paca_struct, name));
2634
Michael Ellerman66716832018-05-21 21:06:19 +10002635 DUMP(p, lock_token, "%#-*x");
2636 DUMP(p, paca_index, "%#-*x");
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002637 DUMP(p, kernel_toc, "%#-*llx");
2638 DUMP(p, kernelbase, "%#-*llx");
2639 DUMP(p, kernel_msr, "%#-*llx");
Michael Ellerman66716832018-05-21 21:06:19 +10002640 DUMP(p, emergency_sp, "%-*px");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302641#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman66716832018-05-21 21:06:19 +10002642 DUMP(p, nmi_emergency_sp, "%-*px");
2643 DUMP(p, mc_emergency_sp, "%-*px");
2644 DUMP(p, in_nmi, "%#-*x");
2645 DUMP(p, in_mce, "%#-*x");
2646 DUMP(p, hmi_event_available, "%#-*x");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302647#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002648 DUMP(p, data_offset, "%#-*llx");
Michael Ellerman66716832018-05-21 21:06:19 +10002649 DUMP(p, hw_cpu_id, "%#-*x");
2650 DUMP(p, cpu_start, "%#-*x");
2651 DUMP(p, kexec_state, "%#-*x");
Michael Ellerman4e003742017-10-19 15:08:43 +11002652#ifdef CONFIG_PPC_BOOK3S_64
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002653 if (!early_radix_enabled()) {
2654 for (i = 0; i < SLB_NUM_BOLTED; i++) {
2655 u64 esid, vsid;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002656
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002657 if (!p->slb_shadow_ptr)
2658 continue;
Michael Ellermanad987fc2015-10-14 16:58:36 +11002659
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002660 esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2661 vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
Michael Ellermanad987fc2015-10-14 16:58:36 +11002662
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002663 if (esid || vsid) {
2664 printf(" %-*s[%d] = 0x%016llx 0x%016llx\n",
2665 22, "slb_shadow", i, esid, vsid);
2666 }
Michael Ellermanad987fc2015-10-14 16:58:36 +11002667 }
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002668 DUMP(p, vmalloc_sllp, "%#-*x");
Nicholas Piggin126b11b2018-09-15 01:30:53 +10002669 DUMP(p, stab_rr, "%#-*x");
2670 DUMP(p, slb_used_bitmap, "%#-*x");
2671 DUMP(p, slb_kern_bitmap, "%#-*x");
Nicholas Piggin82d8f4c2018-09-15 01:30:50 +10002672
Nicholas Piggine83cbf72018-09-15 01:30:54 +10002673 if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) {
2674 DUMP(p, slb_cache_ptr, "%#-*x");
2675 for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2676 printf(" %-*s[%d] = 0x%016x\n",
2677 22, "slb_cache", i, p->slb_cache[i]);
2678 }
Nicholas Piggin82d8f4c2018-09-15 01:30:50 +10002679 }
Michael Ellerman274920a2018-01-10 23:49:12 +11002680
Michael Ellerman66716832018-05-21 21:06:19 +10002681 DUMP(p, rfi_flush_fallback_area, "%-*px");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002682#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002683 DUMP(p, dscr_default, "%#-*llx");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002684#ifdef CONFIG_PPC_BOOK3E
Michael Ellerman66716832018-05-21 21:06:19 +10002685 DUMP(p, pgd, "%-*px");
2686 DUMP(p, kernel_pgd, "%-*px");
2687 DUMP(p, tcd_ptr, "%-*px");
2688 DUMP(p, mc_kstack, "%-*px");
2689 DUMP(p, crit_kstack, "%-*px");
2690 DUMP(p, dbg_kstack, "%-*px");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002691#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002692 DUMP(p, __current, "%-*px");
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002693 DUMP(p, kstack, "%#-*llx");
Michael Ellerman9ce53e22018-05-21 21:28:34 +10002694 printf(" %-*s = 0x%016llx\n", 25, "kstack_base", p->kstack & ~(THREAD_SIZE - 1));
Michael Ellerman50530f52018-10-12 13:58:52 +11002695#ifdef CONFIG_STACKPROTECTOR
2696 DUMP(p, canary, "%#-*lx");
2697#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002698 DUMP(p, saved_r1, "%#-*llx");
Nicholas Piggin0a882e22019-06-28 16:33:18 +10002699#ifdef CONFIG_PPC_BOOK3E
Michael Ellerman66716832018-05-21 21:06:19 +10002700 DUMP(p, trap_save, "%#-*x");
Nicholas Piggin0a882e22019-06-28 16:33:18 +10002701#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002702 DUMP(p, irq_soft_mask, "%#-*x");
2703 DUMP(p, irq_happened, "%#-*x");
Will Deacon420af152019-02-22 14:45:42 +00002704#ifdef CONFIG_MMIOWB
2705 DUMP(p, mmiowb_state.nesting_count, "%#-*x");
2706 DUMP(p, mmiowb_state.mmiowb_pending, "%#-*x");
2707#endif
Michael Ellerman66716832018-05-21 21:06:19 +10002708 DUMP(p, irq_work_pending, "%#-*x");
Michael Ellerman66716832018-05-21 21:06:19 +10002709 DUMP(p, sprg_vdso, "%#-*llx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002710
Michael Ellermanad987fc2015-10-14 16:58:36 +11002711#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
Michael Ellerman66716832018-05-21 21:06:19 +10002712 DUMP(p, tm_scratch, "%#-*llx");
Michael Ellermanad987fc2015-10-14 16:58:36 +11002713#endif
2714
2715#ifdef CONFIG_PPC_POWERNV
Nicholas Piggin10d91612019-04-13 00:30:52 +10002716 DUMP(p, idle_state, "%#-*lx");
2717 if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) {
2718 DUMP(p, thread_idle_state, "%#-*x");
2719 DUMP(p, subcore_sibling_mask, "%#-*x");
2720 } else {
2721#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
2722 DUMP(p, requested_psscr, "%#-*llx");
2723 DUMP(p, dont_stop.counter, "%#-*x");
2724#endif
2725 }
Michael Ellermanad987fc2015-10-14 16:58:36 +11002726#endif
2727
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002728 DUMP(p, accounting.utime, "%#-*lx");
2729 DUMP(p, accounting.stime, "%#-*lx");
Christophe Leroyabcff862018-08-02 07:53:59 +00002730#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002731 DUMP(p, accounting.utime_scaled, "%#-*lx");
Christophe Leroyabcff862018-08-02 07:53:59 +00002732#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002733 DUMP(p, accounting.starttime, "%#-*lx");
2734 DUMP(p, accounting.starttime_user, "%#-*lx");
Christophe Leroyabcff862018-08-02 07:53:59 +00002735#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002736 DUMP(p, accounting.startspurr, "%#-*lx");
2737 DUMP(p, accounting.utime_sspurr, "%#-*lx");
Christophe Leroyabcff862018-08-02 07:53:59 +00002738#endif
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002739 DUMP(p, accounting.steal_time, "%#-*lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002740#undef DUMP
2741
2742 catch_memory_errors = 0;
2743 sync();
2744}
2745
2746static void dump_all_pacas(void)
2747{
2748 int cpu;
2749
2750 if (num_possible_cpus() == 0) {
2751 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2752 return;
2753 }
2754
2755 for_each_possible_cpu(cpu)
2756 dump_one_paca(cpu);
2757}
2758
2759static void dump_pacas(void)
2760{
2761 unsigned long num;
2762 int c;
2763
2764 c = inchar();
2765 if (c == 'a') {
2766 dump_all_pacas();
2767 return;
2768 }
2769
2770 termch = c; /* Put c back, it wasn't 'a' */
2771
2772 if (scanhex(&num))
2773 dump_one_paca(num);
2774 else
2775 dump_one_paca(xmon_owner);
2776}
2777#endif
2778
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002779#ifdef CONFIG_PPC_POWERNV
2780static void dump_one_xive(int cpu)
2781{
2782 unsigned int hwid = get_hard_smp_processor_id(cpu);
Cédric Le Goaterc3e0dbd2019-08-14 17:47:52 +02002783 bool hv = cpu_has_feature(CPU_FTR_HVMODE);
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002784
Cédric Le Goaterc3e0dbd2019-08-14 17:47:52 +02002785 if (hv) {
2786 opal_xive_dump(XIVE_DUMP_TM_HYP, hwid);
2787 opal_xive_dump(XIVE_DUMP_TM_POOL, hwid);
2788 opal_xive_dump(XIVE_DUMP_TM_OS, hwid);
2789 opal_xive_dump(XIVE_DUMP_TM_USER, hwid);
2790 opal_xive_dump(XIVE_DUMP_VP, hwid);
2791 opal_xive_dump(XIVE_DUMP_EMU_STATE, hwid);
2792 }
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002793
2794 if (setjmp(bus_error_jmp) != 0) {
2795 catch_memory_errors = 0;
2796 printf("*** Error dumping xive on cpu %d\n", cpu);
2797 return;
2798 }
2799
2800 catch_memory_errors = 1;
2801 sync();
2802 xmon_xive_do_dump(cpu);
2803 sync();
2804 __delay(200);
2805 catch_memory_errors = 0;
2806}
2807
2808static void dump_all_xives(void)
2809{
2810 int cpu;
2811
2812 if (num_possible_cpus() == 0) {
2813 printf("No possible cpus, use 'dx #' to dump individual cpus\n");
2814 return;
2815 }
2816
2817 for_each_possible_cpu(cpu)
2818 dump_one_xive(cpu);
2819}
2820
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002821static void dump_xives(void)
2822{
2823 unsigned long num;
2824 int c;
2825
Breno Leitao402e1722017-10-17 16:20:18 -02002826 if (!xive_enabled()) {
2827 printf("Xive disabled on this system\n");
2828 return;
2829 }
2830
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002831 c = inchar();
2832 if (c == 'a') {
2833 dump_all_xives();
2834 return;
2835 } else if (c == 'i') {
2836 if (scanhex(&num))
Cédric Le Goater6bf66eb2021-03-31 16:45:11 +02002837 xmon_xive_get_irq_config(num, NULL);
Cédric Le Goater39f14e72019-08-14 17:47:54 +02002838 else
Cédric Le Goater6bf66eb2021-03-31 16:45:11 +02002839 xmon_xive_get_irq_all();
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002840 return;
2841 }
2842
2843 termch = c; /* Put c back, it wasn't 'a' */
2844
2845 if (scanhex(&num))
2846 dump_one_xive(num);
2847 else
2848 dump_one_xive(xmon_owner);
2849}
2850#endif /* CONFIG_PPC_POWERNV */
2851
Douglas Miller5e48dc02017-02-07 07:40:44 -06002852static void dump_by_size(unsigned long addr, long count, int size)
2853{
2854 unsigned char temp[16];
2855 int i, j;
2856 u64 val;
2857
2858 count = ALIGN(count, 16);
2859
2860 for (i = 0; i < count; i += 16, addr += 16) {
2861 printf(REG, addr);
2862
2863 if (mread(addr, temp, 16) != 16) {
2864 printf("\nFaulted reading %d bytes from 0x"REG"\n", 16, addr);
2865 return;
2866 }
2867
2868 for (j = 0; j < 16; j += size) {
2869 putchar(' ');
2870 switch (size) {
2871 case 1: val = temp[j]; break;
2872 case 2: val = *(u16 *)&temp[j]; break;
2873 case 4: val = *(u32 *)&temp[j]; break;
2874 case 8: val = *(u64 *)&temp[j]; break;
2875 default: val = 0;
2876 }
2877
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02002878 printf("%0*llx", size * 2, val);
Douglas Miller5e48dc02017-02-07 07:40:44 -06002879 }
Douglas Miller8ec26c22017-02-27 08:28:14 -06002880 printf(" |");
2881 for (j = 0; j < 16; ++j) {
2882 val = temp[j];
2883 putchar(' ' <= val && val <= '~' ? val : '.');
2884 }
2885 printf("|\n");
Douglas Miller5e48dc02017-02-07 07:40:44 -06002886 }
2887}
2888
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002889static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890dump(void)
2891{
Douglas Miller5e48dc02017-02-07 07:40:44 -06002892 static char last[] = { "d?\n" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 int c;
2894
2895 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002896
2897#ifdef CONFIG_PPC64
2898 if (c == 'p') {
Sam bobroff958b7c82015-10-08 11:50:23 +11002899 xmon_start_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002900 dump_pacas();
Sam bobroff958b7c82015-10-08 11:50:23 +11002901 xmon_end_pagination();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002902 return;
2903 }
2904#endif
Benjamin Herrenschmidt243e2512017-04-05 17:54:50 +10002905#ifdef CONFIG_PPC_POWERNV
2906 if (c == 'x') {
2907 xmon_start_pagination();
2908 dump_xives();
2909 xmon_end_pagination();
2910 return;
2911 }
2912#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002913
Breno Leitao4125d012017-08-02 17:14:05 -03002914 if (c == 't') {
2915 dump_tracing();
2916 return;
2917 }
2918
Douglas Miller5e48dc02017-02-07 07:40:44 -06002919 if (c == '\n')
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 termch = c;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002921
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 scanhex((void *)&adrs);
2923 if (termch != '\n')
2924 termch = 0;
2925 if (c == 'i') {
2926 scanhex(&nidump);
2927 if (nidump == 0)
2928 nidump = 16;
Michael Ellermand64c7db2020-02-19 22:00:07 +11002929 else if (nidump > MAX_IDUMP)
2930 nidump = MAX_IDUMP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 adrs += ppc_inst_dump(adrs, nidump, 1);
2932 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002933 } else if (c == 'l') {
2934 dump_log_buf();
Andrew Donnellanfde93a02016-02-09 18:17:49 +11002935 } else if (c == 'o') {
2936 dump_opal_msglog();
Balbir Singh80eff6c2017-10-30 22:01:12 +11002937 } else if (c == 'v') {
2938 /* dump virtual to physical translation */
2939 show_pte(adrs);
Olaf Hering7e5b5932006-03-08 20:40:28 +01002940 } else if (c == 'r') {
2941 scanhex(&ndump);
2942 if (ndump == 0)
2943 ndump = 64;
2944 xmon_rawdump(adrs, ndump);
2945 adrs += ndump;
2946 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 } else {
2948 scanhex(&ndump);
2949 if (ndump == 0)
2950 ndump = 64;
2951 else if (ndump > MAX_DUMP)
2952 ndump = MAX_DUMP;
Douglas Miller5e48dc02017-02-07 07:40:44 -06002953
2954 switch (c) {
2955 case '8':
2956 case '4':
2957 case '2':
2958 case '1':
2959 ndump = ALIGN(ndump, 16);
2960 dump_by_size(adrs, ndump, c - '0');
2961 last[1] = c;
2962 last_cmd = last;
2963 break;
2964 default:
2965 prdump(adrs, ndump);
2966 last_cmd = "d\n";
2967 }
2968
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 adrs += ndump;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 }
2971}
2972
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002973static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974prdump(unsigned long adrs, long ndump)
2975{
2976 long n, m, c, r, nr;
2977 unsigned char temp[16];
2978
2979 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002980 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 putchar(' ');
2982 r = n < 16? n: 16;
2983 nr = mread(adrs, temp, r);
2984 adrs += nr;
2985 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002986 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002987 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 if (m < nr)
2989 printf("%.2x", temp[m]);
2990 else
2991 printf("%s", fault_chars[fault_type]);
2992 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002993 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002994 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002995 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002997 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 printf(" |");
2999 for (m = 0; m < r; ++m) {
3000 if (m < nr) {
3001 c = temp[m];
3002 putchar(' ' <= c && c <= '~'? c: '.');
3003 } else
3004 putchar(' ');
3005 }
3006 n -= r;
3007 for (; m < 16; ++m)
3008 putchar(' ');
3009 printf("|\n");
3010 if (nr < r)
3011 break;
3012 }
3013}
3014
Michael Ellerman4c4c8722006-11-23 00:46:42 +01003015typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
3016
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003017static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01003018generic_inst_dump(unsigned long adr, long count, int praddr,
3019 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020{
3021 int nr, dotted;
3022 unsigned long first_adr;
Jordan Niethe94afd062020-05-06 13:40:31 +10003023 struct ppc_inst inst, last_inst = ppc_inst(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024
3025 dotted = 0;
Jordan Niethe8b98afc2020-06-02 15:27:26 +10003026 for (first_adr = adr; count > 0; --count, adr += ppc_inst_len(inst)) {
3027 nr = mread_instr(adr, &inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 if (nr == 0) {
3029 if (praddr) {
3030 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003031 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 }
3033 break;
3034 }
Jordan Niethe217862d2020-05-06 13:40:30 +10003035 if (adr > first_adr && ppc_inst_equal(inst, last_inst)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 if (!dotted) {
3037 printf(" ...\n");
3038 dotted = 1;
3039 }
3040 continue;
3041 }
3042 dotted = 0;
3043 last_inst = inst;
3044 if (praddr)
Jordan Niethe50428fd2020-06-02 15:27:25 +10003045 printf(REG" %s", adr, ppc_inst_as_str(inst));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 printf("\t");
Jordan Niethe8b98afc2020-06-02 15:27:26 +10003047 if (!ppc_inst_prefixed(inst))
3048 dump_func(ppc_inst_val(inst), adr);
3049 else
Christophe Leroy693557e2021-04-20 14:02:06 +00003050 dump_func(ppc_inst_as_ulong(inst), adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 printf("\n");
3052 }
3053 return adr - first_adr;
3054}
3055
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003056static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01003057ppc_inst_dump(unsigned long adr, long count, int praddr)
3058{
3059 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
3060}
3061
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062void
3063print_address(unsigned long addr)
3064{
3065 xmon_print_symbol(addr, "\t# ", "");
3066}
3067
Breno Leitaoe3a83792018-10-22 11:54:16 -03003068static void
Vinay Sridharf312deb2009-05-14 23:13:07 +00003069dump_log_buf(void)
3070{
John Ognessf9f3f022021-03-03 11:15:25 +01003071 struct kmsg_dump_iter iter;
Nathan Lynch2cec178e2021-05-14 11:24:20 -05003072 static unsigned char buf[1024];
Michael Ellermanca5dd392012-08-23 22:09:12 +00003073 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00003074
Michael Ellermane3bc8042012-08-23 22:09:13 +00003075 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00003076 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00003077 return;
3078 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00003079
Michael Ellermane3bc8042012-08-23 22:09:13 +00003080 catch_memory_errors = 1;
3081 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00003082
John Ognessa4f98762021-03-03 11:15:27 +01003083 kmsg_dump_rewind(&iter);
Sam bobroff0c23a882015-10-08 11:50:24 +11003084 xmon_start_pagination();
John Ognessa4f98762021-03-03 11:15:27 +01003085 while (kmsg_dump_get_line(&iter, false, buf, sizeof(buf), &len)) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00003086 buf[len] = '\0';
3087 printf("%s", buf);
3088 }
Sam bobroff0c23a882015-10-08 11:50:24 +11003089 xmon_end_pagination();
Vinay Sridharf312deb2009-05-14 23:13:07 +00003090
Michael Ellermane3bc8042012-08-23 22:09:13 +00003091 sync();
3092 /* wait a little while to see if we get a machine check */
3093 __delay(200);
3094 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00003095}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
Andrew Donnellanfde93a02016-02-09 18:17:49 +11003097#ifdef CONFIG_PPC_POWERNV
3098static void dump_opal_msglog(void)
3099{
3100 unsigned char buf[128];
3101 ssize_t res;
Arnd Bergmanna2305e32021-04-29 10:06:38 +02003102 volatile loff_t pos = 0;
Andrew Donnellanfde93a02016-02-09 18:17:49 +11003103
3104 if (!firmware_has_feature(FW_FEATURE_OPAL)) {
3105 printf("Machine is not running OPAL firmware.\n");
3106 return;
3107 }
3108
3109 if (setjmp(bus_error_jmp) != 0) {
3110 printf("Error dumping OPAL msglog!\n");
3111 return;
3112 }
3113
3114 catch_memory_errors = 1;
3115 sync();
3116
3117 xmon_start_pagination();
3118 while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
3119 if (res < 0) {
3120 printf("Error dumping OPAL msglog! Error: %zd\n", res);
3121 break;
3122 }
3123 buf[res] = '\0';
3124 printf("%s", buf);
3125 pos += res;
3126 }
3127 xmon_end_pagination();
3128
3129 sync();
3130 /* wait a little while to see if we get a machine check */
3131 __delay(200);
3132 catch_memory_errors = 0;
3133}
3134#endif
3135
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136/*
3137 * Memory operations - move, set, print differences
3138 */
3139static unsigned long mdest; /* destination address */
3140static unsigned long msrc; /* source address */
3141static unsigned long mval; /* byte value to set memory to */
3142static unsigned long mcount; /* # bytes to affect */
3143static unsigned long mdiffs; /* max # differences to print */
3144
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003145static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146memops(int cmd)
3147{
3148 scanhex((void *)&mdest);
3149 if( termch != '\n' )
3150 termch = 0;
3151 scanhex((void *)(cmd == 's'? &mval: &msrc));
3152 if( termch != '\n' )
3153 termch = 0;
3154 scanhex((void *)&mcount);
3155 switch( cmd ){
3156 case 'm':
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05003157 if (xmon_is_ro) {
3158 printf(xmon_ro_msg);
3159 break;
3160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 memmove((void *)mdest, (void *)msrc, mcount);
3162 break;
3163 case 's':
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05003164 if (xmon_is_ro) {
3165 printf(xmon_ro_msg);
3166 break;
3167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 memset((void *)mdest, mval, mcount);
3169 break;
3170 case 'd':
3171 if( termch != '\n' )
3172 termch = 0;
3173 scanhex((void *)&mdiffs);
3174 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
3175 break;
3176 }
3177}
3178
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003179static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
3181{
3182 unsigned n, prt;
3183
3184 prt = 0;
3185 for( n = nb; n > 0; --n )
3186 if( *p1++ != *p2++ )
3187 if( ++prt <= maxpr )
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003188 printf("%px %.2x # %px %.2x\n", p1 - 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 p1[-1], p2 - 1, p2[-1]);
3190 if( prt > maxpr )
3191 printf("Total of %d differences\n", prt);
3192}
3193
3194static unsigned mend;
3195static unsigned mask;
3196
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003197static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198memlocate(void)
3199{
3200 unsigned a, n;
3201 unsigned char val[4];
3202
3203 last_cmd = "ml";
3204 scanhex((void *)&mdest);
3205 if (termch != '\n') {
3206 termch = 0;
3207 scanhex((void *)&mend);
3208 if (termch != '\n') {
3209 termch = 0;
3210 scanhex((void *)&mval);
3211 mask = ~0;
3212 if (termch != '\n') termch = 0;
3213 scanhex((void *)&mask);
3214 }
3215 }
3216 n = 0;
3217 for (a = mdest; a < mend; a += 4) {
3218 if (mread(a, val, 4) == 4
3219 && ((GETWORD(val) ^ mval) & mask) == 0) {
3220 printf("%.16x: %.16x\n", a, GETWORD(val));
3221 if (++n >= 10)
3222 break;
3223 }
3224 }
3225}
3226
3227static unsigned long mskip = 0x1000;
3228static unsigned long mlim = 0xffffffff;
3229
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003230static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231memzcan(void)
3232{
3233 unsigned char v;
3234 unsigned a;
3235 int ok, ook;
3236
3237 scanhex(&mdest);
3238 if (termch != '\n') termch = 0;
3239 scanhex(&mskip);
3240 if (termch != '\n') termch = 0;
3241 scanhex(&mlim);
3242 ook = 0;
3243 for (a = mdest; a < mlim; a += mskip) {
3244 ok = mread(a, &v, 1);
3245 if (ok && !ook) {
3246 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 } else if (!ok && ook)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003248 printf("%.8lx\n", a - mskip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249 ook = ok;
3250 if (a + mskip < a)
3251 break;
3252 }
3253 if (ook)
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003254 printf("%.8lx\n", a - mskip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255}
3256
Arnd Bergmanna2305e32021-04-29 10:06:38 +02003257static void show_task(struct task_struct *volatile tsk)
Douglas Miller6dfb5402015-11-23 09:01:15 -06003258{
Peter Zijlstra2f064a52021-06-11 10:28:17 +02003259 unsigned int p_state = READ_ONCE(tsk->__state);
Douglas Miller6dfb5402015-11-23 09:01:15 -06003260 char state;
3261
3262 /*
3263 * Cloned from kdb_task_state_char(), which is not entirely
3264 * appropriate for calling from xmon. This could be moved
3265 * to a common, generic, routine used by both.
3266 */
Denis Kirjanovb1f896c2021-10-26 16:31:08 +03003267 state = (p_state == TASK_RUNNING) ? 'R' :
Peter Zijlstra2f064a52021-06-11 10:28:17 +02003268 (p_state & TASK_UNINTERRUPTIBLE) ? 'D' :
3269 (p_state & TASK_STOPPED) ? 'T' :
3270 (p_state & TASK_TRACED) ? 'C' :
Douglas Miller6dfb5402015-11-23 09:01:15 -06003271 (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
3272 (tsk->exit_state & EXIT_DEAD) ? 'E' :
Peter Zijlstra2f064a52021-06-11 10:28:17 +02003273 (p_state & TASK_INTERRUPTIBLE) ? 'S' : '?';
Douglas Miller6dfb5402015-11-23 09:01:15 -06003274
Michael Ellerman0e7e92e2020-05-20 21:17:40 +10003275 printf("%16px %16lx %16px %6d %6d %c %2d %s\n", tsk,
3276 tsk->thread.ksp, tsk->thread.regs,
Breno Leitaoe3a83792018-10-22 11:54:16 -03003277 tsk->pid, rcu_dereference(tsk->parent)->pid,
Christophe Leroy05486082019-01-31 10:08:50 +00003278 state, task_cpu(tsk),
Douglas Miller6dfb5402015-11-23 09:01:15 -06003279 tsk->comm);
3280}
3281
Balbir Singh80eff6c2017-10-30 22:01:12 +11003282#ifdef CONFIG_PPC_BOOK3S_64
Breno Leitaoe3a83792018-10-22 11:54:16 -03003283static void format_pte(void *ptep, unsigned long pte)
Balbir Singh80eff6c2017-10-30 22:01:12 +11003284{
Christophe Leroy26973fa2018-10-09 13:51:56 +00003285 pte_t entry = __pte(pte);
3286
Balbir Singh80eff6c2017-10-30 22:01:12 +11003287 printf("ptep @ 0x%016lx = 0x%016lx\n", (unsigned long)ptep, pte);
3288 printf("Maps physical address = 0x%016lx\n", pte & PTE_RPN_MASK);
3289
3290 printf("Flags = %s%s%s%s%s\n",
Christophe Leroy26973fa2018-10-09 13:51:56 +00003291 pte_young(entry) ? "Accessed " : "",
3292 pte_dirty(entry) ? "Dirty " : "",
3293 pte_read(entry) ? "Read " : "",
3294 pte_write(entry) ? "Write " : "",
3295 pte_exec(entry) ? "Exec " : "");
Balbir Singh80eff6c2017-10-30 22:01:12 +11003296}
3297
3298static void show_pte(unsigned long addr)
3299{
3300 unsigned long tskv = 0;
Arnd Bergmanna2305e32021-04-29 10:06:38 +02003301 struct task_struct *volatile tsk = NULL;
Balbir Singh80eff6c2017-10-30 22:01:12 +11003302 struct mm_struct *mm;
Mike Rapoport2fb47062020-06-04 16:46:44 -07003303 pgd_t *pgdp;
3304 p4d_t *p4dp;
Balbir Singh80eff6c2017-10-30 22:01:12 +11003305 pud_t *pudp;
3306 pmd_t *pmdp;
3307 pte_t *ptep;
3308
3309 if (!scanhex(&tskv))
3310 mm = &init_mm;
3311 else
3312 tsk = (struct task_struct *)tskv;
3313
3314 if (tsk == NULL)
3315 mm = &init_mm;
3316 else
3317 mm = tsk->active_mm;
3318
3319 if (setjmp(bus_error_jmp) != 0) {
3320 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11003321 printf("*** Error dumping pte for task %px\n", tsk);
Balbir Singh80eff6c2017-10-30 22:01:12 +11003322 return;
3323 }
3324
3325 catch_memory_errors = 1;
3326 sync();
3327
Mike Rapoport2fb47062020-06-04 16:46:44 -07003328 if (mm == &init_mm)
Balbir Singh80eff6c2017-10-30 22:01:12 +11003329 pgdp = pgd_offset_k(addr);
Mike Rapoport2fb47062020-06-04 16:46:44 -07003330 else
Balbir Singh80eff6c2017-10-30 22:01:12 +11003331 pgdp = pgd_offset(mm, addr);
Balbir Singh80eff6c2017-10-30 22:01:12 +11003332
Mike Rapoport2fb47062020-06-04 16:46:44 -07003333 p4dp = p4d_offset(pgdp, addr);
3334
3335 if (p4d_none(*p4dp)) {
3336 printf("No valid P4D\n");
Balbir Singh80eff6c2017-10-30 22:01:12 +11003337 return;
3338 }
3339
Mike Rapoport2fb47062020-06-04 16:46:44 -07003340 if (p4d_is_leaf(*p4dp)) {
3341 format_pte(p4dp, p4d_val(*p4dp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003342 return;
3343 }
Balbir Singh80eff6c2017-10-30 22:01:12 +11003344
Mike Rapoport2fb47062020-06-04 16:46:44 -07003345 printf("p4dp @ 0x%px = 0x%016lx\n", p4dp, p4d_val(*p4dp));
3346
3347 pudp = pud_offset(p4dp, addr);
Balbir Singh80eff6c2017-10-30 22:01:12 +11003348
3349 if (pud_none(*pudp)) {
3350 printf("No valid PUD\n");
3351 return;
3352 }
3353
Aneesh Kumar K.Vd6eaced2019-05-14 11:33:00 +05303354 if (pud_is_leaf(*pudp)) {
Balbir Singh80eff6c2017-10-30 22:01:12 +11003355 format_pte(pudp, pud_val(*pudp));
3356 return;
3357 }
3358
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003359 printf("pudp @ 0x%px = 0x%016lx\n", pudp, pud_val(*pudp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003360
3361 pmdp = pmd_offset(pudp, addr);
3362
3363 if (pmd_none(*pmdp)) {
3364 printf("No valid PMD\n");
3365 return;
3366 }
3367
Aneesh Kumar K.Vd6eaced2019-05-14 11:33:00 +05303368 if (pmd_is_leaf(*pmdp)) {
Balbir Singh80eff6c2017-10-30 22:01:12 +11003369 format_pte(pmdp, pmd_val(*pmdp));
3370 return;
3371 }
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003372 printf("pmdp @ 0x%px = 0x%016lx\n", pmdp, pmd_val(*pmdp));
Balbir Singh80eff6c2017-10-30 22:01:12 +11003373
3374 ptep = pte_offset_map(pmdp, addr);
3375 if (pte_none(*ptep)) {
3376 printf("no valid PTE\n");
3377 return;
3378 }
3379
3380 format_pte(ptep, pte_val(*ptep));
3381
3382 sync();
3383 __delay(200);
3384 catch_memory_errors = 0;
3385}
3386#else
3387static void show_pte(unsigned long addr)
3388{
3389 printf("show_pte not yet implemented\n");
3390}
3391#endif /* CONFIG_PPC_BOOK3S_64 */
3392
Douglas Miller6dfb5402015-11-23 09:01:15 -06003393static void show_tasks(void)
3394{
3395 unsigned long tskv;
Arnd Bergmanna2305e32021-04-29 10:06:38 +02003396 struct task_struct *volatile tsk = NULL;
Douglas Miller6dfb5402015-11-23 09:01:15 -06003397
Michael Ellerman0e7e92e2020-05-20 21:17:40 +10003398 printf(" task_struct ->thread.ksp ->thread.regs PID PPID S P CMD\n");
Douglas Miller6dfb5402015-11-23 09:01:15 -06003399
3400 if (scanhex(&tskv))
3401 tsk = (struct task_struct *)tskv;
3402
3403 if (setjmp(bus_error_jmp) != 0) {
3404 catch_memory_errors = 0;
Michael Ellermand8104182017-12-06 23:23:28 +11003405 printf("*** Error dumping task %px\n", tsk);
Douglas Miller6dfb5402015-11-23 09:01:15 -06003406 return;
3407 }
3408
3409 catch_memory_errors = 1;
3410 sync();
3411
3412 if (tsk)
3413 show_task(tsk);
3414 else
3415 for_each_process(tsk)
3416 show_task(tsk);
3417
3418 sync();
3419 __delay(200);
3420 catch_memory_errors = 0;
3421}
3422
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003423static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003424{
3425 unsigned long args[8];
3426 unsigned long ret;
3427 int i;
3428 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
3429 unsigned long, unsigned long, unsigned long,
3430 unsigned long, unsigned long, unsigned long);
3431 callfunc_t func;
3432
3433 if (!scanhex(&adrs))
3434 return;
3435 if (termch != '\n')
3436 termch = 0;
3437 for (i = 0; i < 8; ++i)
3438 args[i] = 0;
3439 for (i = 0; i < 8; ++i) {
3440 if (!scanhex(&args[i]) || termch == '\n')
3441 break;
3442 termch = 0;
3443 }
3444 func = (callfunc_t) adrs;
3445 ret = 0;
3446 if (setjmp(bus_error_jmp) == 0) {
3447 catch_memory_errors = 1;
3448 sync();
3449 ret = func(args[0], args[1], args[2], args[3],
3450 args[4], args[5], args[6], args[7]);
3451 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10003452 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003453 } else {
3454 printf("*** %x exception occurred\n", fault_except);
3455 }
3456 catch_memory_errors = 0;
3457}
3458
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459/* Input scanning routines */
3460int
3461skipbl(void)
3462{
3463 int c;
3464
3465 if( termch != 0 ){
3466 c = termch;
3467 termch = 0;
3468 } else
3469 c = inchar();
3470 while( c == ' ' || c == '\t' )
3471 c = inchar();
3472 return c;
3473}
3474
3475#define N_PTREGS 44
Yisheng Xie0abbf2b2018-05-31 19:11:25 +08003476static const char *regnames[N_PTREGS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
3478 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
3479 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
3480 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003481 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
3482#ifdef CONFIG_PPC64
3483 "softe",
3484#else
3485 "mq",
3486#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 "trap", "dar", "dsisr", "res"
3488};
3489
3490int
3491scanhex(unsigned long *vp)
3492{
3493 int c, d;
3494 unsigned long v;
3495
3496 c = skipbl();
3497 if (c == '%') {
3498 /* parse register name */
3499 char regname[8];
3500 int i;
3501
3502 for (i = 0; i < sizeof(regname) - 1; ++i) {
3503 c = inchar();
3504 if (!isalnum(c)) {
3505 termch = c;
3506 break;
3507 }
3508 regname[i] = c;
3509 }
3510 regname[i] = 0;
Yisheng Xie0abbf2b2018-05-31 19:11:25 +08003511 i = match_string(regnames, N_PTREGS, regname);
3512 if (i < 0) {
3513 printf("invalid register name '%%%s'\n", regname);
3514 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 }
Yisheng Xie0abbf2b2018-05-31 19:11:25 +08003516 if (xmon_regs == NULL) {
3517 printf("regs not available\n");
3518 return 0;
3519 }
3520 *vp = ((unsigned long *)xmon_regs)[i];
3521 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 }
3523
3524 /* skip leading "0x" if any */
3525
3526 if (c == '0') {
3527 c = inchar();
3528 if (c == 'x') {
3529 c = inchar();
3530 } else {
3531 d = hexdigit(c);
3532 if (d == EOF) {
3533 termch = c;
3534 *vp = 0;
3535 return 1;
3536 }
3537 }
3538 } else if (c == '$') {
3539 int i;
3540 for (i=0; i<63; i++) {
3541 c = inchar();
Vincent Bernat05b981f2014-07-15 13:43:47 +02003542 if (isspace(c) || c == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 termch = c;
3544 break;
3545 }
3546 tmpstr[i] = c;
3547 }
3548 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07003549 *vp = 0;
3550 if (setjmp(bus_error_jmp) == 0) {
3551 catch_memory_errors = 1;
3552 sync();
3553 *vp = kallsyms_lookup_name(tmpstr);
3554 sync();
3555 }
3556 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 if (!(*vp)) {
3558 printf("unknown symbol '%s'\n", tmpstr);
3559 return 0;
3560 }
3561 return 1;
3562 }
3563
3564 d = hexdigit(c);
3565 if (d == EOF) {
3566 termch = c;
3567 return 0;
3568 }
3569 v = 0;
3570 do {
3571 v = (v << 4) + d;
3572 c = inchar();
3573 d = hexdigit(c);
3574 } while (d != EOF);
3575 termch = c;
3576 *vp = v;
3577 return 1;
3578}
3579
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003580static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581scannl(void)
3582{
3583 int c;
3584
3585 c = termch;
3586 termch = 0;
3587 while( c != '\n' )
3588 c = inchar();
3589}
3590
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003591static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592{
3593 if( '0' <= c && c <= '9' )
3594 return c - '0';
3595 if( 'A' <= c && c <= 'F' )
3596 return c - ('A' - 10);
3597 if( 'a' <= c && c <= 'f' )
3598 return c - ('a' - 10);
3599 return EOF;
3600}
3601
3602void
3603getstring(char *s, int size)
3604{
3605 int c;
3606
3607 c = skipbl();
Oliver O'Halloran066bc352020-02-17 15:13:43 +11003608 if (c == '\n') {
3609 *s = 0;
3610 return;
3611 }
3612
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 do {
3614 if( size > 1 ){
3615 *s++ = c;
3616 --size;
3617 }
3618 c = inchar();
3619 } while( c != ' ' && c != '\t' && c != '\n' );
3620 termch = c;
3621 *s = 0;
3622}
3623
3624static char line[256];
3625static char *lineptr;
3626
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003627static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628flush_input(void)
3629{
3630 lineptr = NULL;
3631}
3632
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003633static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634inchar(void)
3635{
3636 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003637 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 lineptr = NULL;
3639 return EOF;
3640 }
3641 lineptr = line;
3642 }
3643 return *lineptr++;
3644}
3645
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003646static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647take_input(char *str)
3648{
3649 lineptr = str;
3650}
3651
3652
3653static void
3654symbol_lookup(void)
3655{
3656 int type = inchar();
Boqun Feng302c7b02016-11-22 17:20:09 +08003657 unsigned long addr, cpu;
3658 void __percpu *ptr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 static char tmp[64];
3660
3661 switch (type) {
3662 case 'a':
3663 if (scanhex(&addr))
3664 xmon_print_symbol(addr, ": ", "\n");
3665 termch = 0;
3666 break;
3667 case 's':
3668 getstring(tmp, 64);
3669 if (setjmp(bus_error_jmp) == 0) {
3670 catch_memory_errors = 1;
3671 sync();
3672 addr = kallsyms_lookup_name(tmp);
3673 if (addr)
3674 printf("%s: %lx\n", tmp, addr);
3675 else
3676 printf("Symbol '%s' not found.\n", tmp);
3677 sync();
3678 }
3679 catch_memory_errors = 0;
3680 termch = 0;
3681 break;
Boqun Feng302c7b02016-11-22 17:20:09 +08003682 case 'p':
3683 getstring(tmp, 64);
3684 if (setjmp(bus_error_jmp) == 0) {
3685 catch_memory_errors = 1;
3686 sync();
3687 ptr = (void __percpu *)kallsyms_lookup_name(tmp);
3688 sync();
3689 }
3690
3691 if (ptr &&
3692 ptr >= (void __percpu *)__per_cpu_start &&
3693 ptr < (void __percpu *)__per_cpu_end)
3694 {
3695 if (scanhex(&cpu) && cpu < num_possible_cpus()) {
3696 addr = (unsigned long)per_cpu_ptr(ptr, cpu);
3697 } else {
3698 cpu = raw_smp_processor_id();
3699 addr = (unsigned long)this_cpu_ptr(ptr);
3700 }
3701
3702 printf("%s for cpu 0x%lx: %lx\n", tmp, cpu, addr);
3703 } else {
3704 printf("Percpu symbol '%s' not found.\n", tmp);
3705 }
3706
3707 catch_memory_errors = 0;
3708 termch = 0;
3709 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 }
3711}
3712
3713
3714/* Print an address in numeric and symbolic form (if possible) */
3715static void xmon_print_symbol(unsigned long address, const char *mid,
3716 const char *after)
3717{
3718 char *modname;
Arnd Bergmanna2305e32021-04-29 10:06:38 +02003719 const char *volatile name = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 unsigned long offset, size;
3721
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003722 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 if (setjmp(bus_error_jmp) == 0) {
3724 catch_memory_errors = 1;
3725 sync();
3726 name = kallsyms_lookup(address, &size, &offset, &modname,
3727 tmpstr);
3728 sync();
3729 /* wait a little while to see if we get a machine check */
3730 __delay(200);
3731 }
3732
3733 catch_memory_errors = 0;
3734
3735 if (name) {
3736 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
3737 if (modname)
3738 printf(" [%s]", modname);
3739 }
3740 printf("%s", after);
3741}
3742
Michael Ellerman4e003742017-10-19 15:08:43 +11003743#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10003744void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745{
3746 int i;
Anshuman Khandual8218a302015-07-29 12:40:04 +05303747 unsigned long esid,vsid;
will schmidtb3b95952007-12-07 08:22:23 +11003748 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749
Michael Ellerman736256e2014-05-26 21:02:14 +10003750 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751
Michael Neuling584f8b72007-12-06 17:24:48 +11003752 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11003753 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
3754 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
Michael Ellerman85673642017-04-24 10:35:14 +10003755
3756 if (!esid && !vsid)
3757 continue;
3758
3759 printf("%02d %016lx %016lx", i, esid, vsid);
3760
3761 if (!(esid & SLB_ESID_V)) {
3762 printf("\n");
3763 continue;
3764 }
3765
3766 llp = vsid & SLB_VSID_LLP;
3767 if (vsid & SLB_VSID_B_1T) {
3768 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
3769 GET_ESID_1T(esid),
3770 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
3771 llp);
3772 } else {
3773 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
3774 GET_ESID(esid),
3775 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
3776 llp);
will schmidtb3b95952007-12-07 08:22:23 +11003777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 }
3779}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003780#endif
3781
Christophe Leroy68289ae2018-11-17 10:25:02 +00003782#ifdef CONFIG_PPC_BOOK3S_32
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003783void dump_segments(void)
3784{
3785 int i;
3786
3787 printf("sr0-15 =");
3788 for (i = 0; i < 16; ++i)
Christophe Leroy179ae572021-02-06 11:47:27 +00003789 printf(" %x", mfsr(i << 28));
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10003790 printf("\n");
3791}
3792#endif
3793
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003794#ifdef CONFIG_44x
3795static void dump_tlb_44x(void)
3796{
3797 int i;
3798
3799 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
3800 unsigned long w0,w1,w2;
3801 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
3802 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
3803 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003804 printf("[%02x] %08lx %08lx %08lx ", i, w0, w1, w2);
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003805 if (w0 & PPC44x_TLB_VALID) {
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02003806 printf("V %08lx -> %01lx%08lx %c%c%c%c%c",
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11003807 w0 & PPC44x_TLB_EPN_MASK,
3808 w1 & PPC44x_TLB_ERPN_MASK,
3809 w1 & PPC44x_TLB_RPN_MASK,
3810 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
3811 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
3812 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
3813 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
3814 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
3815 }
3816 printf("\n");
3817 }
3818}
3819#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003820
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10003821#ifdef CONFIG_PPC_BOOK3E
3822static void dump_tlb_book3e(void)
3823{
3824 u32 mmucfg, pidmask, lpidmask;
3825 u64 ramask;
3826 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3827 int mmu_version;
3828 static const char *pgsz_names[] = {
3829 " 1K",
3830 " 2K",
3831 " 4K",
3832 " 8K",
3833 " 16K",
3834 " 32K",
3835 " 64K",
3836 "128K",
3837 "256K",
3838 "512K",
3839 " 1M",
3840 " 2M",
3841 " 4M",
3842 " 8M",
3843 " 16M",
3844 " 32M",
3845 " 64M",
3846 "128M",
3847 "256M",
3848 "512M",
3849 " 1G",
3850 " 2G",
3851 " 4G",
3852 " 8G",
3853 " 16G",
3854 " 32G",
3855 " 64G",
3856 "128G",
3857 "256G",
3858 "512G",
3859 " 1T",
3860 " 2T",
3861 };
3862
3863 /* Gather some infos about the MMU */
3864 mmucfg = mfspr(SPRN_MMUCFG);
3865 mmu_version = (mmucfg & 3) + 1;
3866 ntlbs = ((mmucfg >> 2) & 3) + 1;
3867 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3868 lpidsz = (mmucfg >> 24) & 0xf;
3869 rasz = (mmucfg >> 16) & 0x7f;
3870 if ((mmu_version > 1) && (mmucfg & 0x10000))
3871 lrat = 1;
3872 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3873 mmu_version, ntlbs, pidsz, lpidsz, rasz);
3874 pidmask = (1ul << pidsz) - 1;
3875 lpidmask = (1ul << lpidsz) - 1;
3876 ramask = (1ull << rasz) - 1;
3877
3878 for (tlb = 0; tlb < ntlbs; tlb++) {
3879 u32 tlbcfg;
3880 int nent, assoc, new_cc = 1;
3881 printf("TLB %d:\n------\n", tlb);
3882 switch(tlb) {
3883 case 0:
3884 tlbcfg = mfspr(SPRN_TLB0CFG);
3885 break;
3886 case 1:
3887 tlbcfg = mfspr(SPRN_TLB1CFG);
3888 break;
3889 case 2:
3890 tlbcfg = mfspr(SPRN_TLB2CFG);
3891 break;
3892 case 3:
3893 tlbcfg = mfspr(SPRN_TLB3CFG);
3894 break;
3895 default:
3896 printf("Unsupported TLB number !\n");
3897 continue;
3898 }
3899 nent = tlbcfg & 0xfff;
3900 assoc = (tlbcfg >> 24) & 0xff;
3901 for (i = 0; i < nent; i++) {
3902 u32 mas0 = MAS0_TLBSEL(tlb);
3903 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3904 u64 mas2 = 0;
3905 u64 mas7_mas3;
3906 int esel = i, cc = i;
3907
3908 if (assoc != 0) {
3909 cc = i / assoc;
3910 esel = i % assoc;
3911 mas2 = cc * 0x1000;
3912 }
3913
3914 mas0 |= MAS0_ESEL(esel);
3915 mtspr(SPRN_MAS0, mas0);
3916 mtspr(SPRN_MAS1, mas1);
3917 mtspr(SPRN_MAS2, mas2);
3918 asm volatile("tlbre 0,0,0" : : : "memory");
3919 mas1 = mfspr(SPRN_MAS1);
3920 mas2 = mfspr(SPRN_MAS2);
3921 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3922 if (assoc && (i % assoc) == 0)
3923 new_cc = 1;
3924 if (!(mas1 & MAS1_VALID))
3925 continue;
3926 if (assoc == 0)
3927 printf("%04x- ", i);
3928 else if (new_cc)
3929 printf("%04x-%c", cc, 'A' + esel);
3930 else
3931 printf(" |%c", 'A' + esel);
3932 new_cc = 0;
3933 printf(" %016llx %04x %s %c%c AS%c",
3934 mas2 & ~0x3ffull,
3935 (mas1 >> 16) & 0x3fff,
3936 pgsz_names[(mas1 >> 7) & 0x1f],
3937 mas1 & MAS1_IND ? 'I' : ' ',
3938 mas1 & MAS1_IPROT ? 'P' : ' ',
3939 mas1 & MAS1_TS ? '1' : '0');
3940 printf(" %c%c%c%c%c%c%c",
3941 mas2 & MAS2_X0 ? 'a' : ' ',
3942 mas2 & MAS2_X1 ? 'v' : ' ',
3943 mas2 & MAS2_W ? 'w' : ' ',
3944 mas2 & MAS2_I ? 'i' : ' ',
3945 mas2 & MAS2_M ? 'm' : ' ',
3946 mas2 & MAS2_G ? 'g' : ' ',
3947 mas2 & MAS2_E ? 'e' : ' ');
3948 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3949 if (mas1 & MAS1_IND)
3950 printf(" %s\n",
3951 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3952 else
3953 printf(" U%c%c%c S%c%c%c\n",
3954 mas7_mas3 & MAS3_UX ? 'x' : ' ',
3955 mas7_mas3 & MAS3_UW ? 'w' : ' ',
3956 mas7_mas3 & MAS3_UR ? 'r' : ' ',
3957 mas7_mas3 & MAS3_SX ? 'x' : ' ',
3958 mas7_mas3 & MAS3_SW ? 'w' : ' ',
3959 mas7_mas3 & MAS3_SR ? 'r' : ' ');
3960 }
3961 }
3962}
3963#endif /* CONFIG_PPC_BOOK3E */
3964
Michael Ellerman9f1067c22008-05-08 14:27:16 +10003965static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966{
Olaf Heringb13cfd172005-08-04 19:26:42 +02003967 if (enable) {
3968 __debugger = xmon;
3969 __debugger_ipi = xmon_ipi;
3970 __debugger_bpt = xmon_bpt;
3971 __debugger_sstep = xmon_sstep;
3972 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00003973 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003974 __debugger_fault_handler = xmon_fault_handler;
Breno Leitao8d4a8622018-11-08 15:12:42 -02003975
3976#ifdef CONFIG_PPC_PSERIES
3977 /*
3978 * Get the token here to avoid trying to get a lock
3979 * during the crash, causing a deadlock.
3980 */
3981 set_indicator_token = rtas_token("set-indicator");
3982#endif
Olaf Heringb13cfd172005-08-04 19:26:42 +02003983 } else {
3984 __debugger = NULL;
3985 __debugger_ipi = NULL;
3986 __debugger_bpt = NULL;
3987 __debugger_sstep = NULL;
3988 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00003989 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02003990 __debugger_fault_handler = NULL;
3991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003993
3994#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07003995static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11003996{
Christopher M. Riedl69393cb2019-09-07 01:11:24 -05003997 if (xmon_is_locked_down()) {
3998 clear_all_bpt();
3999 xmon_init(0);
4000 return;
4001 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004002 /* ensure xmon is enabled */
4003 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01004004 debugger(get_irq_regs());
Pan Xinhui3b5bf422017-03-22 16:27:49 -03004005 if (!xmon_on)
4006 xmon_init(0);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004007}
4008
Emil Velikovfff134c2020-05-13 22:43:46 +01004009static const struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004010 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07004011 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004012 .action_msg = "Entering xmon",
4013};
4014
4015static int __init setup_xmon_sysrq(void)
4016{
4017 register_sysrq_key('x', &sysrq_xmon_op);
4018 return 0;
4019}
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03004020device_initcall(setup_xmon_sysrq);
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004021#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10004022
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05304023static void clear_all_bpt(void)
4024{
4025 int i;
4026
4027 /* clear/unpatch all breakpoints */
4028 remove_bpts();
4029 remove_cpu_bpts();
4030
4031 /* Disable all breakpoints */
4032 for (i = 0; i < NBPTS; ++i)
4033 bpts[i].enabled = 0;
4034
4035 /* Clear any data or iabr breakpoints */
Ravi Bangoria30df74d2020-05-14 16:47:41 +05304036 iabr = NULL;
4037 for (i = 0; i < nr_wp_slots(); i++)
4038 dabr[i].enabled = 0;
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05304039}
4040
Christopher M. Riedl69393cb2019-09-07 01:11:24 -05004041#ifdef CONFIG_DEBUG_FS
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03004042static int xmon_dbgfs_set(void *data, u64 val)
4043{
4044 xmon_on = !!val;
4045 xmon_init(xmon_on);
4046
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05304047 /* make sure all breakpoints removed when disabling */
Christopher M. Riedl69393cb2019-09-07 01:11:24 -05004048 if (!xmon_on) {
Vaibhav Jain1ff3b402018-03-04 23:01:32 +05304049 clear_all_bpt();
Christopher M. Riedl69393cb2019-09-07 01:11:24 -05004050 get_output_lock();
4051 printf("xmon: All breakpoints cleared\n");
4052 release_output_lock();
4053 }
4054
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03004055 return 0;
4056}
4057
4058static int xmon_dbgfs_get(void *data, u64 *val)
4059{
4060 *val = xmon_on;
4061 return 0;
4062}
4063
4064DEFINE_SIMPLE_ATTRIBUTE(xmon_dbgfs_ops, xmon_dbgfs_get,
4065 xmon_dbgfs_set, "%llu\n");
4066
4067static int __init setup_xmon_dbgfs(void)
4068{
Aneesh Kumar K.Vdbf77fed2021-08-12 18:58:31 +05304069 debugfs_create_file("xmon", 0600, arch_debugfs_dir, NULL,
4070 &xmon_dbgfs_ops);
Guilherme G. Piccolide78ae62017-03-22 16:27:51 -03004071 return 0;
4072}
4073device_initcall(setup_xmon_dbgfs);
4074#endif /* CONFIG_DEBUG_FS */
4075
Guilherme G. Piccolib5617832017-03-22 16:27:50 -03004076static int xmon_early __initdata;
Michael Ellerman476792832006-10-03 14:12:08 +10004077
4078static int __init early_parse_xmon(char *p)
4079{
Christopher M. Riedl69393cb2019-09-07 01:11:24 -05004080 if (xmon_is_locked_down()) {
4081 xmon_init(0);
4082 xmon_early = 0;
4083 xmon_on = 0;
4084 } else if (!p || strncmp(p, "early", 5) == 0) {
Michael Ellerman476792832006-10-03 14:12:08 +10004085 /* just "xmon" is equivalent to "xmon=early" */
4086 xmon_init(1);
4087 xmon_early = 1;
Pan Xinhui3b5bf422017-03-22 16:27:49 -03004088 xmon_on = 1;
4089 } else if (strncmp(p, "on", 2) == 0) {
Michael Ellerman476792832006-10-03 14:12:08 +10004090 xmon_init(1);
Pan Xinhui3b5bf422017-03-22 16:27:49 -03004091 xmon_on = 1;
Christopher M. Riedl0acb5f62019-04-15 22:26:38 -05004092 } else if (strncmp(p, "rw", 2) == 0) {
4093 xmon_init(1);
4094 xmon_on = 1;
4095 xmon_is_ro = false;
4096 } else if (strncmp(p, "ro", 2) == 0) {
4097 xmon_init(1);
4098 xmon_on = 1;
4099 xmon_is_ro = true;
Pan Xinhui3b5bf422017-03-22 16:27:49 -03004100 } else if (strncmp(p, "off", 3) == 0)
4101 xmon_on = 0;
Michael Ellerman476792832006-10-03 14:12:08 +10004102 else
4103 return 1;
4104
4105 return 0;
4106}
4107early_param("xmon", early_parse_xmon);
4108
4109void __init xmon_setup(void)
4110{
Pan Xinhui3b5bf422017-03-22 16:27:49 -03004111 if (xmon_on)
Michael Ellerman476792832006-10-03 14:12:08 +10004112 xmon_init(1);
Michael Ellerman476792832006-10-03 14:12:08 +10004113 if (xmon_early)
4114 debugger(NULL);
4115}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004116
Arnd Bergmanne0555952006-11-27 19:18:55 +01004117#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004118
4119struct spu_info {
4120 struct spu *spu;
4121 u64 saved_mfc_sr1_RW;
4122 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01004123 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004124 u8 stopped_ok;
4125};
4126
4127#define XMON_NUM_SPUS 16 /* Enough for current hardware */
4128
4129static struct spu_info spu_info[XMON_NUM_SPUS];
4130
4131void xmon_register_spus(struct list_head *list)
4132{
4133 struct spu *spu;
4134
4135 list_for_each_entry(spu, list, full_list) {
4136 if (spu->number >= XMON_NUM_SPUS) {
4137 WARN_ON(1);
4138 continue;
4139 }
4140
4141 spu_info[spu->number].spu = spu;
4142 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01004143 spu_info[spu->number].dump_addr = (unsigned long)
4144 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004145 }
4146}
4147
4148static void stop_spus(void)
4149{
4150 struct spu *spu;
Arnd Bergmanna2305e32021-04-29 10:06:38 +02004151 volatile int i;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004152 u64 tmp;
4153
4154 for (i = 0; i < XMON_NUM_SPUS; i++) {
4155 if (!spu_info[i].spu)
4156 continue;
4157
4158 if (setjmp(bus_error_jmp) == 0) {
4159 catch_memory_errors = 1;
4160 sync();
4161
4162 spu = spu_info[i].spu;
4163
4164 spu_info[i].saved_spu_runcntl_RW =
4165 in_be32(&spu->problem->spu_runcntl_RW);
4166
4167 tmp = spu_mfc_sr1_get(spu);
4168 spu_info[i].saved_mfc_sr1_RW = tmp;
4169
4170 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
4171 spu_mfc_sr1_set(spu, tmp);
4172
4173 sync();
4174 __delay(200);
4175
4176 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01004177
4178 printf("Stopped spu %.2d (was %s)\n", i,
4179 spu_info[i].saved_spu_runcntl_RW ?
4180 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004181 } else {
4182 catch_memory_errors = 0;
4183 printf("*** Error stopping spu %.2d\n", i);
4184 }
4185 catch_memory_errors = 0;
4186 }
4187}
4188
4189static void restart_spus(void)
4190{
4191 struct spu *spu;
Arnd Bergmanna2305e32021-04-29 10:06:38 +02004192 volatile int i;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004193
4194 for (i = 0; i < XMON_NUM_SPUS; i++) {
4195 if (!spu_info[i].spu)
4196 continue;
4197
4198 if (!spu_info[i].stopped_ok) {
4199 printf("*** Error, spu %d was not successfully stopped"
4200 ", not restarting\n", i);
4201 continue;
4202 }
4203
4204 if (setjmp(bus_error_jmp) == 0) {
4205 catch_memory_errors = 1;
4206 sync();
4207
4208 spu = spu_info[i].spu;
4209 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
4210 out_be32(&spu->problem->spu_runcntl_RW,
4211 spu_info[i].saved_spu_runcntl_RW);
4212
4213 sync();
4214 __delay(200);
4215
4216 printf("Restarted spu %.2d\n", i);
4217 } else {
4218 catch_memory_errors = 0;
4219 printf("*** Error restarting spu %.2d\n", i);
4220 }
4221 catch_memory_errors = 0;
4222 }
4223}
4224
Michael Ellermana8984972006-10-24 18:31:28 +02004225#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01004226#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02004227do { \
4228 if (setjmp(bus_error_jmp) == 0) { \
4229 catch_memory_errors = 1; \
4230 sync(); \
4231 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01004232 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02004233 sync(); \
4234 __delay(200); \
4235 } else { \
4236 catch_memory_errors = 0; \
4237 printf(" %-*s = *** Error reading field.\n", \
4238 DUMP_WIDTH, #field); \
4239 } \
4240 catch_memory_errors = 0; \
4241} while (0)
4242
Michael Ellerman437a0702006-11-23 00:46:39 +01004243#define DUMP_FIELD(obj, format, field) \
4244 DUMP_VALUE(format, field, obj->field)
4245
Michael Ellermana8984972006-10-24 18:31:28 +02004246static void dump_spu_fields(struct spu *spu)
4247{
4248 printf("Dumping spu fields at address %p:\n", spu);
4249
4250 DUMP_FIELD(spu, "0x%x", number);
4251 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02004252 DUMP_FIELD(spu, "0x%lx", local_store_phys);
4253 DUMP_FIELD(spu, "0x%p", local_store);
4254 DUMP_FIELD(spu, "0x%lx", ls_size);
4255 DUMP_FIELD(spu, "0x%x", node);
4256 DUMP_FIELD(spu, "0x%lx", flags);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02004257 DUMP_FIELD(spu, "%llu", class_0_pending);
4258 DUMP_FIELD(spu, "0x%llx", class_0_dar);
4259 DUMP_FIELD(spu, "0x%llx", class_1_dar);
4260 DUMP_FIELD(spu, "0x%llx", class_1_dsisr);
4261 DUMP_FIELD(spu, "0x%x", irqs[0]);
4262 DUMP_FIELD(spu, "0x%x", irqs[1]);
4263 DUMP_FIELD(spu, "0x%x", irqs[2]);
Michael Ellermana8984972006-10-24 18:31:28 +02004264 DUMP_FIELD(spu, "0x%x", slb_replace);
4265 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02004266 DUMP_FIELD(spu, "0x%p", mm);
4267 DUMP_FIELD(spu, "0x%p", ctx);
4268 DUMP_FIELD(spu, "0x%p", rq);
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02004269 DUMP_FIELD(spu, "0x%llx", timestamp);
Michael Ellermana8984972006-10-24 18:31:28 +02004270 DUMP_FIELD(spu, "0x%lx", problem_phys);
4271 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01004272 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
4273 in_be32(&spu->problem->spu_runcntl_RW));
4274 DUMP_VALUE("0x%x", problem->spu_status_R,
4275 in_be32(&spu->problem->spu_status_R));
4276 DUMP_VALUE("0x%x", problem->spu_npc_RW,
4277 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02004278 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01004279 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02004280}
4281
Pu Lehuif234ad42021-04-09 15:01:51 +08004282static int spu_inst_dump(unsigned long adr, long count, int praddr)
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004283{
4284 return generic_inst_dump(adr, count, praddr, print_insn_spu);
4285}
4286
4287static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01004288{
4289 unsigned long offset, addr, ls_addr;
4290
4291 if (setjmp(bus_error_jmp) == 0) {
4292 catch_memory_errors = 1;
4293 sync();
4294 ls_addr = (unsigned long)spu_info[num].spu->local_store;
4295 sync();
4296 __delay(200);
4297 } else {
4298 catch_memory_errors = 0;
Mathieu Malaterree70d8f52018-03-25 11:06:47 +02004299 printf("*** Error: accessing spu info for spu %ld\n", num);
Michael Ellerman24a24c82006-11-23 00:46:41 +01004300 return;
4301 }
4302 catch_memory_errors = 0;
4303
4304 if (scanhex(&offset))
4305 addr = ls_addr + offset;
4306 else
4307 addr = spu_info[num].dump_addr;
4308
4309 if (addr >= ls_addr + LS_SIZE) {
4310 printf("*** Error: address outside of local store\n");
4311 return;
4312 }
4313
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004314 switch (subcmd) {
4315 case 'i':
4316 addr += spu_inst_dump(addr, 16, 1);
4317 last_cmd = "sdi\n";
4318 break;
4319 default:
4320 prdump(addr, 64);
4321 addr += 64;
4322 last_cmd = "sd\n";
4323 break;
4324 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01004325
4326 spu_info[num].dump_addr = addr;
4327}
4328
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004329static int do_spu_cmd(void)
4330{
Michael Ellerman24a24c82006-11-23 00:46:41 +01004331 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004332 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004333
4334 cmd = inchar();
4335 switch (cmd) {
4336 case 's':
4337 stop_spus();
4338 break;
4339 case 'r':
4340 restart_spus();
4341 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01004342 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004343 subcmd = inchar();
4344 if (isxdigit(subcmd) || subcmd == '\n')
4345 termch = subcmd;
Gustavo A. R. Silva5e66a0c2020-07-27 17:42:01 -05004346 fallthrough;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004347 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01004348 scanhex(&num);
4349 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02004350 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01004351 return 0;
4352 }
4353
4354 switch (cmd) {
4355 case 'f':
4356 dump_spu_fields(spu_info[num].spu);
4357 break;
4358 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01004359 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01004360 break;
4361 }
4362
Michael Ellermana8984972006-10-24 18:31:28 +02004363 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004364 default:
4365 return -1;
4366 }
4367
4368 return 0;
4369}
Arnd Bergmanne0555952006-11-27 19:18:55 +01004370#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02004371static int do_spu_cmd(void)
4372{
4373 return -1;
4374}
4375#endif